feat(#777): register Cursor-native hooks (.cursor/hooks.json) for session-start/post-tool parity (#831)
* feat(#777): register Cursor-native hooks (.cursor/hooks.json) for session-start/post-tool parity - Add gsd-cursor-session-start.js: injects STATE.md presence reminder (or new-project nudge) into Cursor sessions via the sessionStart hook event - Add gsd-cursor-post-tool.js: emits an additional_context nudge when write-class tool calls touch .planning/ files (postToolUse hook event) - Add 'cursor-hooks-json' installSurface to runtime-config-adapter-registry; writeCursorHooksJson/reconcileCursorHooksJson write the canonical { version: 1, hooks: { sessionStart, postToolUse } } JSON shape with idempotent reconciliation that preserves user-owned hook entries - Hook scripts are copied with /gsd:→gsd- rewrite so installed files contain no colon-form slash-command refs (bug-376 invariant) - 20 new tests in tests/cursor-hooks.test.cjs cover all reconciler paths, entry helpers, removal, runtime adapter surface, and hook script behavior - Update CONTEXT.md, ARCHITECTURE.md, installer-migrations.md, and 000-first-time-baseline.cts to include Cursor hooks.json surface Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#777): build hooks/dist on demand in bug-376 test for scoped/windows CI hooks/dist is gitignored and only produced by `npm run build:hooks`. The CI scoped (ubuntu-latest/node-22) and windows (windows-latest/node-24) test jobs do NOT run build:hooks before executing tests, so bug-376's prerequisite suite was failing with "hooks/dist not found" on both legs. Add ensureHooksDist() helper (mirrors bug-3357 pattern) that builds hooks/dist on demand in the before() hooks of prerequisite and Suite 3. Also add ensureHooksDist() call to Suite 3's before() so the snapshot step is also hermetic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,8 @@ export const BUNDLED_GSD_HOOK_FILES: ReadonlySet<string> = Object.freeze(new Set
|
||||
'hooks/gsd-check-update-worker.js',
|
||||
'hooks/gsd-check-update.js',
|
||||
'hooks/gsd-context-monitor.js',
|
||||
'hooks/gsd-cursor-post-tool.js',
|
||||
'hooks/gsd-cursor-session-start.js',
|
||||
'hooks/gsd-graphify-update.sh',
|
||||
'hooks/gsd-phase-boundary.sh',
|
||||
'hooks/gsd-prompt-guard.js',
|
||||
|
||||
@@ -23,7 +23,7 @@ const RUNTIME_SURFACES: Record<string, string[]> = {
|
||||
kilo: ['gsd-core', 'command', 'skills', 'agents'],
|
||||
copilot: ['gsd-core', 'skills', 'agents'],
|
||||
antigravity: ['gsd-core', 'skills', 'agents'],
|
||||
cursor: ['gsd-core', 'skills', 'agents'],
|
||||
cursor: ['gsd-core', 'skills', 'agents', 'hooks', 'hooks.json'],
|
||||
windsurf: ['gsd-core', 'skills', 'agents', 'rules'],
|
||||
augment: ['gsd-core', 'skills', 'agents'],
|
||||
trae: ['gsd-core', 'skills', 'agents', 'rules'],
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* 'codex-toml' → early-return after writing codex.toml.
|
||||
* 'copilot-instructions' → early-return after writing .github/copilot-instructions.md.
|
||||
* 'cline-rules' → early-return after writing .clinerules.
|
||||
* 'cursor-hooks-json' → early-return after writing .cursor/hooks.json (issue #777).
|
||||
* 'profile-marker-only' → early-return after writing only the profile marker.
|
||||
* - `writesSharedSettings` is the finishInstall writeSettings gate:
|
||||
* false for codex / copilot / kilo / cursor / windsurf / trae / cline (legacy exclusion list).
|
||||
@@ -30,6 +31,7 @@ type ConfigInstallSurface =
|
||||
| 'codex-toml'
|
||||
| 'copilot-instructions'
|
||||
| 'cline-rules'
|
||||
| 'cursor-hooks-json'
|
||||
| 'profile-marker-only';
|
||||
|
||||
type FinishPermissionWriter = 'opencode' | 'kilo' | null;
|
||||
@@ -64,7 +66,7 @@ const REGISTRY: Record<string, Readonly<RegistryEntry>> = Object.freeze({
|
||||
codex: Object.freeze({ installSurface: 'codex-toml', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
copilot: Object.freeze({ installSurface: 'copilot-instructions', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
cline: Object.freeze({ installSurface: 'cline-rules', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
cursor: Object.freeze({ installSurface: 'profile-marker-only', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
cursor: Object.freeze({ installSurface: 'cursor-hooks-json', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
windsurf: Object.freeze({ installSurface: 'profile-marker-only', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
trae: Object.freeze({ installSurface: 'profile-marker-only', writesSharedSettings: false, finishPermissionWriter: null } as const),
|
||||
});
|
||||
@@ -82,6 +84,7 @@ const INSTALL_SURFACES: ReadonlyArray<ConfigInstallSurface> = Object.freeze([
|
||||
'codex-toml',
|
||||
'copilot-instructions',
|
||||
'cline-rules',
|
||||
'cursor-hooks-json',
|
||||
'profile-marker-only',
|
||||
]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user