Skip to content

fix(skills): preserve same-version legacy targets during auto-sync#195

Merged
BlackHole1 merged 1 commit into
mainfrom
fix-auto-sync
May 12, 2026
Merged

fix(skills): preserve same-version legacy targets during auto-sync#195
BlackHole1 merged 1 commit into
mainfrom
fix-auto-sync

Conversation

@BlackHole1
Copy link
Copy Markdown
Member

Startup synchronization previously rewrote oo-managed legacy symlink targets and re-published skills whenever the publication state was considered stale, even when the installed version already matched the running CLI. This produced unexpected churn for users who had not asked to migrate legacy installations.

Auto-sync now leaves same-version targets alone and only adopts legacy matching local copies by writing metadata in place. Bundled skill targets installed at the development version are also skipped so local development copies stay untouched across release-version startups. Use oo skills add for bundled and local skills, and oo skills update for registry skills, to migrate legacy symlinks explicitly.

Startup synchronization previously rewrote oo-managed legacy symlink
targets and re-published skills whenever the publication state was
considered stale, even when the installed version already matched
the running CLI. This produced unexpected churn for users who had
not asked to migrate legacy installations.

Auto-sync now leaves same-version targets alone and only adopts
legacy matching local copies by writing metadata in place. Bundled
skill targets installed at the development version are also skipped
so local development copies stay untouched across release-version
startups. Use `oo skills add` for bundled and local skills, and
`oo skills update` for registry skills, to migrate legacy symlinks
explicitly.

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

coderabbitai Bot commented May 12, 2026

Review Change Stack

Summary by CodeRabbit

  • Documentation
    • Updated AI Agent Skills command documentation in English and Chinese to clarify startup synchronization: development-version bundled skills are no longer auto-refreshed during startup, legacy symlinks are preserved unless explicitly updated via oo skills add or oo skills update, and symlink replacement occurs only during explicit operations.

Walkthrough

This PR refines the managed skill startup synchronization logic by removing dependency on "publication current" state checks and replacing them with direct metadata/version matching. It adds explicit handling to skip synchronization when the running CLI or installed skill is a development build. The changes preserve symlinks instead of converting them to copies and require users to run explicit oo skills add/oo skills update commands for symlink migration rather than relying on automatic startup synchronization. Documentation and tests are updated to reflect these new semantics.

Possibly related PRs

  • oomol-lab/oo-cli#169: Modifies startup managed-skill synchronization logic in auto-sync.ts with related CLI startup tests and documentation changes.
  • oomol-lab/oo-cli#153: Changes how isManagedSkillPublicationCurrent is consulted in skill synchronization; this PR removes its gating entirely.
  • oomol-lab/oo-cli#111: Modifies managed-skills startup synchronization in auto-sync.ts and related tests, with this PR refining the skip semantics introduced there.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required format '(): ' and clearly summarizes the main change of preserving same-version legacy targets during auto-sync.
Description check ✅ Passed The description is directly related to the changeset, explaining the problem addressed and the new behavior for startup synchronization of legacy symlink targets.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix-auto-sync

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
src/application/commands/skills/auto-sync.ts (1)

479-493: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Move the “adopted” log after metadata writes complete.

At Line 482 the info log is emitted before writeLocalSkillMetadata(...) finishes. If either write fails, logs can contain both “adopted” and “failed” for the same attempt.

Suggested fix
             if (
                 metadataState.metadata === undefined
                 && !metadataState.exists
             ) {
-                context.logger.info(
-                    {
-                        agentName: installation.agentName,
-                        path: installation.installedSkillDirectoryPath,
-                        skillName: skill.name,
-                    },
-                    "Local skill startup synchronization adopted a legacy matching target.",
-                );
-                await Promise.all([
-                    writeLocalSkillMetadata(skill.path),
-                    writeLocalSkillMetadata(installation.installedSkillDirectoryPath),
-                ]);
+                await writeLocalSkillMetadata(skill.path);
+                await writeLocalSkillMetadata(
+                    installation.installedSkillDirectoryPath,
+                );
+                context.logger.info(
+                    {
+                        agentName: installation.agentName,
+                        path: installation.installedSkillDirectoryPath,
+                        skillName: skill.name,
+                    },
+                    "Local skill startup synchronization adopted a legacy matching target.",
+                );
                 return;
             }
🤖 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/auto-sync.ts` around lines 479 - 493, The
info log about "Local skill startup synchronization adopted a legacy matching
target" is currently emitted before the two async writes complete; move the
context.logger.info call so it runs after awaiting
Promise.all([writeLocalSkillMetadata(skill.path),
writeLocalSkillMetadata(installation.installedSkillDirectoryPath)]), keeping the
same log payload (agentName, path, skillName) and message, so the "adopted"
message is only logged on successful completion of writeLocalSkillMetadata for
both targets (refer to metadataState, installation, skill,
writeLocalSkillMetadata and context.logger).
🧹 Nitpick comments (1)
src/application/commands/skills/index.cli.test.ts (1)

372-419: ⚡ Quick win

Add an assertion for metadata adoption in the local-symlink startup test.

This test verifies symlink preservation, but the new behavior also adopts legacy matching targets by writing local metadata. Please assert .oo-metadata.json exists after startup to lock that behavior.

Suggested test assertion
             expect((await lstat(codexSkillDirectoryPath)).isSymbolicLink()).toBeTrue();
             expect(await readFile(join(codexSkillDirectoryPath, "SKILL.md"), "utf8")).toBe(
                 "# Campaign Writer\n",
             );
+            await expect(
+                stat(join(canonicalSkillDirectoryPath, ".oo-metadata.json")),
+            ).resolves.toMatchObject({
+                isFile: expect.any(Function),
+            });
             expect(content).not.toContain(
                 `"msg":"Local skill synchronized during CLI startup."`,
             );

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 372 - 419,
The test "leaves synchronized local symlink targets unchanged during cli
startup" currently verifies symlink preservation but doesn't assert that the new
metadata adoption behavior occurred; update this test (in the same test
function) to check that the local metadata file ".oo-metadata.json" has been
created inside the local symlink target after startup by asserting its
existence/readability at join(codexSkillDirectoryPath, ".oo-metadata.json") (use
existing helpers like readFile or stat/exists as used elsewhere) so the test
locks in the metadata-adoption behavior introduced by the startup
synchronization code.
🤖 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.

Outside diff comments:
In `@src/application/commands/skills/auto-sync.ts`:
- Around line 479-493: The info log about "Local skill startup synchronization
adopted a legacy matching target" is currently emitted before the two async
writes complete; move the context.logger.info call so it runs after awaiting
Promise.all([writeLocalSkillMetadata(skill.path),
writeLocalSkillMetadata(installation.installedSkillDirectoryPath)]), keeping the
same log payload (agentName, path, skillName) and message, so the "adopted"
message is only logged on successful completion of writeLocalSkillMetadata for
both targets (refer to metadataState, installation, skill,
writeLocalSkillMetadata and context.logger).

---

Nitpick comments:
In `@src/application/commands/skills/index.cli.test.ts`:
- Around line 372-419: The test "leaves synchronized local symlink targets
unchanged during cli startup" currently verifies symlink preservation but
doesn't assert that the new metadata adoption behavior occurred; update this
test (in the same test function) to check that the local metadata file
".oo-metadata.json" has been created inside the local symlink target after
startup by asserting its existence/readability at join(codexSkillDirectoryPath,
".oo-metadata.json") (use existing helpers like readFile or stat/exists as used
elsewhere) so the test locks in the metadata-adoption behavior introduced by the
startup synchronization code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 40a7d8f3-36f5-44a0-8d27-438d646c498f

📥 Commits

Reviewing files that changed from the base of the PR and between b9d60cc and 85110ba.

📒 Files selected for processing (4)
  • docs/commands.md
  • docs/commands.zh-CN.md
  • src/application/commands/skills/auto-sync.ts
  • src/application/commands/skills/index.cli.test.ts

@BlackHole1 BlackHole1 merged commit 702dc27 into main May 12, 2026
6 checks passed
@BlackHole1 BlackHole1 deleted the fix-auto-sync branch May 12, 2026 07:07
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