fix(#2644): deduplicate Cursor slash menu (#2812)

* fix(#2644): deduplicate Cursor slash menu

* fix: preserve installer executable mode

* chore: add changeset for PR #2812

* test(#2644): acknowledge Cursor emission changes

* test(#2644): drop spent emitted drift acknowledgments

* fix(#2644): remove retired Cursor command converter

---------

Co-authored-by: clezcoding <clezcoding@users.noreply.github.com>
Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
This commit is contained in:
𝚌𝚕𝚎𝚣𝚌𝚘𝚍𝚒𝚗𝚐
2026-08-03 18:05:45 +02:00
committed by GitHub
parent 067a4d1c6c
commit 88f6d9bd1b
29 changed files with 727 additions and 360 deletions

View File

@@ -422,6 +422,7 @@
"research-provider.cjs",
"research-store.cjs",
"resolution.cjs",
"retired-artifact-cleanup.cjs",
"review-lane-descriptor.cjs",
"review-lane-invocation.cjs",
"review-lane-runner.cjs",

View File

@@ -508,6 +508,7 @@ Full listing: `gsd-core/bin/lib/*.cjs`.
| `prompt-budget.cjs` | Pure token-budget accounting for review prompts — estimates tokens, applies deterministic trim priority (head-shrink PROJECT.md, proportional plan truncation, drop context/research/requirements, hard-fail guard), returns structured metadata for `review.max_prompt_tokens` (#3081) |
| `research-provider.cjs` | Research provider waterfall, confidence tiers, and planResearch (cache-hits + fetch plan) |
| `research-store.cjs` | Content-addressed research cache: sha256 keys, per-source TTL staleness, two-tier (user ~/.gsd / project .planning) store |
| `retired-artifact-cleanup.cjs` | Manifest-safe cleanup for descriptor-declared retired runtime artifact surfaces; shared by install and profile/surface apply so removed layout kinds converge without deleting modified or unknown user files (#2644) |
| `probe-core.cjs` | Generic spec-phase probe resolution model (compiled from `src/probe-core.cts`, gitignored; ADR-550 Decision 7) — the status×verification re-cut (`status: resolved/dismissed/unresolved` × per-probe `verification`), `validateResolution`/`validateRequirement`, `analyzeCoverage(items, resolutions?, validators)` merge/rollup/orphan-reject, the `byVerification` rollup, and the `runProbeCli` I/O scaffold; the shared seam consumed by `edge-probe` (and the prohibition probe #644); exports `VALID_STATUS`, `validateResolution`, `validateRequirement`, `analyzeCoverage`, `runProbeCli` (#550) |
| `prohibition-enforcement.cjs` | Deterministic test-tier prohibition PRODUCER/gate (compiled from `src/prohibition-enforcement.cts`, gitignored; #1259, ADR-550 D5d "heavy half") — locates the wired mechanical check (`node-test` or `lint-rule`), confirms it is fail-first, runs it via an injectable runner, builds typed `enforcementEvidence`, and emits the `dispositionForProhibition` verdict; a passing wired check disposes green, a missing/failing/non-fail-first check hard-gates (flagged, non-green) in both interactive and autonomous modes; exports `runProhibitionEnforcement`, `routeProhibitionEnforcement`; CLI surface `gsd_run check prohibition-enforcement <request.json>` |
| `review-lane-descriptor.cjs` | Declared reviewer-lane contract (compiled from `src/review-lane-descriptor.cts`, gitignored; ADR-2782) — the frozen `REVIEWER_LANES` roster, the lane slug grammar, and two pure parity gates: `checkReviewerLaneParity` (descriptor ↔ roster ↔ registry, plus anti-parity against re-added bespoke workflow legs) and `checkReviewerDocsParity` (declared flags and section titles ↔ `docs/COMMANDS.md`, `docs/FEATURES.md` and their locale mirrors; #2800, closes #2781/#2272); exports `REVIEWER_LANES`, `PARITY_VIOLATION`, `DOCS_PARITY_VIOLATION`, `LANE_SLUG_RE` |

View File

@@ -282,7 +282,7 @@ COPILOT_CONFIG_DIR=~/.copilot-alt npx @opengsd/gsd-core@latest --copilot --globa
npx @opengsd/gsd-core@latest --cursor --global
```
Artifacts land in `~/.cursor/`. GSD installs slash commands (`~/.cursor/commands/gsd-*.md`), skills (`~/.cursor/skills/gsd-*/SKILL.md`), agents, and rule references. Each GSD action appears once in Cursor's `/` menu: the command surface is the single `/` entry point, and the skills are installed with `user-invocable: false` so they stay model-invocable background knowledge without duplicating the `/` entries.
Artifacts land in `~/.cursor/`. GSD installs skills (`~/.cursor/skills/gsd-*/SKILL.md`), agents, and rule references. Cursor exposes each skill once in the `/` menu while keeping it available for contextual model invocation. Upgrading removes manifest-managed legacy `~/.cursor/commands/gsd-*.md` copies that previously duplicated those menu entries; unknown user-authored command files are preserved.
**Override the install directory:**

View File

@@ -505,6 +505,7 @@ Each row corresponds to one migration record in `src/installer-migrations/`.
| `2026-07-17-opencode-baseline-commands-dir` | `005-opencode-baseline-commands-dir.cts` | 1.7.0 | global, local | No | Baselines pre-existing files under OpenCode's `commands/` (plural) directory during the first-time scan. #2329 moved OpenCode command materialization to `commands/`, but 000's `RUNTIME_SURFACES.opencode` is a shipped, immutable body that still only names the legacy `command/` alias, so this fix-forward migration widens the scanned surface. OpenCode only; Kilo is unaffected. |
| `2026-07-20-pi-extension-cjs-to-js` | `006-pi-extension-cjs-to-js.cts` | 1.7.1 | global, local | Yes | Removes the stale `extensions/gsd.cjs` left by pre-#2470 pi installs. pi's extension auto-discovery (`isExtensionFile()`) accepts only `.ts`/`.js`, so the `.cjs` file was never loaded and `/gsd` never registered; #2470 renamed the installed artifact to `extensions/gsd.js`, orphaning the old path. Locally modified copies are backed up rather than deleted; an unmanifested `gsd.cjs` is preserved as a user file. pi only. |
| `2026-07-28-retire-config-root-commonjs-marker` | `007-retire-config-root-commonjs-marker.cts` | 1.8.0 | global, local | Yes | Removes `<configRoot>/package.json` when it is exactly the `{"type":"commonjs"}` marker pre-#2544 installs wrote there. #2544 moved that marker into the directories GSD fills (`hooks/`, and the native plugin dir), so an upgraded install would otherwise keep both and stay pinned to CommonJS at a config root GSD no longer writes. Ownership is proven by exact content match, not the manifest (the marker was never manifest-recorded) — a `package.json` with any other content is left untouched, with no backup-and-remove branch. All runtimes; kimi's root marker lives outside `configDir` and is retired by the installer instead. |
| `2026-07-29-cursor-retire-commands-surface` | `008-cursor-retire-commands-surface.cts` | 1.8.1 | global, local | Yes | Removes manifest-managed `commands/gsd-*.md` files from Cursor installs. Cursor already exposes the corresponding skills in the slash menu and to contextual model invocation, so the command copies produced duplicate entries (#2644). Modified files are backed up; unmanifested files are preserved. |
## Prior Art

View File

@@ -448,7 +448,7 @@ Sources consulted:
- https://www.codebuddy.ai/docs/cli/settings
- /websites/codebuddy_cn (Context7)
**EoS migration status (#2098):** Migrated onto the declarative adapter (dogfooded in `tests/declarative-reference-codebuddy.test.cjs`). The two remaining `isCodebuddy` branches in `bin/install.js` — a duplicate `commands/` slash-command output report, and a dead legacy agent-converter dispatch arm (unreachable since codebuddy is in `_DESCRIPTOR_AGENTS_RUNTIMES`) — were folded onto the already-generic `runtime.hostBehaviors.reportCommandsDir` (shared with Cursor) and removed outright; `isCodebuddy` no longer appears as a live read anywhere in `bin/install.js`, `src/runtime-artifact-conversion.cts`, `src/shell-command-projection.cts`, or `src/runtime-name-policy.cts`. Two upgrades land: (1) **extended hook events** — codebuddy's `extendedHookEvents` was previously `[]` (none wired); this PR wires all four — `SubagentStop`/`Stop`/`PreCompact`/`SubagentStart` — into `extendedHookEvents` (mirrors qwen/kimi), so an install now registers all four as hooks in `settings.json` alongside the pre-existing base session/tool events (`SessionStart`/`PreToolUse`/`PostToolUse`); cite https://www.codebuddy.ai/docs/cli/hooks. (2) **`dispatch.background`** — the descriptor already declared `true`, exceeding the `declarative-cli` profile baseline of `false`; the negotiation contract (`negotiateHostCapabilities`) now surfaces that value with no downgrade warning, documenting the legitimate deviation. Note: the CodeBuddy CLI has no background-dispatch frontmatter field on sub-agents (`agentMode`/`enabledAutoRun` are IDE-only per https://www.codebuddy.ai/docs/cli/sub-agents) — background dispatch remains a caller-side invocation parameter (`run_in_background: true`), not a field GSD's agent artifacts emit.
**EoS migration status (#2098):** Migrated onto the declarative adapter (dogfooded in `tests/declarative-reference-codebuddy.test.cjs`). The two remaining `isCodebuddy` branches in `bin/install.js` — a duplicate `commands/` slash-command output report, and a dead legacy agent-converter dispatch arm (unreachable since codebuddy is in `_DESCRIPTOR_AGENTS_RUNTIMES`) — were folded onto the generic `runtime.hostBehaviors.reportCommandsDir` and removed outright; `isCodebuddy` no longer appears as a live read anywhere in `bin/install.js`, `src/runtime-artifact-conversion.cts`, `src/shell-command-projection.cts`, or `src/runtime-name-policy.cts`. Cursor also used that report flag historically, but retired its parallel command surface in #2644 because Cursor skills already appear in the slash menu. Two upgrades land: (1) **extended hook events** — codebuddy's `extendedHookEvents` was previously `[]` (none wired); this PR wires all four — `SubagentStop`/`Stop`/`PreCompact`/`SubagentStart` — into `extendedHookEvents` (mirrors qwen/kimi), so an install now registers all four as hooks in `settings.json` alongside the pre-existing base session/tool events (`SessionStart`/`PreToolUse`/`PostToolUse`); cite https://www.codebuddy.ai/docs/cli/hooks. (2) **`dispatch.background`** — the descriptor already declared `true`, exceeding the `declarative-cli` profile baseline of `false`; the negotiation contract (`negotiateHostCapabilities`) now surfaces that value with no downgrade warning, documenting the legitimate deviation. Note: the CodeBuddy CLI has no background-dispatch frontmatter field on sub-agents (`agentMode`/`enabledAutoRun` are IDE-only per https://www.codebuddy.ai/docs/cli/sub-agents) — background dispatch remains a caller-side invocation parameter (`run_in_background: true`), not a field GSD's agent artifacts emit.
---
@@ -848,4 +848,3 @@ hosts) adds a belt-and-suspenders `maxDepth: 5` ceiling independent of whatever
engine enforces natively — there is no separate extension-side "subagent contribution"
registration API beyond the chat participant + Language Model Tools already registered; VS Code's
chat engine surfaces them to `#runSubagent` on its own.

View File

@@ -28,7 +28,7 @@ For the transform each converter applies, see [ADR-1593 §3 — converter transf
| **codex** | `skills/` | `gsd-` | flat | unconfirmed → conservative | `convertClaudeCommandToCodexSkill` | TOML config (`configFormat: toml`). Description truncated to 180 chars (`metadata.short-description`). `sandboxTier: codex-agent-sandbox`. |
| **opencode** | `skills/` | `gsd-` | flat | recursive (`**` glob) | `convertClaudeCommandToOpencodeSkill` | XDG config home. Shares the opencode-family converter entry point (`convertClaudeCommandToOpencodeFamilySkill`). Also ships `command` (singular) commands. |
| **kilo** | `skills/` | `gsd-` | flat | recursive (`**` glob) | `convertClaudeCommandToKiloSkill` | OpenCode fork; same `**` glob loader. `permissionWriter: kilo`. Also ships `command` commands. |
| **cursor** | `skills/` | `gsd-` | flat | recursive | `convertClaudeCommandToCursorSkill` | Also ships flat `commands/` via `convertClaudeCommandToCursorCommand`. `configFormat: none`. |
| **cursor** | `skills/` | `gsd-` | flat | recursive | `convertClaudeCommandToCursorSkill` | Skills are the single slash-menu and contextual invocation surface; legacy managed `commands/` copies are retired by migration 008 (#2644). `configFormat: none`. |
| **copilot** | `skills/` | `gsd-` | flat | unconfirmed → conservative | `convertClaudeCommandToCopilotSkill` | Markdown config. Scope-aware converter (global-home vs workspace-relative). |
| **antigravity** | `skills/` | `gsd-` | flat | non-recursive (one-level) | `convertClaudeCommandToAntigravitySkill` | `dot-home-nested` config home. Scope-aware converter. Loader confirmed: *"will not recursive scan"*. Flattened by #1614 — `agy` scans only `skills/<name>/SKILL.md`, so nesting hid sub-skills. |
| **windsurf** | — *(no skills kind)* | `gsd-` | — | workflows | `convertClaudeCommandToWindsurfWorkflow` | Emits `.windsurf/workflows/gsd-*.md` slash-command workflows. `configFormat: none`. `installSurface: profile-marker-only`. |