Skip to content

fix(cua-driver): thread --force through skills link_agent - #1970

Open
f-trycua wants to merge 1 commit into
mainfrom
fix/skills-link-force-flag
Open

fix(cua-driver): thread --force through skills link_agent#1970
f-trycua wants to merge 1 commit into
mainfrom
fix/skills-link-force-flag

Conversation

@f-trycua

@f-trycua f-trycua commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

cua-driver skills install --force and cua-driver skills update both re-fetched the skill pack but did not actually repoint per-agent symlinks that already existed — link_agent ignored the force flag entirely. So when switching between a release install and a local-build install (both land at ~/.cua-driver/skills/cua-driver, but the link's resolved target needs refreshing if the pack was rebuilt or moved) the stale links were stuck:

$ cua-driver skills install
✅ Skill pack at /Users/.../.cua-driver/skills/cua-driver
  ✅ linked Claude Code skill at /Users/.../.claude/skills/cua-driver
  ✅ linked Codex skill at /Users/.../.agents/skills/cua-driver
  ✅ linked OpenCode skill at /Users/.../.config/opencode/skills/cua-driver
  Hermes skill link already exists at /Users/.../.hermes/skills/cua-driver (skipping)
                                                                            ^^^^^^^^^^
                                                                            no way out

update advertised itself as "same as install --force" in the docstring but had the same gap.

Fix

Single-file change in crates/cua-driver/src/skills.rs:

  • Pass force to link_agent() from the AGENTS loop.
  • In link_agent, when the link exists + resolves (case 2) and force=true, remove + recreate only if it's a symlink/junction. If the path is a real directory (case 4), still skip unconditionally — even under --force we never recursively delete user-managed content at the agent's skill-dir path.
  • Tighten the "already exists" message to mention --force / skills update so users discover the escape hatch from the output.
  • Document the new case-2 fork on link_agent. Update the top-of-file subcommand list — it claimed update was the same as install --force, which had been wrong since the force flag never reached the link path.

Diff: +39 / -9 on one file.

Test plan

Verified with an isolated HOME smoke harness:

  • install (no flag) → existing Hermes symlink skipped with the improved message; case-4 real-dir skipped; other agents get fresh links.
  • install --force → Hermes symlink refreshed; case-4 real-dir at ~/.claude/skills/cua-driver left alone; other agents refreshed.
  • update → same behavior as install --force.
  • cargo check -p cua-driver clean.

Adjacent issue (not in this PR)

uninstall.sh sweeps Claude / Codex / OpenClaw / OpenCode skill links but not ~/.gemini/skills/cua-driver (Antigravity) or ~/.hermes/skills/cua-driver (Hermes) — both added to AGENTS in skills.rs without matching the bash uninstaller. That's how the user originally arrived at the stuck Hermes link in the first place. Splitting into a separate single-concern PR; will file an issue.

Summary by CodeRabbit

Release Notes

  • Documentation

    • Clarified --force flag documentation in the update subcommand, explicitly describing its behavior of re-fetching and repointing symlinks for existing installations.
  • Bug Fixes

    • Improved symlink and directory handling logic during force-update operations to prevent accidental deletion of existing directories while properly updating linked resources.

`cua-driver skills install --force` and `cua-driver skills update` both
re-fetch the skill pack but did NOT actually repoint per-agent symlinks
that already existed — link_agent ignored the force flag entirely. So
switching between a release install and a local-build install (which
both land at `~/.cua-driver/skills/cua-driver`, but the link's resolved
target needs refreshing if the pack was rebuilt or moved) left stale
links in place with no escape hatch.

The fix is a single-file change:

- Pass `force` to `link_agent()` from the AGENTS loop.
- In `link_agent`, when the link exists + resolves (case 2) and
  `force=true`, remove + recreate IF it's a symlink/junction. If the
  path is a real directory (case 4), still skip unconditionally — even
  under --force we never recursively delete user-managed content at the
  agent's skill-dir path.
- Tighten the existing 'already exists' message to mention --force /
  `skills update` so users discover the escape hatch from the output.
- Doc-comment the new case 2 fork on `link_agent`. Update the top-of-file
  subcommand list to match (it claimed `update` was the same as `install
  --force`, which had been a lie since the force flag never reached the
  link path).

Verified with an isolated HOME smoke harness covering:
  - install (no flag) → existing links skipped
  - install --force → symlinks refreshed, real-dir at link path left alone
  - update → same behavior as install --force
@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Jun 22, 2026 7:00pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

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: ca6059c6-ddd9-46a1-aa8e-3bf2c2a28c86

📥 Commits

Reviewing files that changed from the base of the PR and between 08aa9c8 and b0a8035.

📒 Files selected for processing (1)
  • libs/cua-driver/rust/crates/cua-driver/src/skills.rs

📝 Walkthrough

Walkthrough

Adds a force boolean parameter to the internal link_agent function in skills.rs. The install/update loop passes this flag (true for update), and link_agent now branches on it: already-resolved links are skipped without force, recreated under force if a symlink/junction, or always skipped if a real directory. Command docs are updated accordingly.

Changes

Force-aware symlink refresh in link_agent

Layer / File(s) Summary
Signature change, state-machine docs, and command docs
libs/cua-driver/rust/crates/cua-driver/src/skills.rs
Module-level docs updated to describe --force and update alias semantics; link_agent signature extended with force: bool and inline state-machine commentary updated to describe the new resolved-link branching path.
Force-aware branching and call-site wiring
libs/cua-driver/rust/crates/cua-driver/src/skills.rs
link_agent now returns Ok(false) for already-resolved links when force is false, refuses deletion for real directories under force, and removes then recreates symlinks/junctions under force. The install loop call to link_agent passes the computed force flag.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • trycua/cua#1683: Modifies the same link_agent function in skills.rs to distinguish already-resolved vs. dangling symlink/junction states — the direct predecessor to the force parameter added here.

Poem

🐇 Hippity-hop through the symlink maze,
Old links resolved? I'll leave them in place!
But --force me and I'll snip with care,
Real directories? Those I won't dare.
A junction removed, a fresh pointer made,
No stale skill packs left in the shade! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(cua-driver): thread --force through skills link_agent' directly and specifically describes the main code change: passing the --force parameter through to the link_agent function to fix symlink updates in the skills command.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/skills-link-force-flag

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

Copy link
Copy Markdown
Contributor

Linux visual regression artifacts

Matrix jobs now run independently. Download visual artifacts from this workflow run.
Each background-GUI job uploads a .gif of the interaction plus two annotated PNGs (<app>.png raw, <app>-atspi.png with AT-SPI element boxes); the cua-driver-linux-som-overlays artifact adds <app>-som.png cua Set-of-Marks overlays:

  • cua-driver-linux-cursor-click-gif
  • cua-driver-linux-background-terminal-gif
  • cua-driver-linux-parallel-drag-xserver
  • cua-driver-linux-background-gui-chromium
  • cua-driver-linux-background-gui-tk
  • cua-driver-linux-background-gui-gtk3-gedit
  • cua-driver-linux-background-gui-gtk3-mousepad
  • cua-driver-linux-background-gui-gtk3-scite
  • cua-driver-linux-background-gui-gtk4-characters
  • cua-driver-linux-background-gui-qt5-manuskript
  • cua-driver-linux-background-gui-qt5-klog
  • cua-driver-linux-background-gui-qt5-openambit
  • cua-driver-linux-background-gui-qt6-kate
  • cua-driver-linux-background-gui-qt6-kcalc
  • cua-driver-linux-background-gui-qt6-okular
  • cua-driver-linux-background-gui-qt6-qownnotes
  • cua-driver-linux-background-gui-electron-zettlr
  • cua-driver-linux-background-gui-electron-joplin
  • cua-driver-linux-background-gui-electron-logseq
  • cua-driver-linux-som-overlays

Open workflow run and download artifacts

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