Skip to content

feat(skills)!: remove Codex agent support - #254

Merged
BlackHole1 merged 2 commits into
mainfrom
remove-codex
Jun 2, 2026
Merged

feat(skills)!: remove Codex agent support#254
BlackHole1 merged 2 commits into
mainfrom
remove-codex

Conversation

@BlackHole1

Copy link
Copy Markdown
Member

Codex now reads skills from the universal ~/.agents location, so a dedicated Codex host, agent identifier, and per-skill openai.yaml manifests are no longer needed. Dropping them removes --agent codex and the codex host from list, locate, install, and repair output.

The universal ~/.agents host is now always provisioned, guaranteeing at least one install target even when no other supported agent home exists.

Add a one-time cleanup that deletes oo-managed skills left under the legacy ~/.codex home and bundled storage, identified strictly by their .oo-metadata.json. Codex does not deduplicate ~/.codex/skills against ~/.agents, so the stale copies would otherwise surface as duplicates; user-authored and unmanaged directories are preserved.

Codex now reads skills from the universal `~/.agents` location, so a
dedicated Codex host, agent identifier, and per-skill `openai.yaml`
manifests are no longer needed. Dropping them removes `--agent codex`
and the `codex` host from list, locate, install, and repair output.

The universal `~/.agents` host is now always provisioned, guaranteeing
at least one install target even when no other supported agent home
exists.

Add a one-time cleanup that deletes oo-managed skills left under the
legacy `~/.codex` home and bundled storage, identified strictly by
their `.oo-metadata.json`. Codex does not deduplicate `~/.codex/skills`
against `~/.agents`, so the stale copies would otherwise surface as
duplicates; user-authored and unmanaged directories are preserved.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1937e99-c2ac-4f5c-86b1-0a73288dd646

📥 Commits

Reviewing files that changed from the base of the PR and between 401dc54 and b5143e5.

📒 Files selected for processing (8)
  • contrib/skills/shared/oo-create-skill/SKILL.md
  • docs/path-first-skill-publish-plan.md
  • src/application/bootstrap/run-cli.test.ts
  • src/application/commands/info.cli.test.ts
  • src/application/commands/skills/embedded-assets.test.ts
  • src/application/commands/skills/install.cli.test.ts
  • src/application/commands/skills/legacy-codex-cleanup.test.ts
  • src/application/commands/skills/legacy-codex-cleanup.ts
✅ Files skipped from review due to trivial changes (1)
  • contrib/skills/shared/oo-create-skill/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • docs/path-first-skill-publish-plan.md
  • src/application/bootstrap/run-cli.test.ts
  • src/application/commands/skills/install.cli.test.ts
  • src/application/commands/info.cli.test.ts
  • src/application/commands/skills/legacy-codex-cleanup.ts
  • src/application/commands/skills/embedded-assets.test.ts

Summary by CodeRabbit

  • New Features

    • Automatic startup cleanup removes legacy managed skills from the old location and ensures the new Universal agent host is provisioned.
  • Behavior Changes

    • Bundled/published skills now install to ~/.agents/skills and surface “Universal” as the default agent/host.
    • Universal host is always available even if its directory is missing.
  • Documentation

    • Command docs and examples updated to use ~/.agents/skills and Universal; removed legacy Codex references.

Walkthrough

This PR migrates the managed skill agent infrastructure from Codex (legacy) to Universal as the default, always-provisioned agent. The core changes include: removing Codex from the supported agents registry and making Universal always available; renaming bundled skill path constants from codex-specific to generic "managed" naming; updating all path resolution to use ~/.agents instead of ~/.codex; removing static agent YAML configuration files from bundled skills and always rendering skill content through a unified pipeline; adding a new legacy cleanup routine to remove Codex-managed skills during CLI startup; and comprehensively updating test suites, documentation, and internationalization to reflect the new Universal-centric model.

Possibly related PRs

  • oomol-lab/oo-cli#111: Introduces the startup synchronization flow (synchronizeManagedSkillsForAvailableHosts) that the main PR wires legacy Codex cleanup into during CLI bootstrap.
  • oomol-lab/oo-cli#227: Adds initial Universal agent support and updates bundled skill agent coverage that the main PR completes by removing Codex and making Universal the default.
  • oomol-lab/oo-cli#230: Introduces the oo info command and agent-status reporting that the main PR updates to surface the new Universal agent in place of Codex.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch remove-codex

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/application/commands/skills/check.ts (1)

89-97: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Honor alwaysProvision before rejecting a missing home.

On a clean machine, --agent universal still fails here because ~/.agents is checked for existence before verifyWritableDirectory() gets a chance to create it. That breaks the new always-provisioned host contract and makes first-run preflight fail unnecessarily.

💡 Minimal fix
 import {
     createManagedSkillAgentNotInstalledError,
     createMissingRequiredSkillAgentError,
     parseManagedSkillAgentOption,
+    readManagedSkillAgent,
     resolveManagedSkillAgentHomeDirectory,
 } from "./managed-skill-agents.ts";
@@
 export async function resolveRequestedManagedSkillHost(
     env: Record<string, string | undefined>,
     translator: Pick<CliExecutionContext["translator"], "t">,
     agentName: BundledSkillAgentName,
 ): Promise<Array<{ agentName: BundledSkillAgentName; homeDirectory: string }>> {
+    const agent = readManagedSkillAgent(agentName);
     const homeDirectory = resolveManagedSkillAgentHomeDirectory(env, agentName);

-    if (!(await directoryExists(homeDirectory))) {
+    if (!agent.alwaysProvision && !(await directoryExists(homeDirectory))) {
         throw createManagedSkillAgentNotInstalledError(
             agentName,
             homeDirectory,
             translator,
         );

As per coding guidelines, "For file operations, attempt the operation and catch the error (EAFP) rather than pre-checking existence then reading (LBYL)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/check.ts` around lines 89 - 97, The code
currently checks directoryExists(homeDirectory) and throws
createManagedSkillAgentNotInstalledError before honoring the alwaysProvision
behavior; instead, call verifyWritableDirectory(homeDirectory) (or the existing
helper that creates directories) for the resolved path returned by
resolveManagedSkillAgentHomeDirectory(agentName) and let it create the directory
or fail, catching errors and only throwing
createManagedSkillAgentNotInstalledError if verifyWritableDirectory fails for
reasons other than a needed provision; remove the pre-check with directoryExists
and rely on EAFP (attempt verifyWritableDirectory and handle errors) so
alwaysProvision paths can create the home on first run.
src/application/commands/skills/embedded-assets.test.ts (1)

1013-1025: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cover all non-allowed-tools hosts in this frontmatter assertion.

This loop skips codebuddy and openclaw, so a renderer regression that starts emitting allowed-tools for either host would pass. Derive the list from availableBundledSkillAgentNames and exclude only the hosts that are expected to contain that field.

As per coding guidelines, "Any modification must include sufficient tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/embedded-assets.test.ts` around lines 1013 -
1025, The test currently iterates a hardcoded agent list and misses some hosts;
modify the loop to iterate over availableBundledSkillAgentNames (instead of the
hardcoded ["universal", ...]) and filter out only the known agents that are
expected to include "allowed-tools" (e.g., keep an explicit exclude set), then
for each skillName from availableBundledSkillNames use
getBundledSkillFiles(skillName, agentName) and
readBundledSkillFileContent(skillFile) as before and assert that the content
does not contain "allowed-tools" for all remaining agents; ensure the test
covers all agents by deriving the agent list from
availableBundledSkillAgentNames and only excluding the specific hosts that
should allow that field.
🧹 Nitpick comments (9)
src/application/commands/skills/list.cli.test.ts (1)

73-73: ⚡ Quick win

Prefer a line-based assertion here instead of a regex.

This check only needs to prove the Universal … controlled row is rendered, and the regex makes the test more brittle than necessary. A simple includes/line-scan assertion would be easier to maintain. As per coding guidelines, "Avoid using regular expressions when possible".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/list.cli.test.ts` at line 73, Replace the
brittle regex assertion on result.stdout with a line-based check: scan
result.stdout lines and assert that at least one line includes the distinct
tokens "Universal", "installed", and "controlled" (e.g. using split('\n') and
.some). Update the assertion that currently uses
toMatch(/Universal\s+installed\s+\S*controlled/) to this token-in-line style
using result.stdout so the test only verifies the rendered row without relying
on a regex.
src/application/commands/skills/init.test.ts (1)

18-41: ⚡ Quick win

Add one happy-path that does not pre-create the universal home.

These updated tests still mkdir() the universal agent home before invoking skills init, so they won't catch a regression in the new "universal is always provisioned" contract that this PR introduces. At least one --agent universal success case should rely on the command/bootstrap to create ~/.agents itself. As per coding guidelines, "Any modification must include sufficient tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/init.test.ts` around lines 18 - 41, Add a new
happy-path test that verifies "skills init --agent universal" succeeds when the
universal agent home does NOT exist beforehand: copy the existing test structure
in init.test.ts (using createCliSandbox(),
resolveManagedSkillAgentHomeDirectory(..., "universal"),
resolveManagedSkillDirectoryPath(..., "campaign-writer"), and sandbox.run([...
"skills","init", ...])) but do NOT call mkdir(universalHomeDirectory) before
invoking sandbox.run; after the command, assert the process succeeded and that
universalHomeDirectory and skillDirectoryPath now exist (and contain the
expected files) to ensure the command/bootstrap provisions the universal agent
home.
src/application/commands/skills/install-output.test.ts (1)

47-75: ⚡ Quick win

Build the fixture paths with join().

These hardcoded POSIX paths make the test data platform-specific. Use node:path helpers here too.

♻️ Proposed fix
+import { join } from "node:path";
 import { describe, expect, test } from "bun:test";
@@
                 {
                     agentName: "universal",
-                    path: "/tmp/universal/skills/chatgpt",
+                    path: join("tmp", "universal", "skills", "chatgpt"),
                 },
                 {
                     agentName: "claude",
-                    path: "/tmp/claude/skills/chatgpt",
+                    path: join("tmp", "claude", "skills", "chatgpt"),
                 },
@@
                 {
                     agentName: "universal",
-                    path: "/tmp/universal/skills/vision",
+                    path: join("tmp", "universal", "skills", "vision"),
                 },
                 {
                     agentName: "claude",
-                    path: "/tmp/claude/skills/vision",
+                    path: join("tmp", "claude", "skills", "vision"),
                 },
As per coding guidelines, "Never assume POSIX path separators in code, tests, snapshots, or assertions. Use `node:path` helpers such as `join()`, `resolve()`, and `relative()` for path construction."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/install-output.test.ts` around lines 47 - 75,
The test fixture createMultiSkillMultiAgentSummaries uses hardcoded POSIX paths
for the publication.path fields; replace those literal strings with
platform-safe constructions using node:path.join (and node:os.tmpdir() if
desired) so paths are built via join(...) instead of "/tmp/…". Import the
helpers from 'node:path' (and 'node:os' if using the system temp dir) and update
the path values in the createMultiSkillMultiAgentSummaries return objects
(publication.path entries for agents "universal" and "claude") to use path.join
with the appropriate path segments.
src/application/commands/uninstall.cli.test.ts (1)

59-60: ⚡ Quick win

Use the managed-skill path helpers here instead of re-encoding ~/.agents/skills.

This setup duplicates the host layout inline, which is exactly what this PR had to update. Building the path with resolveManagedSkillAgentHomeDirectory() and resolveManagedSkillDirectoryPath() will keep the test aligned with production behavior if the managed host layout changes again.

Suggested fix
-    const universalHome = join(options.sandbox.env.HOME!, ".agents");
-    const skillDirectory = join(universalHome, "skills", options.skillName);
+    const universalHome = resolveManagedSkillAgentHomeDirectory(
+        options.sandbox.env,
+        "universal",
+    );
+    const skillDirectory = resolveManagedSkillDirectoryPath(
+        universalHome,
+        options.skillName,
+    );

You'll also need to import the two path helpers in this file. As per coding guidelines, "When extracting a shared utility from production code, also replace any test helpers or inline expressions that duplicate the same logic."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/uninstall.cli.test.ts` around lines 59 - 60, Replace
the inline construction of the managed-skill path in the test by calling the
production helpers: use
resolveManagedSkillAgentHomeDirectory(options.sandbox.env.HOME) to get the
universalHome and resolveManagedSkillDirectoryPath(universalHome,
options.skillName) to get skillDirectory so the test mirrors production layout;
import both resolveManagedSkillAgentHomeDirectory and
resolveManagedSkillDirectoryPath at the top of the test file and remove the
join(...) expressions that hard-code "~/.agents/skills".
src/application/commands/skills/update.test.ts (1)

36-37: ⚡ Quick win

Extract a local helper for installed skill paths instead of repeating the host-layout join.

This file repeats the same resolveManagedSkillAgentHomeDirectory(...) + join(..., "skills", skillName) setup in many places, and this migration had to edit all of them. A single helper built on resolveManagedSkillDirectoryPath() would make the next host-layout change a one-line update.

Suggested helper
function resolveInstalledSkillDirectoryPath(
    sandbox: Awaited<ReturnType<typeof createCliSandbox>>,
    agentId: "universal" | "claude" | "hermes",
    skillName: string,
): string {
    return resolveManagedSkillDirectoryPath(
        resolveManagedSkillAgentHomeDirectory(sandbox.env, agentId),
        skillName,
    );
}

Then replace the repeated join(homeDirectory, "skills", "...") calls with this helper.

As per coding guidelines, "In test files, extract repeated setup (mock, stub, or setup objects) into a local factory function at the bottom of the file."

Also applies to: 117-118, 163-164, 191-192, 309-310, 398-399, 488-489, 619-620, 705-706, 810-811

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/update.test.ts` around lines 36 - 37, Extract
a local helper named resolveInstalledSkillDirectoryPath that takes the sandbox
(Awaited<ReturnType<typeof createCliSandbox>>), an agentId ("universal" |
"claude" | "hermes"), and skillName and returns
resolveManagedSkillDirectoryPath(resolveManagedSkillAgentHomeDirectory(sandbox.env,
agentId), skillName); then replace the repeated patterns that compute
universalHomeDirectory + join(..., "skills", skillName) (and similar for other
agents) with calls to resolveInstalledSkillDirectoryPath across this test file
(references include the existing resolveManagedSkillAgentHomeDirectory and
resolveManagedSkillDirectoryPath uses).
src/application/commands/skills/index.cli.test.ts (1)

63-70: ⚡ Quick win

Add a clean-machine startup bootstrap case.

Line 70 pre-creates universalHomeDirectory, so this test no longer exercises the new ~/.agents provisioning path. The regression-prone case here is starting the CLI with no managed home on disk and asserting startup bootstraps bundled skills into Universal.

As per coding guidelines, "Any modification must include sufficient tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/index.cli.test.ts` around lines 63 - 70, The
test "auto-installs bundled skills during cli startup" currently pre-creates
universalHomeDirectory (created via resolveManagedSkillAgentHomeDirectory in the
test using mkdir), which prevents exercising the clean-machine bootstrap path;
remove the pre-creation (the mkdir/universalHomeDirectory setup) or add a
separate test that ensures the managed home does not exist before invoking
createCliSandbox/startup, then run the CLI startup and assert that bundled
skills (skillDirectoryPath and findSkillsDirectoryPath) are created; update the
test around createCliSandbox, resolveManagedSkillAgentHomeDirectory, and the
assertions so the case where no managed home exists on disk is covered.
src/application/commands/skills/repair.cli.test.ts (1)

41-58: ⚡ Quick win

Cover repair --agent universal without an existing home directory.

All successful Universal repair cases still create the home first, so the suite does not prove the always-provisioned Universal host works on a clean machine. Please add one case where the canonical source exists, ~/.agents is absent, and skills repair --skill oo --agent universal recreates the host target.

As per coding guidelines, "Any modification must include sufficient tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/repair.cli.test.ts` around lines 41 - 58, Add
a new test (e.g., "repair --skill oo --agent universal creates home when
absent") that does not pre-create the universal home directory: use
createCliSandbox() to get sandbox, compute universalHomeDirectory with
resolveManagedSkillAgentHomeDirectory(sandbox.env, "universal") and ensure it
does not exist (do NOT call mkdir on it). Prepare the canonical/bundled source
for the "oo" skill (same approach as other tests: create or ensure the canonical
skill bundle that repair uses is present), then call
sandbox.run(["skills","repair","--skill","oo","--agent","universal"], { version:
TEST_CLI_VERSION }) and assert that universalHomeDirectory and the managed skill
directory (resolveManagedSkillDirectoryPath(universalHomeDirectory, "oo")) are
created and contain the expected files (e.g., SKILL.md matches the canonical
source). Ensure the test uses the same sandbox.run and
resolveManagedSkillDirectoryPath identifiers as the existing tests.
src/application/commands/skills/managed-skill-hosts.test.ts (1)

10-23: ⚡ Quick win

Extract the repeated temp-home setup into a local fixture helper.

Both tests rebuild the same rootDirectory/env/cleanup flow inline. Move that into a small helper at the bottom of the file so future host-case additions stay consistent.

As per coding guidelines, "In test files, extract repeated setup (mock, stub, or setup objects) into a local factory function at the bottom of the file."

Also applies to: 25-44

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/managed-skill-hosts.test.ts` around lines 10
- 23, Extract the repeated temporary-home setup used by tests (the
createTemporaryDirectory call, env = { HOME, USERPROFILE }, and the rm cleanup)
into a small local fixture factory function at the bottom of the file (e.g.,
makeTempHomeFixture) that returns { rootDirectory, env, cleanup } and call that
fixture from both tests that use resolveAvailableManagedSkillHosts; replace the
inline try/finally with awaiting the fixture and calling its cleanup, and keep
references to createTemporaryDirectory, resolveAvailableManagedSkillHosts, and
rm intact so the tests use the new helper consistently.
src/application/commands/skills/check.test.ts (1)

278-279: ⚡ Quick win

Reuse the managed skills path helper here.

join(openClawHomeDirectory, "skills") duplicates the production path logic that this suite already imports elsewhere. Using resolveManagedSkillsDirectoryPath(openClawHomeDirectory) keeps the test aligned with future path-layout changes.

As per coding guidelines, "When extracting a shared utility from production code, also replace any test helpers or inline expressions that duplicate the same logic. An extraction is incomplete if test files still contain local functions or raw inline code doing the same thing."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/check.test.ts` around lines 278 - 279, The
test duplicates production path logic by building publishRootPath with
join(openClawHomeDirectory, "skills"); replace that inline join with the shared
helper resolveManagedSkillsDirectoryPath(openClawHomeDirectory) so
publishRootPath is derived from resolveManagedSkillsDirectoryPath instead,
keeping references to resolveManagedSkillAgentHomeDirectory and
openClawHomeDirectory intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contrib/skills/shared/oo-create-skill/SKILL.md`:
- Line 3: The shared SKILL.md description hardcodes "Claude/agent skill", which
is misleading for non-Claude hosts; update the description in SKILL.md to use
neutral wording (e.g., "agent skill") or replace the hardcoded name with an
agentic-markdown variable (e.g., an agent-specific placeholder) so the rendered
text is host-agnostic — locate the string "Claude/agent skill" in SKILL.md and
replace it with the neutral term or variable.

In `@docs/path-first-skill-publish-plan.md`:
- Around line 10-12: The sample publish flow hardcodes the agent flag ("--agent
universal") which breaks for agent-native local skills; update the example so
the primary command omits the --agent flag (i.e., show "oo skills locate
<skill-id>" and "oo skills publish <path>") or explicitly instruct users to
supply the skill's owning agent when needed, and add a short note clarifying
that local skills remain agent-native and therefore may require an explicit
--agent if not using the default.

In `@src/application/commands/info.cli.test.ts`:
- Around line 79-85: The test is incorrectly creating the "universal"
managed-skill home which masks a regression where the info command might require
an existing directory; remove the mkdir call that uses
resolveManagedSkillAgentHomeDirectory(...) and
resolveManagedSkillsDirectoryPath(...), and instead assert that the "universal"
agent is reported as "available" when no directory exists (or add a separate
test case named e.g. "info: reports universal available when no home exists"
that verifies info returns available without creating the directory). Ensure the
test references the same helper functions/values
(resolveManagedSkillAgentHomeDirectory, resolveManagedSkillsDirectoryPath,
"universal") so it targets the no-home behavior.

In `@src/application/commands/skills/install.cli.test.ts`:
- Around line 54-58: The assertion depends on ordering by checking targets[0];
instead locate the entry with agentId "universal" and assert against that object
instead. In the test (variable targets) use Array.prototype.find to get the
element where agentId === "universal", assert that it exists, and then assert
its properties (e.g., status: "installed") with toMatchObject or equivalent so
the test is order-independent.

In `@src/application/commands/skills/legacy-codex-cleanup.test.ts`:
- Around line 55-60: Replace the weak assertions that only check for an
isDirectory function on the Stats object with assertions that call isDirectory()
and expect true: for each occurrence where you do await
expect(stat(localSkillPath)).resolves.toMatchObject({ isDirectory:
expect.any(Function) }) (and the similar checks for unmanagedSkillPath and the
other two occurrences around lines 103-105 and 141-143), instead await the stat
call (e.g., const s = await stat(localSkillPath)) and assert
expect(s.isDirectory()).toBe(true); do the same for unmanagedSkillPath and the
other two stat checks so the tests verify the path is actually a directory.

In `@src/application/commands/skills/legacy-codex-cleanup.ts`:
- Around line 44-48: The current Promise.all in removeLegacyCodexManagedSkills
causes a fail-fast return when removeLegacyCodexHomeManagedSkills rejects,
leaving removeLegacyCodexCanonicalBundledStorage running; change the
implementation to await both branches to settle (use Promise.allSettled or await
each branch with try/catch and capture errors) and then rethrow or return an
aggregated error after both have completed; update references in
removeLegacyCodexManagedSkills to ensure it only resolves after both
removeLegacyCodexHomeManagedSkills and removeLegacyCodexCanonicalBundledStorage
have settled, and add a test that mocks removeLegacyCodexHomeManagedSkills to
reject while verifying removeLegacyCodexCanonicalBundledStorage has completed
before removeLegacyCodexManagedSkills resolves/rejects (so run-cli.ts’s
synchronization race is prevented).

---

Outside diff comments:
In `@src/application/commands/skills/check.ts`:
- Around line 89-97: The code currently checks directoryExists(homeDirectory)
and throws createManagedSkillAgentNotInstalledError before honoring the
alwaysProvision behavior; instead, call verifyWritableDirectory(homeDirectory)
(or the existing helper that creates directories) for the resolved path returned
by resolveManagedSkillAgentHomeDirectory(agentName) and let it create the
directory or fail, catching errors and only throwing
createManagedSkillAgentNotInstalledError if verifyWritableDirectory fails for
reasons other than a needed provision; remove the pre-check with directoryExists
and rely on EAFP (attempt verifyWritableDirectory and handle errors) so
alwaysProvision paths can create the home on first run.

In `@src/application/commands/skills/embedded-assets.test.ts`:
- Around line 1013-1025: The test currently iterates a hardcoded agent list and
misses some hosts; modify the loop to iterate over
availableBundledSkillAgentNames (instead of the hardcoded ["universal", ...])
and filter out only the known agents that are expected to include
"allowed-tools" (e.g., keep an explicit exclude set), then for each skillName
from availableBundledSkillNames use getBundledSkillFiles(skillName, agentName)
and readBundledSkillFileContent(skillFile) as before and assert that the content
does not contain "allowed-tools" for all remaining agents; ensure the test
covers all agents by deriving the agent list from
availableBundledSkillAgentNames and only excluding the specific hosts that
should allow that field.

---

Nitpick comments:
In `@src/application/commands/skills/check.test.ts`:
- Around line 278-279: The test duplicates production path logic by building
publishRootPath with join(openClawHomeDirectory, "skills"); replace that inline
join with the shared helper
resolveManagedSkillsDirectoryPath(openClawHomeDirectory) so publishRootPath is
derived from resolveManagedSkillsDirectoryPath instead, keeping references to
resolveManagedSkillAgentHomeDirectory and openClawHomeDirectory intact.

In `@src/application/commands/skills/index.cli.test.ts`:
- Around line 63-70: The test "auto-installs bundled skills during cli startup"
currently pre-creates universalHomeDirectory (created via
resolveManagedSkillAgentHomeDirectory in the test using mkdir), which prevents
exercising the clean-machine bootstrap path; remove the pre-creation (the
mkdir/universalHomeDirectory setup) or add a separate test that ensures the
managed home does not exist before invoking createCliSandbox/startup, then run
the CLI startup and assert that bundled skills (skillDirectoryPath and
findSkillsDirectoryPath) are created; update the test around createCliSandbox,
resolveManagedSkillAgentHomeDirectory, and the assertions so the case where no
managed home exists on disk is covered.

In `@src/application/commands/skills/init.test.ts`:
- Around line 18-41: Add a new happy-path test that verifies "skills init
--agent universal" succeeds when the universal agent home does NOT exist
beforehand: copy the existing test structure in init.test.ts (using
createCliSandbox(), resolveManagedSkillAgentHomeDirectory(..., "universal"),
resolveManagedSkillDirectoryPath(..., "campaign-writer"), and sandbox.run([...
"skills","init", ...])) but do NOT call mkdir(universalHomeDirectory) before
invoking sandbox.run; after the command, assert the process succeeded and that
universalHomeDirectory and skillDirectoryPath now exist (and contain the
expected files) to ensure the command/bootstrap provisions the universal agent
home.

In `@src/application/commands/skills/install-output.test.ts`:
- Around line 47-75: The test fixture createMultiSkillMultiAgentSummaries uses
hardcoded POSIX paths for the publication.path fields; replace those literal
strings with platform-safe constructions using node:path.join (and
node:os.tmpdir() if desired) so paths are built via join(...) instead of
"/tmp/…". Import the helpers from 'node:path' (and 'node:os' if using the system
temp dir) and update the path values in the createMultiSkillMultiAgentSummaries
return objects (publication.path entries for agents "universal" and "claude") to
use path.join with the appropriate path segments.

In `@src/application/commands/skills/list.cli.test.ts`:
- Line 73: Replace the brittle regex assertion on result.stdout with a
line-based check: scan result.stdout lines and assert that at least one line
includes the distinct tokens "Universal", "installed", and "controlled" (e.g.
using split('\n') and .some). Update the assertion that currently uses
toMatch(/Universal\s+installed\s+\S*controlled/) to this token-in-line style
using result.stdout so the test only verifies the rendered row without relying
on a regex.

In `@src/application/commands/skills/managed-skill-hosts.test.ts`:
- Around line 10-23: Extract the repeated temporary-home setup used by tests
(the createTemporaryDirectory call, env = { HOME, USERPROFILE }, and the rm
cleanup) into a small local fixture factory function at the bottom of the file
(e.g., makeTempHomeFixture) that returns { rootDirectory, env, cleanup } and
call that fixture from both tests that use resolveAvailableManagedSkillHosts;
replace the inline try/finally with awaiting the fixture and calling its
cleanup, and keep references to createTemporaryDirectory,
resolveAvailableManagedSkillHosts, and rm intact so the tests use the new helper
consistently.

In `@src/application/commands/skills/repair.cli.test.ts`:
- Around line 41-58: Add a new test (e.g., "repair --skill oo --agent universal
creates home when absent") that does not pre-create the universal home
directory: use createCliSandbox() to get sandbox, compute universalHomeDirectory
with resolveManagedSkillAgentHomeDirectory(sandbox.env, "universal") and ensure
it does not exist (do NOT call mkdir on it). Prepare the canonical/bundled
source for the "oo" skill (same approach as other tests: create or ensure the
canonical skill bundle that repair uses is present), then call
sandbox.run(["skills","repair","--skill","oo","--agent","universal"], { version:
TEST_CLI_VERSION }) and assert that universalHomeDirectory and the managed skill
directory (resolveManagedSkillDirectoryPath(universalHomeDirectory, "oo")) are
created and contain the expected files (e.g., SKILL.md matches the canonical
source). Ensure the test uses the same sandbox.run and
resolveManagedSkillDirectoryPath identifiers as the existing tests.

In `@src/application/commands/skills/update.test.ts`:
- Around line 36-37: Extract a local helper named
resolveInstalledSkillDirectoryPath that takes the sandbox
(Awaited<ReturnType<typeof createCliSandbox>>), an agentId ("universal" |
"claude" | "hermes"), and skillName and returns
resolveManagedSkillDirectoryPath(resolveManagedSkillAgentHomeDirectory(sandbox.env,
agentId), skillName); then replace the repeated patterns that compute
universalHomeDirectory + join(..., "skills", skillName) (and similar for other
agents) with calls to resolveInstalledSkillDirectoryPath across this test file
(references include the existing resolveManagedSkillAgentHomeDirectory and
resolveManagedSkillDirectoryPath uses).

In `@src/application/commands/uninstall.cli.test.ts`:
- Around line 59-60: Replace the inline construction of the managed-skill path
in the test by calling the production helpers: use
resolveManagedSkillAgentHomeDirectory(options.sandbox.env.HOME) to get the
universalHome and resolveManagedSkillDirectoryPath(universalHome,
options.skillName) to get skillDirectory so the test mirrors production layout;
import both resolveManagedSkillAgentHomeDirectory and
resolveManagedSkillDirectoryPath at the top of the test file and remove the
join(...) expressions that hard-code "~/.agents/skills".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c8ec0a77-93b1-4a0d-890c-89b8f8e55f0a

📥 Commits

Reviewing files that changed from the base of the PR and between d7dab72 and 401dc54.

⛔ Files ignored due to path filters (2)
  • src/application/commands/__snapshots__/info.cli.test.ts.snap is excluded by !**/*.snap
  • src/application/commands/skills/__snapshots__/index.cli.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (53)
  • contrib/ci/npm-packages.test.ts
  • contrib/skills/shared/oo-create-skill/SKILL.md
  • contrib/skills/shared/oo-create-skill/agents/openai.yaml
  • contrib/skills/shared/oo-find-skills/SKILL.md
  • contrib/skills/shared/oo-find-skills/agents/openai.yaml
  • contrib/skills/shared/oo-publish-skill/agents/openai.yaml
  • contrib/skills/shared/oo/SKILL.md
  • contrib/skills/shared/oo/agents/openai.yaml
  • docs/commands.md
  • docs/commands.zh-CN.md
  • docs/path-first-skill-publish-plan.md
  • src/application/bootstrap/run-cli.test.ts
  • src/application/bootstrap/run-cli.ts
  • src/application/commands/info.cli.test.ts
  • src/application/commands/skills/__tests__/helpers.ts
  • src/application/commands/skills/bundled-skill-observation.test.ts
  • src/application/commands/skills/bundled-skill-observation.ts
  • src/application/commands/skills/bundled-skill-paths.ts
  • src/application/commands/skills/check-update.cli.test.ts
  • src/application/commands/skills/check.test.ts
  • src/application/commands/skills/check.ts
  • src/application/commands/skills/embedded-assets.test.ts
  • src/application/commands/skills/embedded-assets.ts
  • src/application/commands/skills/index.cli.test.ts
  • src/application/commands/skills/index.test.ts
  • src/application/commands/skills/info-inventory.test.ts
  • src/application/commands/skills/init.test.ts
  • src/application/commands/skills/install-output.test.ts
  • src/application/commands/skills/install.cli.test.ts
  • src/application/commands/skills/legacy-canonical-migration.test.ts
  • src/application/commands/skills/legacy-canonical-migration.ts
  • src/application/commands/skills/legacy-codex-cleanup.test.ts
  • src/application/commands/skills/legacy-codex-cleanup.ts
  • src/application/commands/skills/list.cli.test.ts
  • src/application/commands/skills/locate.test.ts
  • src/application/commands/skills/managed-skill-agents.test.ts
  • src/application/commands/skills/managed-skill-agents.ts
  • src/application/commands/skills/managed-skill-hosts.test.ts
  • src/application/commands/skills/managed-skill-hosts.ts
  • src/application/commands/skills/managed-skill-paths.test.ts
  • src/application/commands/skills/managed-skill-paths.ts
  • src/application/commands/skills/publish.test.ts
  • src/application/commands/skills/repair.cli.test.ts
  • src/application/commands/skills/share.test.ts
  • src/application/commands/skills/shared.test.ts
  • src/application/commands/skills/sync.cli.test.ts
  • src/application/commands/skills/uninstall.cli.test.ts
  • src/application/commands/skills/update.cli.test.ts
  • src/application/commands/skills/update.test.ts
  • src/application/commands/uninstall.cli.test.ts
  • src/application/self-update/uninstall.test.ts
  • src/application/self-update/uninstall.ts
  • src/i18n/catalog.ts
💤 Files with no reviewable changes (8)
  • src/application/commands/skills/bundled-skill-observation.test.ts
  • contrib/skills/shared/oo-create-skill/agents/openai.yaml
  • contrib/skills/shared/oo/agents/openai.yaml
  • contrib/skills/shared/oo-publish-skill/agents/openai.yaml
  • src/application/commands/skills/bundled-skill-observation.ts
  • contrib/skills/shared/oo/SKILL.md
  • contrib/skills/shared/oo-find-skills/agents/openai.yaml
  • src/i18n/catalog.ts

Comment thread contrib/skills/shared/oo-create-skill/SKILL.md Outdated
Comment thread docs/path-first-skill-publish-plan.md
Comment thread src/application/commands/info.cli.test.ts Outdated
Comment thread src/application/commands/skills/install.cli.test.ts
Comment thread src/application/commands/skills/legacy-codex-cleanup.test.ts Outdated
Comment thread src/application/commands/skills/legacy-codex-cleanup.ts Outdated
The cleanup used Promise.all, which short-circuits on the first
rejection and could leave the second branch unfinished. Switch to
Promise.allSettled so both the home and canonical bundled cleanups
always run, logging each failure independently as best-effort.

Also modernize the related stat assertions to call isDirectory()
directly and align the create-skill SKILL.md and publish docs with
the agent-neutral wording.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@BlackHole1
BlackHole1 merged commit eb5c9a4 into main Jun 2, 2026
6 checks passed
@BlackHole1
BlackHole1 deleted the remove-codex branch June 2, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant