Skip to content

feat(skills): add --force flag to install#233

Merged
BlackHole1 merged 2 commits into
mainfrom
add-add-force
May 25, 2026
Merged

feat(skills): add --force flag to install#233
BlackHole1 merged 2 commits into
mainfrom
add-add-force

Conversation

@BlackHole1
Copy link
Copy Markdown
Member

Allow oo skills install to overwrite an existing same-name skill directory that is not managed by oo (no readable .oo-metadata.json). Previously the install was blocked by a name conflict, forcing users to manually clean up the directory before retrying.

--force (or -f) replaces the previous contents and writes the new skill, emitting a warn log entry to record the overwrite. It still honors path containment, package validation, auth, and download validation, and does not affect startup auto-sync, update, sync, uninstall, or publish. In multi-skill packages it does not implicitly select all skills; combine with --skill or --all -y.

Telemetry records a low-cardinality has_force boolean so adoption of the new flag can be observed without leaking user input.

Allow `oo skills install` to overwrite an existing same-name skill
directory that is not managed by oo (no readable `.oo-metadata.json`).
Previously the install was blocked by a name conflict, forcing users
to manually clean up the directory before retrying.

`--force` (or `-f`) replaces the previous contents and writes the new
skill, emitting a `warn` log entry to record the overwrite. It still
honors path containment, package validation, auth, and download
validation, and does not affect startup auto-sync, `update`, `sync`,
`uninstall`, or `publish`. In multi-skill packages it does not
implicitly select all skills; combine with `--skill` or `--all -y`.

Telemetry records a low-cardinality `has_force` boolean so adoption
of the new flag can be observed without leaking user input.

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

coderabbitai Bot commented May 25, 2026

Review Change Stack

Summary by CodeRabbit

  • New Features
    • Added --force/-f to oo skills install, allowing overwrite of an existing unmanaged skill directory; removes prior contents and records a warning. Does not bypass validations or implicitly select all skills in multi-skill packages.
  • Documentation
    • Updated command docs (EN/CN) describing --force behavior and limitations.
  • Tests
    • Added tests covering --force overwrite behavior for bundled and registry installs.
  • Telemetry
    • Telemetry now records a has_force flag and related install metadata.

Walkthrough

This PR adds a --force/-f option to oo skills install to permit overwriting existing skill directories that lack oo-managed metadata (.oo-metadata.json). The flag is defined in the input schema with telemetry support and i18n translations. It is threaded through bundled and registry skill installation paths, where it bypasses conflict checks during selection and refactors validation to warn instead of error when unmanaged targets exist. Tests verify the overwrite behavior for both bundled and registry skills.

Possibly related PRs

  • oomol-lab/oo-cli#35: Adds canonical/symlink-based storage and unmanaged conflict detection to bundled-skill installation, which this PR extends with --force to control whether unmanaged conflicts block or allow overwrite.
  • oomol-lab/oo-cli#110: Modifies registry-skill publication and host-aware validation in validateRegistrySkillPublicationTargets, which this PR updates with --force and logger context parameters to support forced install scenarios.
  • oomol-lab/oo-cli#144: Extends RegistrySkillInstallRequest and threads new parameters through the registry install flow, similar to how this PR adds the force parameter to that same request type and execution path.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required format with type(scope): subject, clearly describing the main change of adding a --force flag to the install command.
Description check ✅ Passed The description is directly related to the changeset, detailing the --force flag functionality, its constraints, and telemetry implications across all modified files.
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 add-add-force

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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
docs/commands.md (1)

853-861: ⚡ Quick win

Remove internal log-level detail from command contract docs.

Consider dropping “a warn log records the overwrite” here. The option behavior is user-facing, but log severity is an internal implementation detail and can drift without changing command contract.

As per coding guidelines, docs/commands*.md: "Documentation under docs/commands*.md should describe only user-facing CLI contract ... Do not document internal implementation details."

🤖 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 `@docs/commands.md` around lines 853 - 861, Remove the internal logging detail
from the -f/--force option description: delete the phrase "a `warn` log records
the overwrite" so the docs only state the user-facing behavior of --force
(overrides install when the target directory exists and is not managed by oo,
removes previous contents before writing, and does not bypass path containment,
package validation, auth, download validation, or affect startup auto-sync / `oo
skills update` / `oo skills sync` / `oo skills uninstall` / `oo skills publish`,
nor implicitly select multi-skill packages — use `--skill` or `--all -y` with
`--force`). Ensure the resulting text contains only the CLI contract and no
implementation/log-level details.
docs/commands.zh-CN.md (1)

728-734: ⚡ Quick win

文档中建议去掉内部日志级别细节。

这里的 warn 日志级别属于实现细节,建议只保留 --force 的用户可观察行为说明,避免把内部日志实现写入命令契约文档。

As per coding guidelines, docs/commands*.md: "Documentation under docs/commands*.md should describe only user-facing CLI contract ... Do not document internal implementation details."

🤖 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 `@docs/commands.zh-CN.md` around lines 728 - 734, Remove the
implementation-detail about the internal log level from the `-f, --force` option
description: delete the phrase that says the override "并以 `warn` 日志记录此事件" and
any similar wording; keep only the user-facing behavior (that `--force` allows
overwriting a directory with an existing skill that lacks readable
`.oo-metadata.json`, and that it does not bypass path/package/auth/download
checks nor affect auto-sync or other `oo skills` commands and does not
implicitly select all skills). Ensure the option text references the flag `-f,
--force` and `.oo-metadata.json` but does not mention internal logging levels or
other implementation details.
🤖 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 `@src/application/commands/skills/index.test.ts`:
- Around line 1286-1384: Add assertions to verify the new telemetry property for
the `--force` path: after the call to sandbox.run([... "skills", "install",
"oo", "--force" ]) (or the `-f` case), retrieve the emitted telemetry event from
the test sandbox (using the same sandbox instance used in the test) and assert
that the telemetry properties include has_force: true and that no raw/private
fields are present (for example, assert the event properties do not contain keys
like api_key, openai_key, raw_input or other sensitive/raw fields). Apply this
check in at least one of the `--force` tests (e.g., the "`--force` overwrites an
unmanaged same-name bundled host directory" test) and mirror for the `-f`
short-flag test if desired; use the existing sandbox.run/createCliSandbox
variables to locate where to read the recorded telemetry event and add the
assertions right after the existing exitCode/stderr/metadataContent checks.

---

Nitpick comments:
In `@docs/commands.md`:
- Around line 853-861: Remove the internal logging detail from the -f/--force
option description: delete the phrase "a `warn` log records the overwrite" so
the docs only state the user-facing behavior of --force (overrides install when
the target directory exists and is not managed by oo, removes previous contents
before writing, and does not bypass path containment, package validation, auth,
download validation, or affect startup auto-sync / `oo skills update` / `oo
skills sync` / `oo skills uninstall` / `oo skills publish`, nor implicitly
select multi-skill packages — use `--skill` or `--all -y` with `--force`).
Ensure the resulting text contains only the CLI contract and no
implementation/log-level details.

In `@docs/commands.zh-CN.md`:
- Around line 728-734: Remove the implementation-detail about the internal log
level from the `-f, --force` option description: delete the phrase that says the
override "并以 `warn` 日志记录此事件" and any similar wording; keep only the user-facing
behavior (that `--force` allows overwriting a directory with an existing skill
that lacks readable `.oo-metadata.json`, and that it does not bypass
path/package/auth/download checks nor affect auto-sync or other `oo skills`
commands and does not implicitly select all skills). Ensure the option text
references the flag `-f, --force` and `.oo-metadata.json` but does not mention
internal logging levels or other implementation details.
🪄 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: c7b7362e-f1cf-423c-ba05-653402de1f00

📥 Commits

Reviewing files that changed from the base of the PR and between 7a128b2 and 7366a24.

📒 Files selected for processing (8)
  • docs/commands.md
  • docs/commands.zh-CN.md
  • src/application/commands/skills/index.test.ts
  • src/application/commands/skills/install.ts
  • src/application/commands/skills/registry-skill-install.ts
  • src/application/commands/skills/registry-skill-publication.ts
  • src/application/commands/skills/shared.ts
  • src/i18n/catalog.ts

Comment thread src/application/commands/skills/index.test.ts
Signed-off-by: Kevin Cui <bh@bugs.cc>
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.

♻️ Duplicate comments (1)
src/application/commands/skills/index.test.ts (1)

2967-3040: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add telemetry assertions for the registry --force path.

The past review comment requested telemetry assertions for --force tests and specifically mentioned "Also applies to: 2948-3021" (the original location of this test). While the bundled-skill test now has telemetry assertions, this registry-install test still lacks them. Please add assertions to verify has_force: true, package_kind: "registry", package_name: "openai", and absence of forbidden properties.

💡 Suggested assertion block
             expect(
                 await readFile(join(codexSkillDirectoryPath, "SKILL.md"), "utf8"),
             ).toContain("# ChatGPT");
+            const storePaths = resolveStorePaths({
+                appName: APP_NAME,
+                env: sandbox.env,
+                platform: process.platform,
+            });
+            const telemetryPayload = parseTelemetryRowPayload(
+                readTelemetryRowsForTest(storePaths.telemetryDirectory)[0]!,
+            );
+            expect(telemetryPayload).toMatchObject({
+                properties: {
+                    command_full: "skills.install",
+                    has_force: true,
+                    package_kind: "registry",
+                    package_name: "openai",
+                },
+            });
+            expect(telemetryPayload.properties).not.toHaveProperty("cwd");
+            expect(telemetryPayload.properties).not.toHaveProperty("path");
+            expect(telemetryPayload.properties).not.toHaveProperty("file_name");
         }
         finally {
             await sandbox.cleanup();

As per coding guidelines, src/application/commands/**/*.{ts,test.ts}: "When adding command-specific telemetry properties, add or update tests that assert the expected safe property shape and absence of raw/private values."

🤖 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.test.ts` around lines 2967 - 3040, The
test "`--force` installs a published registry skill over an unmanaged host
target" currently lacks telemetry assertions; update the test (inside the same
test block after the sandbox.run call and after checking exitCode/stderr) to
assert telemetry properties on the captured telemetry payload (the same place
you inspect result) verifying has_force: true, package_kind: "registry",
package_name: "openai" and ensure forbidden/raw properties (e.g. any private
tokens/URLs) are not present; reference the test's result from sandbox.run and
the same test flow that creates the registry archive
(createRegistrySkillArchiveBytes) so the assertions run for the registry install
path and maintain existing checks that read SKILL.md and
resolveManagedSkillMetadataFilePath/renderSkillMetadataJson.
🤖 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.

Duplicate comments:
In `@src/application/commands/skills/index.test.ts`:
- Around line 2967-3040: The test "`--force` installs a published registry skill
over an unmanaged host target" currently lacks telemetry assertions; update the
test (inside the same test block after the sandbox.run call and after checking
exitCode/stderr) to assert telemetry properties on the captured telemetry
payload (the same place you inspect result) verifying has_force: true,
package_kind: "registry", package_name: "openai" and ensure forbidden/raw
properties (e.g. any private tokens/URLs) are not present; reference the test's
result from sandbox.run and the same test flow that creates the registry archive
(createRegistrySkillArchiveBytes) so the assertions run for the registry install
path and maintain existing checks that read SKILL.md and
resolveManagedSkillMetadataFilePath/renderSkillMetadataJson.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a0cdb1b-5fcc-41ee-97e7-f8eb1df57421

📥 Commits

Reviewing files that changed from the base of the PR and between 7366a24 and 51a29e1.

📒 Files selected for processing (2)
  • src/application/commands/skills/index.test.ts
  • src/application/commands/telemetry-decisions.test.ts

@BlackHole1 BlackHole1 merged commit 753d1ce into main May 25, 2026
6 checks passed
@BlackHole1 BlackHole1 deleted the add-add-force branch May 25, 2026 14:52
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