feat(workspace): `skill publish <name>` and a "Publish to workspace" action

Merged
SA
2mo ago
+491-17

Issue for this PR

Part of #1271 β€” the surface. #1280 added the publish path; this PR is what invokes it.

Was stacked on #1280; retargeted to main after it merged (rebuilt as one commit carrying only the command and the dialog action). The skill publish command here is what ran the end-to-end pass recorded on #1280.

Type of change

  • New feature

What does this PR do?

Two ways to publish a locally authored skill to the linked workspace, saying the same things.

altimate-code skill publish <name> β€” resolves the skill the way skill test does, refuses a built-in (there is no directory to bundle; the workspace-owned snapshot is refused by publishSkill itself), and prints one line on success. Every deliberate refusal is printed as-is, because each already says what to do next:

$ altimate-code skill publish hello
This project is not linked to a workspace. Run `altimate-code link` first.

"Publish to workspace" in the Skills dialog's per-skill action picker, next to Show / Edit / Test / Remove. This is the discoverability half: the UAT report was that a participant could not tell whether publishing from the CLI was possible at all. A row that anyone who opens a skill will see answers that; a row under /workspace would only be found by someone already thinking about workspaces β€” and the verb needs a skill name, which that menu does not have. Disabled for built-ins and for skills the workspace sent us, the same way Remove is disabled for built-ins.

Deliberately not done: auto-publishing from skill create. A freshly scaffolded skill is a stub, publish should be an explicit "this is ready for the team" act, and create works on unlinked projects where publish cannot.

describePublish / explainPublishError in skill-publish.ts give both surfaces one vocabulary; a skill_published telemetry event records the outcome alongside the existing skill_created / skill_installed / skill_removed.

How did you verify your code works?

  • 538 pass across test/altimate/workspace, test/altimate/plugin, the install classifier and the fork-feature guards; typecheck clean.
  • New tests pin the shared wording and that a deliberate error passes through while an unexpected one does not.
  • skill publish smoke-run from source on an unlinked project (prints the not-linked line) and on a missing skill (prints the not-found line); skill --help lists the subcommand.

Screenshots / recordings

Not a visual change beyond one new row in an existing picker.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

πŸ€– Generated with Claude Code

https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6


Summary by cubic

Adds a skill publish <name> CLI command and a "Publish to workspace" action in the Skills dialog's per-skill picker, so locally authored skills can be uploaded to the linked workspace (part of #1271). The publish path from #1280 existed but nothing invoked it; the dialog's built-in check only caught embedded and relative skills, so filesystem-installed built-ins under ~/.altimate/builtin were publishable and publishing one would have synced a managed override to the whole team.

  • Both surfaces now refuse built-ins, personal skills, workspace-sent skills, symlinked skill roots, and skills whose real path lies outside the project, using shared describePublish/explainPublishError wording.
  • Skills are judged against the worktree root (or the session directory when the project has no git), so publishing from a subdirectory still reaches skills under the repo root; the boundary is resolved before checking, so a root symlinked to / can't bypass the fallback.
  • Path classification uses path.relative segments rather than string prefixes, so siblings like ~/.claude/skills-archive aren't mistaken for personal skills. The picker publishes one skill at a time instead of double-firing on Enter, and a skill_published telemetry event records the outcome from both CLI and TUI. The CLI's not-found message no longer assumes .opencode/skills is the only location.

Summary by CodeRabbit

  • New Features
    • Added CLI support for publishing project skills to a linked workspace.
    • Added a β€œPublish to workspace” action in the skill picker.
    • Added publishing summaries, error messages, and telemetry for created or updated skills.
  • Bug Fixes
    • Prevented publishing built-in, personal, symlinked, root-level, or out-of-project skills.
    • Improved skill classification for similarly named directories and consistent CLI/TUI behavior.
    • Prevented duplicate publish actions while a publish is in progress.
  • Tests
    • Added coverage for publishing workflows, validation, error handling, and skill classification.