@skillcap/gdh 0.18.2 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/INSTALL-BUNDLE.json +1 -1
  2. package/README.md +4 -4
  3. package/RELEASE-SPAN-UPDATE-CONTRACTS.json +91 -8
  4. package/node_modules/@gdh/adapters/dist/authoring-hook-render.d.ts +10 -0
  5. package/node_modules/@gdh/adapters/dist/authoring-hook-render.d.ts.map +1 -0
  6. package/node_modules/@gdh/adapters/dist/authoring-hook-render.js +150 -0
  7. package/node_modules/@gdh/adapters/dist/authoring-hook-render.js.map +1 -0
  8. package/node_modules/@gdh/adapters/dist/claude-settings-patch.d.ts +2 -0
  9. package/node_modules/@gdh/adapters/dist/claude-settings-patch.d.ts.map +1 -1
  10. package/node_modules/@gdh/adapters/dist/claude-settings-patch.js +71 -6
  11. package/node_modules/@gdh/adapters/dist/claude-settings-patch.js.map +1 -1
  12. package/node_modules/@gdh/adapters/dist/index.d.ts +18 -30
  13. package/node_modules/@gdh/adapters/dist/index.d.ts.map +1 -1
  14. package/node_modules/@gdh/adapters/dist/index.js +364 -1128
  15. package/node_modules/@gdh/adapters/dist/index.js.map +1 -1
  16. package/node_modules/@gdh/adapters/dist/skill-rendering.d.ts +45 -0
  17. package/node_modules/@gdh/adapters/dist/skill-rendering.d.ts.map +1 -0
  18. package/node_modules/@gdh/adapters/dist/skill-rendering.js +419 -0
  19. package/node_modules/@gdh/adapters/dist/skill-rendering.js.map +1 -0
  20. package/node_modules/@gdh/adapters/package.json +8 -8
  21. package/node_modules/@gdh/authoring/dist/diagnostics-summary.d.ts +8 -0
  22. package/node_modules/@gdh/authoring/dist/diagnostics-summary.d.ts.map +1 -0
  23. package/node_modules/@gdh/authoring/dist/diagnostics-summary.js +22 -0
  24. package/node_modules/@gdh/authoring/dist/diagnostics-summary.js.map +1 -0
  25. package/node_modules/@gdh/authoring/dist/index.d.ts +4 -1
  26. package/node_modules/@gdh/authoring/dist/index.d.ts.map +1 -1
  27. package/node_modules/@gdh/authoring/dist/index.js +17 -2
  28. package/node_modules/@gdh/authoring/dist/index.js.map +1 -1
  29. package/node_modules/@gdh/authoring/dist/lsp.d.ts +5 -1
  30. package/node_modules/@gdh/authoring/dist/lsp.d.ts.map +1 -1
  31. package/node_modules/@gdh/authoring/dist/lsp.js +95 -1
  32. package/node_modules/@gdh/authoring/dist/lsp.js.map +1 -1
  33. package/node_modules/@gdh/authoring/dist/project.d.ts.map +1 -1
  34. package/node_modules/@gdh/authoring/dist/project.js +1 -0
  35. package/node_modules/@gdh/authoring/dist/project.js.map +1 -1
  36. package/node_modules/@gdh/authoring/dist/scene-resource.d.ts +2 -0
  37. package/node_modules/@gdh/authoring/dist/scene-resource.d.ts.map +1 -1
  38. package/node_modules/@gdh/authoring/dist/scene-resource.js +15 -1
  39. package/node_modules/@gdh/authoring/dist/scene-resource.js.map +1 -1
  40. package/node_modules/@gdh/authoring/package.json +2 -2
  41. package/node_modules/@gdh/cli/dist/index.d.ts.map +1 -1
  42. package/node_modules/@gdh/cli/dist/index.js +206 -280
  43. package/node_modules/@gdh/cli/dist/index.js.map +1 -1
  44. package/node_modules/@gdh/cli/package.json +10 -10
  45. package/node_modules/@gdh/core/dist/index.d.ts +78 -83
  46. package/node_modules/@gdh/core/dist/index.d.ts.map +1 -1
  47. package/node_modules/@gdh/core/dist/index.js +4 -4
  48. package/node_modules/@gdh/core/dist/index.js.map +1 -1
  49. package/node_modules/@gdh/core/package.json +1 -1
  50. package/node_modules/@gdh/docs/dist/agent-contract.js +1 -1
  51. package/node_modules/@gdh/docs/dist/agent-contract.js.map +1 -1
  52. package/node_modules/@gdh/docs/dist/guidance.d.ts.map +1 -1
  53. package/node_modules/@gdh/docs/dist/guidance.js +84 -15
  54. package/node_modules/@gdh/docs/dist/guidance.js.map +1 -1
  55. package/node_modules/@gdh/docs/dist/rules.js +3 -3
  56. package/node_modules/@gdh/docs/dist/rules.js.map +1 -1
  57. package/node_modules/@gdh/docs/package.json +2 -2
  58. package/node_modules/@gdh/mcp/package.json +8 -8
  59. package/node_modules/@gdh/observability/dist/guidance-audit.d.ts.map +1 -1
  60. package/node_modules/@gdh/observability/dist/guidance-audit.js +1 -50
  61. package/node_modules/@gdh/observability/dist/guidance-audit.js.map +1 -1
  62. package/node_modules/@gdh/observability/package.json +2 -2
  63. package/node_modules/@gdh/runtime/dist/bridge-broker-contract.d.ts +23 -0
  64. package/node_modules/@gdh/runtime/dist/bridge-broker-contract.d.ts.map +1 -0
  65. package/node_modules/@gdh/runtime/dist/bridge-broker-contract.js +120 -0
  66. package/node_modules/@gdh/runtime/dist/bridge-broker-contract.js.map +1 -0
  67. package/node_modules/@gdh/runtime/dist/index.d.ts +2 -1
  68. package/node_modules/@gdh/runtime/dist/index.d.ts.map +1 -1
  69. package/node_modules/@gdh/runtime/dist/index.js +28 -62
  70. package/node_modules/@gdh/runtime/dist/index.js.map +1 -1
  71. package/node_modules/@gdh/runtime/package.json +2 -2
  72. package/node_modules/@gdh/scan/package.json +3 -3
  73. package/node_modules/@gdh/verify/dist/index.d.ts +0 -1
  74. package/node_modules/@gdh/verify/dist/index.d.ts.map +1 -1
  75. package/node_modules/@gdh/verify/dist/index.js +1 -2
  76. package/node_modules/@gdh/verify/dist/index.js.map +1 -1
  77. package/node_modules/@gdh/verify/package.json +7 -7
  78. package/package.json +11 -11
@@ -10,11 +10,13 @@ import { createDefaultGuidanceUnits, createDefaultRulesDocument, getGuidanceStat
10
10
  import { inspectGuidanceAudit } from "@gdh/observability";
11
11
  import { inspectRuntimeBridgeSurface, inspectRuntimeKnowledgeSurface } from "@gdh/runtime";
12
12
  import { readInventoryCacheOrScan } from "@gdh/scan";
13
- import { evaluateDonePolicy, recommendValidationForChange } from "@gdh/verify";
14
- import { CLAUDE_SETTINGS_RELATIVE_PATH, patchClaudeSettingsForGdhSessionStart, patchClaudeSettingsForGdhStatusline, } from "./claude-settings-patch.js";
13
+ import { CLAUDE_SETTINGS_RELATIVE_PATH, patchClaudeSettingsForGdhAuthoringHooks, patchClaudeSettingsForGdhSessionStart, patchClaudeSettingsForGdhStatusline, } from "./claude-settings-patch.js";
14
+ import { CLAUDE_AUTHORING_HOOK_RELATIVE_PATH, CODEX_AUTHORING_HOOK_COMMAND, CODEX_AUTHORING_HOOK_RELATIVE_PATH, renderGdhAuthoringHook, } from "./authoring-hook-render.js";
15
15
  import { CLAUDE_STATUSLINE_RELATIVE_PATH, renderClaudeUpdateStatusline, } from "./claude-statusline-render.js";
16
16
  import { CLAUDE_CHECK_UPDATE_HOOK_RELATIVE_PATH, CLAUDE_CHECK_UPDATE_WORKER_RELATIVE_PATH, renderClaudeCheckUpdateHook, } from "./claude-update-hook-render.js";
17
17
  import { renderClaudeCheckUpdateWorker } from "./claude-update-worker-render.js";
18
+ import { GDH_MANAGED_AGENT_SKILL_MARKER, renderClaudeCheckSkill, renderClaudeMigrateSkill, renderClaudeOnboardSkill, renderClaudePrepareSkill, renderClaudeScanSkill, renderClaudeStatusSkill, renderClaudeUpdateSkill, renderCodexCheckSkill, renderCodexMigrateSkill, renderCodexOnboardSkill, renderCodexPrepareSkill, renderCodexScanSkill, renderCodexStatusSkill, renderCodexUpdateSkill, renderCursorCheckSkill, renderCursorMigrateSkill, renderCursorOnboardSkill, renderCursorPrepareSkill, renderCursorScanSkill, renderCursorStatusSkill, renderCursorUpdateSkill, } from "./skill-rendering.js";
19
+ export { GDH_MANAGED_AGENT_SKILL_MARKER, GDH_SKILL_DEFINITIONS, GDH_SKILL_IDS, renderGdhSkill, renderManagedSkillMarker, renderClaudeCheckSkill, renderClaudeMigrateSkill, renderClaudeOnboardSkill, renderClaudePrepareSkill, renderClaudeScanSkill, renderClaudeStatusSkill, renderClaudeUpdateSkill, renderCodexCheckSkill, renderCodexMigrateSkill, renderCodexOnboardSkill, renderCodexPrepareSkill, renderCodexScanSkill, renderCodexStatusSkill, renderCodexUpdateSkill, renderCursorCheckSkill, renderCursorMigrateSkill, renderCursorOnboardSkill, renderCursorPrepareSkill, renderCursorScanSkill, renderCursorStatusSkill, renderCursorUpdateSkill, } from "./skill-rendering.js";
18
20
  export const adaptersPackage = definePackageBoundary({
19
21
  name: "@gdh/adapters",
20
22
  layer: "integration",
@@ -26,7 +28,6 @@ export const adaptersPackage = definePackageBoundary({
26
28
  "@gdh/observability",
27
29
  "@gdh/runtime",
28
30
  "@gdh/scan",
29
- "@gdh/verify",
30
31
  ],
31
32
  });
32
33
  export const SUPPORTED_AGENTS = [
@@ -35,47 +36,60 @@ export const SUPPORTED_AGENTS = [
35
36
  "cursor",
36
37
  ];
37
38
  export const CLAUDE_SHIM_RELATIVE_PATH = "CLAUDE.md";
38
- export const CLAUDE_ONBOARD_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/onboard.md";
39
+ export const CLAUDE_ONBOARD_SKILL_RELATIVE_PATH = ".claude/skills/gdh-onboard/SKILL.md";
39
40
  export const PROJECT_MCP_RELATIVE_PATH = ".mcp.json";
40
41
  export const CURSOR_MCP_RELATIVE_PATH = ".cursor/mcp.json";
41
42
  export const CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/gdh-agent.mdc";
42
43
  export const CURSOR_ONBOARD_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-onboard/SKILL.md";
43
44
  export const CODEX_ONBOARD_SKILL_RELATIVE_PATH = ".agents/skills/gdh-onboard/SKILL.md";
44
- export const CLAUDE_STATUS_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/status.md";
45
- export const CLAUDE_MIGRATE_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/migrate.md";
46
- export const CLAUDE_CHECK_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/check.md";
47
- export const CLAUDE_PREPARE_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/prepare.md";
48
- export const CLAUDE_VERIFY_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/verify.md";
45
+ export const CLAUDE_STATUS_SKILL_RELATIVE_PATH = ".claude/skills/gdh-status/SKILL.md";
46
+ export const CLAUDE_MIGRATE_SKILL_RELATIVE_PATH = ".claude/skills/gdh-migrate/SKILL.md";
47
+ export const CLAUDE_CHECK_SKILL_RELATIVE_PATH = ".claude/skills/gdh-check/SKILL.md";
48
+ export const CLAUDE_PREPARE_SKILL_RELATIVE_PATH = ".claude/skills/gdh-prepare/SKILL.md";
49
49
  export const CODEX_STATUS_SKILL_RELATIVE_PATH = ".agents/skills/gdh-status/SKILL.md";
50
50
  export const CODEX_MIGRATE_SKILL_RELATIVE_PATH = ".agents/skills/gdh-migrate/SKILL.md";
51
51
  export const CODEX_CHECK_SKILL_RELATIVE_PATH = ".agents/skills/gdh-check/SKILL.md";
52
52
  export const CODEX_PREPARE_SKILL_RELATIVE_PATH = ".agents/skills/gdh-prepare/SKILL.md";
53
- export const CODEX_VERIFY_SKILL_RELATIVE_PATH = ".agents/skills/gdh-verify/SKILL.md";
54
53
  export const CURSOR_STATUS_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-status/SKILL.md";
55
54
  export const CURSOR_MIGRATE_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-migrate/SKILL.md";
56
55
  export const CURSOR_CHECK_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-check/SKILL.md";
57
56
  export const CURSOR_PREPARE_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-prepare/SKILL.md";
58
- export const CURSOR_VERIFY_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-verify/SKILL.md";
59
57
  // Phase 13 SELF-01: /gdh-update skill surface path constants. The rendered
60
58
  // bodies shell out to `npx -y @skillcap/gdh@latest self-update` (LITERAL
61
59
  // @latest, not the pinned version — D-10) so the NEW CLI performs the update,
62
60
  // not the (potentially pre-Phase-12) OLD pinned one. These constants are
63
61
  // INTENTIONALLY excluded from VERIFY_DRIFT_SCANNED_FILES (D-13) because the
64
62
  // rendered bodies are version-agnostic by design.
65
- export const CLAUDE_UPDATE_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/update.md";
63
+ export const CLAUDE_UPDATE_SKILL_RELATIVE_PATH = ".claude/skills/gdh-update/SKILL.md";
66
64
  export const CODEX_UPDATE_SKILL_RELATIVE_PATH = ".agents/skills/gdh-update/SKILL.md";
67
65
  export const CURSOR_UPDATE_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-update/SKILL.md";
68
- export const CLAUDE_SCAN_COMMAND_RELATIVE_PATH = ".claude/commands/gdh/scan.md";
66
+ export const CLAUDE_SCAN_SKILL_RELATIVE_PATH = ".claude/skills/gdh-scan/SKILL.md";
69
67
  export const CODEX_SCAN_SKILL_RELATIVE_PATH = ".agents/skills/gdh-scan/SKILL.md";
68
+ export const CLAUDE_ONBOARD_COMMAND_RELATIVE_PATH = CLAUDE_ONBOARD_SKILL_RELATIVE_PATH;
69
+ export const CLAUDE_STATUS_COMMAND_RELATIVE_PATH = CLAUDE_STATUS_SKILL_RELATIVE_PATH;
70
+ export const CLAUDE_MIGRATE_COMMAND_RELATIVE_PATH = CLAUDE_MIGRATE_SKILL_RELATIVE_PATH;
71
+ export const CLAUDE_CHECK_COMMAND_RELATIVE_PATH = CLAUDE_CHECK_SKILL_RELATIVE_PATH;
72
+ export const CLAUDE_PREPARE_COMMAND_RELATIVE_PATH = CLAUDE_PREPARE_SKILL_RELATIVE_PATH;
73
+ export const CLAUDE_UPDATE_COMMAND_RELATIVE_PATH = CLAUDE_UPDATE_SKILL_RELATIVE_PATH;
74
+ export const CLAUDE_SCAN_COMMAND_RELATIVE_PATH = CLAUDE_SCAN_SKILL_RELATIVE_PATH;
75
+ const LEGACY_CLAUDE_SKILL_COMMAND_RELATIVE_PATHS = [
76
+ [".claude/commands/gdh/onboard.md", "gdh-onboard"],
77
+ [".claude/commands/gdh/status.md", "gdh-status"],
78
+ [".claude/commands/gdh/migrate.md", "gdh-migrate"],
79
+ [".claude/commands/gdh/update.md", "gdh-update"],
80
+ [".claude/commands/gdh/check.md", "gdh-check"],
81
+ [".claude/commands/gdh/prepare.md", "gdh-prepare"],
82
+ [".claude/commands/gdh/scan.md", "gdh-scan"],
83
+ ];
70
84
  const LEGACY_CODEX_SKILL_RELATIVE_PATHS = [
71
- [".codex/skills/gdh-onboard/SKILL.md", renderCodexOnboardSkill, "gdh-onboard"],
72
- [".codex/skills/gdh-status/SKILL.md", renderCodexStatusSkill, "gdh-status"],
73
- [".codex/skills/gdh-migrate/SKILL.md", renderCodexMigrateSkill, "gdh-migrate"],
74
- [".codex/skills/gdh-update/SKILL.md", renderCodexUpdateSkill, "gdh-update"],
75
- [".codex/skills/gdh-check/SKILL.md", renderCodexCheckSkill, "gdh-check"],
76
- [".codex/skills/gdh-prepare/SKILL.md", renderCodexPrepareSkill, "gdh-prepare"],
77
- [".codex/skills/gdh-verify/SKILL.md", renderCodexVerifySkill, "gdh-verify"],
78
- [".codex/skills/gdh-scan/SKILL.md", renderCodexScanSkill, "gdh-scan"],
85
+ [".codex/skills/gdh-onboard/SKILL.md", "gdh-onboard"],
86
+ [".codex/skills/gdh-status/SKILL.md", "gdh-status"],
87
+ [".codex/skills/gdh-migrate/SKILL.md", "gdh-migrate"],
88
+ [".codex/skills/gdh-update/SKILL.md", "gdh-update"],
89
+ [".codex/skills/gdh-check/SKILL.md", "gdh-check"],
90
+ [".codex/skills/gdh-prepare/SKILL.md", "gdh-prepare"],
91
+ [".codex/skills/gdh-verify/SKILL.md", "gdh-verify"],
92
+ [".codex/skills/gdh-scan/SKILL.md", "gdh-scan"],
79
93
  ];
80
94
  export const CURSOR_SCAN_SKILL_RELATIVE_PATH = ".cursor/skills/gdh-scan/SKILL.md";
81
95
  export const LOCAL_PATH_HINTS_RELATIVE_PATH = ".gdh-state/local-paths.json";
@@ -83,8 +97,7 @@ export const CODEX_PROJECT_CONFIG_RELATIVE_PATH = ".codex/config.toml";
83
97
  export const GDH_MCP_SERVER_NAME = "gdh";
84
98
  // Phase 17 UX-01: single source of truth for the `/gdh-status` preview-header
85
99
  // literal. The character between "dry-run)" and "not" is em-dash U+2014 (NOT
86
- // two hyphens). Centralizing here prevents silent drift across the 3
87
- // `/gdh-status` renderer bodies (Pitfall #5 three-adapter parity).
100
+ // two hyphens). Centralizing here prevents silent drift across shipped skills.
88
101
  const PREVIEW_HEADER_LITERAL = "Preview (dry-run) — not applied";
89
102
  const execFile = promisify(execFileCallback);
90
103
  export async function getSupportedAgentAdaptersStatus(targetPath, options = {}) {
@@ -263,7 +276,6 @@ export async function createGsdSnapshot(targetPath, options = {}) {
263
276
  const context = await buildAuthoringContext(targetPath);
264
277
  const effectiveRepoState = deriveRepoState(context);
265
278
  const files = normalizeChangedFiles(options.files ?? []);
266
- const performed = [...new Set(options.performed ?? [])];
267
279
  const guidance = await getGuidanceStatus(targetPath);
268
280
  const [audit, guidanceResolve] = await Promise.all([
269
281
  inspectGuidanceAudit(targetPath),
@@ -282,41 +294,6 @@ export async function createGsdSnapshot(targetPath, options = {}) {
282
294
  guidance,
283
295
  audit,
284
296
  };
285
- const validationRecommendation = files.length === 0
286
- ? {
287
- state: "unavailable",
288
- summary: "Validation expectations are unavailable until the snapshot is given changed files.",
289
- value: null,
290
- }
291
- : {
292
- state: "available",
293
- summary: "Validation expectations were projected from the current GDH verify recommendation surface.",
294
- value: await recommendValidationForChange({
295
- targetPath,
296
- inventory: context.inventory,
297
- status: context.status,
298
- projectConfig: context.projectConfig,
299
- files,
300
- }),
301
- };
302
- const donePolicy = validationRecommendation.value === null
303
- ? {
304
- state: "unavailable",
305
- summary: "Done-policy evaluation is unavailable until changed files are supplied for the snapshot.",
306
- value: null,
307
- }
308
- : {
309
- state: "available",
310
- summary: "Done-policy evaluation was projected from the current GDH verify done surface.",
311
- value: await evaluateDonePolicy({
312
- targetPath,
313
- inventory: context.inventory,
314
- status: context.status,
315
- projectConfig: context.projectConfig,
316
- files,
317
- performed,
318
- }),
319
- };
320
297
  return {
321
298
  targetPath,
322
299
  adapter: {
@@ -326,12 +303,9 @@ export async function createGsdSnapshot(targetPath, options = {}) {
326
303
  summary: "The GSD bridge is an optional read-mostly adapter over stable GDH outputs and is not required for core GDH behavior.",
327
304
  },
328
305
  files,
329
- performed,
330
306
  status: context.status,
331
307
  guidanceStatus,
332
308
  guidanceResolve,
333
- validationRecommendation,
334
- donePolicy,
335
309
  };
336
310
  }
337
311
  export function renderCursorRule() {
@@ -351,1016 +325,25 @@ export function renderCursorRule() {
351
325
  ].join("\n");
352
326
  }
353
327
  export function renderClaudeOnboardCommand(pinnedVersion) {
354
- return [
355
- "---",
356
- "name: gdh:onboard",
357
- "description: Finish GDH setup handoff and report project readiness",
358
- "allowed-tools:",
359
- " - Read",
360
- " - Grep",
361
- " - Glob",
362
- " - Bash",
363
- " - AskUserQuestion",
364
- "---",
365
- "<objective>",
366
- `Finish the first-time GDH handoff after \`npx -y @skillcap/gdh@${pinnedVersion} setup\` and turn the generated GDH surface into a trustworthy starting point for real work.`,
367
- "</objective>",
368
- "",
369
- "<process>",
370
- "Follow this order:",
371
- "",
372
- `1. Confirm the selected target and current GDH state with \`npx -y @skillcap/gdh@${pinnedVersion} status\`.`,
373
- "2. Read `.gdh/project.yaml`, `docs/agent/README.md`, and `docs/agent/00-gdh-onboarding.md` before asking for facts GDH already knows.",
374
- `3. Check immediate readiness with \`npx -y @skillcap/gdh@${pinnedVersion} guidance status\` and \`npx -y @skillcap/gdh@${pinnedVersion} target prepare --dry-run\`.`,
375
- `4. If authoring is available, run \`npx -y @skillcap/gdh@${pinnedVersion} authoring check\`; if LSP matters, run \`npx -y @skillcap/gdh@${pinnedVersion} lsp status\`.`,
376
- `5. Inspect \`npx -y @skillcap/gdh@${pinnedVersion} run-config list\` and \`npx -y @skillcap/gdh@${pinnedVersion} verification-scenario list\` and call out anything draft, missing, or blocked.`,
377
- "6. If GDH reports `godot_editor_not_configured`, explain that the Godot binary path is machine-local and offer to record `.gdh-state/local-paths.json` `godotEditorBinPath` once the human provides the local path.",
378
- "7. Ask the human only for narrow unresolved environment or target facts.",
379
- "8. End with a concise readiness summary and the exact next development step.",
380
- "</process>",
381
- "",
382
- "<rules>",
383
- "- Do not start editing code during `/gdh-onboard` unless the human explicitly asks.",
384
- "- Prefer GDH structured surfaces over repo guesswork.",
385
- "- Keep the output short, operational, and specific.",
386
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
387
- "</rules>",
388
- "",
389
- ].join("\n");
328
+ return renderClaudeOnboardSkill(pinnedVersion);
390
329
  }
391
- export function renderCodexOnboardSkill(pinnedVersion) {
392
- return [
393
- "---",
394
- 'name: "gdh-onboard"',
395
- 'description: "Finish GDH setup handoff and report project readiness"',
396
- "metadata:",
397
- ' short-description: "Finish GDH setup handoff and report project readiness"',
398
- "---",
399
- "",
400
- "<codex_skill_adapter>",
401
- "## Invocation",
402
- "- This skill is invoked when the user says `/gdh-onboard` or mentions `$gdh-onboard`.",
403
- "- Treat any extra user text as additional onboarding context.",
404
- "",
405
- "## User questions",
406
- "- Ask only narrow follow-up questions when GDH cannot infer the missing setup fact safely.",
407
- "- If structured user-input tooling is unavailable, ask concise plain-text questions instead.",
408
- "</codex_skill_adapter>",
409
- "",
410
- "<objective>",
411
- `Finish the first-time GDH handoff after \`npx -y @skillcap/gdh@${pinnedVersion} setup\` and turn the generated GDH surface into a trustworthy starting point for real work.`,
412
- "</objective>",
413
- "",
414
- "<process>",
415
- "Follow this order:",
416
- "",
417
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} status\``,
418
- "- inspect `.gdh/project.yaml`, `docs/agent/README.md`, and `docs/agent/00-gdh-onboarding.md`",
419
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} guidance status\``,
420
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare --dry-run\``,
421
- `- if authoring is available, run \`npx -y @skillcap/gdh@${pinnedVersion} authoring check\``,
422
- `- if LSP matters, run \`npx -y @skillcap/gdh@${pinnedVersion} lsp status\``,
423
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} run-config list\``,
424
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} verification-scenario list\``,
425
- "- if GDH reports `godot_editor_not_configured`, explain that the Godot binary path is machine-local and offer to record `.gdh-state/local-paths.json` `godotEditorBinPath` once the user provides it",
426
- "- ask only for narrow unresolved environment or target facts",
427
- "- finish with a concise readiness summary and the exact next development step",
428
- "</process>",
429
- "",
430
- "<rules>",
431
- "- Do not start editing code during `/gdh-onboard` unless the human explicitly asks.",
432
- "- Prefer GDH structured surfaces over repo guesswork.",
433
- "- Keep output short, operational, and specific.",
434
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
435
- "</rules>",
436
- "",
437
- ].join("\n");
438
- }
439
- export function renderCursorOnboardSkill(pinnedVersion) {
440
- return [
441
- "---",
442
- "name: gdh-onboard",
443
- 'description: "Finish GDH setup handoff and report project readiness"',
444
- "---",
445
- "",
446
- "<cursor_skill_adapter>",
447
- "## Invocation",
448
- "- This skill is invoked when the user says `/gdh-onboard` or mentions `gdh-onboard`.",
449
- "- Treat any extra user text as additional onboarding context.",
450
- "",
451
- "## User questions",
452
- "- Ask only narrow follow-up questions when GDH cannot infer the missing setup fact safely.",
453
- "- Keep questions conversational and concise.",
454
- "</cursor_skill_adapter>",
455
- "",
456
- "<objective>",
457
- `Finish the first-time GDH handoff after \`npx -y @skillcap/gdh@${pinnedVersion} setup\` and turn the generated GDH surface into a trustworthy starting point for real work.`,
458
- "</objective>",
459
- "",
460
- "<process>",
461
- "Follow this order:",
462
- "",
463
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} status\``,
464
- "- inspect `.gdh/project.yaml`, `docs/agent/README.md`, and `docs/agent/00-gdh-onboarding.md`",
465
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} guidance status\``,
466
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare --dry-run\``,
467
- `- if authoring is available, run \`npx -y @skillcap/gdh@${pinnedVersion} authoring check\``,
468
- `- if LSP matters, run \`npx -y @skillcap/gdh@${pinnedVersion} lsp status\``,
469
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} run-config list\``,
470
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} verification-scenario list\``,
471
- "- if GDH reports `godot_editor_not_configured`, explain that the Godot binary path is machine-local and offer to record `.gdh-state/local-paths.json` `godotEditorBinPath` once the user provides it",
472
- "- ask only for narrow unresolved environment or target facts",
473
- "- finish with a concise readiness summary and the exact next development step",
474
- "</process>",
475
- "",
476
- "<rules>",
477
- "- Do not start editing code during `/gdh-onboard` unless the human explicitly asks.",
478
- "- Prefer GDH structured surfaces over repo guesswork.",
479
- "- Keep output short, operational, and specific.",
480
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
481
- "</rules>",
482
- "",
483
- ].join("\n");
484
- }
485
- // --- gdh-status skill renders ---
486
330
  export function renderClaudeStatusCommand(pinnedVersion) {
487
- return [
488
- "---",
489
- "name: gdh:status",
490
- "description: Check GDH project readiness, surface migration needs, and suggest next step",
491
- "allowed-tools:",
492
- " - Read",
493
- " - Grep",
494
- " - Glob",
495
- " - Bash",
496
- "---",
497
- "<objective>",
498
- "Check GDH project readiness, surface migration needs, and suggest the most productive next step.",
499
- "</objective>",
500
- "",
501
- "<process>",
502
- "Follow this order:",
503
- "",
504
- `1. Run \`npx -y @skillcap/gdh@${pinnedVersion} status\` and explain each readiness field.`,
505
- "2. Distinguish `blockingReasons` (needs /gdh-update or manual intervention) from `coupledReasons` (fixable via /gdh-migrate).",
506
- `3. Check if migration is needed with \`npx -y @skillcap/gdh@${pinnedVersion} migrate\`.`,
507
- `4. ${PREVIEW_HEADER_LITERAL} — migrate output at this step describes planned actions ("would delete …") not applied ones ("deleted").`,
508
- "5. If status JSON `recoveryHints` array is non-empty, surface each entry's `{command, skillName}` pair.",
509
- "6. Surface any degraded or unavailable capabilities.",
510
- "7. Suggest the most productive next step based on current state.",
511
- "</process>",
512
- "",
513
- "<rules>",
514
- "- Do not start editing code.",
515
- "- Prefer structured GDH surfaces over repo guesswork.",
516
- "- Keep output short and operational.",
517
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
518
- "</rules>",
519
- "",
520
- ].join("\n");
331
+ return renderClaudeStatusSkill(pinnedVersion);
521
332
  }
522
- export function renderCodexStatusSkill(pinnedVersion) {
523
- return [
524
- "---",
525
- 'name: "gdh-status"',
526
- 'description: "Check GDH project readiness, surface migration needs, and suggest next step"',
527
- "metadata:",
528
- ' short-description: "Check GDH project readiness, surface migration needs, and suggest next step"',
529
- "---",
530
- "",
531
- "<codex_skill_adapter>",
532
- "## Invocation",
533
- "- This skill is invoked when the user says `/gdh-status` or mentions `$gdh-status`.",
534
- "- Treat any extra user text as additional status context.",
535
- "",
536
- "## User questions",
537
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
538
- "- If structured user-input tooling is unavailable, ask concise plain-text questions instead.",
539
- "</codex_skill_adapter>",
540
- "",
541
- "<objective>",
542
- "Check GDH project readiness, surface migration needs, and suggest the most productive next step.",
543
- "</objective>",
544
- "",
545
- "<process>",
546
- "Follow this order:",
547
- "",
548
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} status\` and explain each readiness field`,
549
- "- distinguish `blockingReasons` (needs /gdh-update or manual intervention) from `coupledReasons` (fixable via /gdh-migrate)",
550
- `- check if migration is needed with \`npx -y @skillcap/gdh@${pinnedVersion} migrate\``,
551
- `- ${PREVIEW_HEADER_LITERAL} — migrate output describes planned actions ("would delete …") not applied ones ("deleted")`,
552
- "- if status JSON `recoveryHints` array is non-empty, surface each entry's `{command, skillName}` pair",
553
- "- surface any degraded or unavailable capabilities",
554
- "- suggest the most productive next step based on current state",
555
- "</process>",
556
- "",
557
- "<rules>",
558
- "- Do not start editing code.",
559
- "- Prefer structured GDH surfaces over repo guesswork.",
560
- "- Keep output short and operational.",
561
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
562
- "</rules>",
563
- "",
564
- ].join("\n");
565
- }
566
- export function renderCursorStatusSkill(pinnedVersion) {
567
- return [
568
- "---",
569
- "name: gdh-status",
570
- 'description: "Check GDH project readiness, surface migration needs, and suggest next step"',
571
- "---",
572
- "",
573
- "<cursor_skill_adapter>",
574
- "## Invocation",
575
- "- This skill is invoked when the user says `/gdh-status` or mentions `gdh-status`.",
576
- "- Treat any extra user text as additional status context.",
577
- "",
578
- "## User questions",
579
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
580
- "- Keep questions conversational and concise.",
581
- "</cursor_skill_adapter>",
582
- "",
583
- "<objective>",
584
- "Check GDH project readiness, surface migration needs, and suggest the most productive next step.",
585
- "</objective>",
586
- "",
587
- "<process>",
588
- "Follow this order:",
589
- "",
590
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} status\` and explain each readiness field`,
591
- "- distinguish `blockingReasons` (needs /gdh-update or manual intervention) from `coupledReasons` (fixable via /gdh-migrate)",
592
- `- check if migration is needed with \`npx -y @skillcap/gdh@${pinnedVersion} migrate\``,
593
- `- ${PREVIEW_HEADER_LITERAL} — migrate output describes planned actions ("would delete …") not applied ones ("deleted")`,
594
- "- if status JSON `recoveryHints` array is non-empty, surface each entry's `{command, skillName}` pair",
595
- "- surface any degraded or unavailable capabilities",
596
- "- suggest the most productive next step based on current state",
597
- "</process>",
598
- "",
599
- "<rules>",
600
- "- Do not start editing code.",
601
- "- Prefer structured GDH surfaces over repo guesswork.",
602
- "- Keep output short and operational.",
603
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
604
- "</rules>",
605
- "",
606
- ].join("\n");
607
- }
608
- // --- gdh-scan skill renders ---
609
333
  export function renderClaudeScanCommand(pinnedVersion) {
610
- return [
611
- "---",
612
- "name: gdh:scan",
613
- "description: Refresh inventory cache and explain persistence effect",
614
- "allowed-tools:",
615
- " - Read",
616
- " - Grep",
617
- " - Glob",
618
- " - Bash",
619
- "---",
620
- "<objective>",
621
- "Refresh the inventory cache and explain the persistence effect of the scan.",
622
- "</objective>",
623
- "",
624
- "<process>",
625
- "Follow this order:",
626
- "",
627
- `1. Run \`npx -y @skillcap/gdh@${pinnedVersion} scan\` and parse the \`persisted\` field from the envelope.`,
628
- "2. Check the `mode` field: `create`, `unchanged`, `overwrite`, or `null`.",
629
- "3. Explain the persistence effect; if `null`, the target is not onboarded and no disk write occurred.",
630
- "</process>",
631
- "",
632
- "<rules>",
633
- "- Do not edit the persisted inventory directly.",
634
- "- Prefer the cached inventory for status reads; re-run scan only when freshness is in question.",
635
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
636
- "</rules>",
637
- "",
638
- ].join("\n");
639
- }
640
- export function renderCodexScanSkill(pinnedVersion) {
641
- return [
642
- "---",
643
- 'name: "gdh-scan"',
644
- 'description: "Refresh inventory cache and explain persistence effect"',
645
- "metadata:",
646
- ' short-description: "Refresh inventory cache and explain persistence effect"',
647
- "---",
648
- "",
649
- "<codex_skill_adapter>",
650
- "## Invocation",
651
- "- This skill is invoked when the user says `/gdh-scan` or mentions `$gdh-scan`.",
652
- "- Treat any extra user text as additional scan context.",
653
- "",
654
- "## User questions",
655
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
656
- "- If structured user-input tooling is unavailable, ask concise plain-text questions instead.",
657
- "</codex_skill_adapter>",
658
- "",
659
- "<objective>",
660
- "Refresh the inventory cache and explain the persistence effect of the scan.",
661
- "</objective>",
662
- "",
663
- "<process>",
664
- "Follow this order:",
665
- "",
666
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} scan\``,
667
- "- parse the `persisted` field from the envelope",
668
- "- check `mode`: `create`, `unchanged`, `overwrite`, or `null`",
669
- "- explain the persistence effect; if `null`, explain the target is not onboarded",
670
- "</process>",
671
- "",
672
- "<rules>",
673
- "- Do not edit the persisted inventory directly.",
674
- "- Prefer the cached inventory for status reads; re-run scan only when freshness is in question.",
675
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
676
- "</rules>",
677
- "",
678
- ].join("\n");
679
- }
680
- export function renderCursorScanSkill(pinnedVersion) {
681
- return [
682
- "---",
683
- "name: gdh-scan",
684
- 'description: "Refresh inventory cache and explain persistence effect"',
685
- "---",
686
- "",
687
- "<cursor_skill_adapter>",
688
- "## Invocation",
689
- "- This skill is invoked when the user says `/gdh-scan` or mentions `gdh-scan`.",
690
- "- Treat any extra user text as additional scan context.",
691
- "",
692
- "## User questions",
693
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
694
- "- Keep questions conversational and concise.",
695
- "</cursor_skill_adapter>",
696
- "",
697
- "<objective>",
698
- "Refresh the inventory cache and explain the persistence effect of the scan.",
699
- "</objective>",
700
- "",
701
- "<process>",
702
- "Follow this order:",
703
- "",
704
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} scan\``,
705
- "- parse the `persisted` field from the envelope",
706
- "- check `mode`: `create`, `unchanged`, `overwrite`, or `null`",
707
- "- explain the persistence effect; if `null`, explain the target is not onboarded",
708
- "</process>",
709
- "",
710
- "<rules>",
711
- "- Do not edit the persisted inventory directly.",
712
- "- Prefer the cached inventory for status reads; re-run scan only when freshness is in question.",
713
- "- For cache/persistence behavior of scan, status, onboard: see `docs/agent/persistence-semantics.md`.",
714
- "</rules>",
715
- "",
716
- ].join("\n");
334
+ return renderClaudeScanSkill(pinnedVersion);
717
335
  }
718
- // --- gdh-migrate skill renders ---
719
336
  export function renderClaudeMigrateCommand(pinnedVersion) {
720
- return [
721
- "---",
722
- "name: gdh:migrate",
723
- "description: Preview and apply GDH project migrations",
724
- "allowed-tools:",
725
- " - Read",
726
- " - Grep",
727
- " - Glob",
728
- " - Bash",
729
- " - AskUserQuestion",
730
- "---",
731
- "<objective>",
732
- "Preview and apply GDH project migrations safely with explicit user approval.",
733
- "</objective>",
734
- "",
735
- "<process>",
736
- "Follow this order:",
737
- "",
738
- `1. Run \`npx -y @skillcap/gdh@${pinnedVersion} migrate\` to preview pending migrations (this is a dry-run; the JSON \`mode\` field will be \`"preview"\`).`,
739
- "2. Inspect `compatibility.blockingReasons` vs `compatibility.coupledReasons` — if `blockingReasons` is non-empty, STOP: `migrate --apply` cannot fix them (recommend `/gdh-update` or manual intervention per each reason's recovery hint). If only `coupledReasons` is non-empty, proceed.",
740
- '3. Explain what each migration step will change and why (use "would" verb forms — "would delete", "would create", "would refresh").',
741
- `4. Offer to run \`npx -y @skillcap/gdh@${pinnedVersion} migrate --apply\` if the user approves — after apply, the JSON \`mode\` field becomes \`"applied"\` and verbs switch to past tense ("deleted", "created", "refreshed").`,
742
- "5. After apply, read `terminal.state` in the stdout JSON.",
743
- "6. If `terminal.state` is `healthy`, confirm no further migration action is required and stop.",
744
- "7. If `terminal.state` is `follow_up_required`, run the surfaced `terminal.commands`, then run the surfaced `terminal.validationCommands`, and confirm the follow-up results before stopping.",
745
- "8. If `terminal.state` is `manual_review_required`, run any surfaced `terminal.commands` first because they are auto-applicable, then run the surfaced `terminal.validationCommands`, explain the remaining `terminal.manualSteps`, and stop for review instead of improvising a repair.",
746
- "9. If `terminal.state` is `blocked`, surface `terminal.summary` plus the reasons and stop.",
747
- "</process>",
748
- "",
749
- "<rules>",
750
- "- Never apply migrations without explicit user approval.",
751
- "- Show the dry-run output first.",
752
- "- Keep explanations concise.",
753
- "</rules>",
754
- "",
755
- ].join("\n");
756
- }
757
- export function renderCodexMigrateSkill(pinnedVersion) {
758
- return [
759
- "---",
760
- 'name: "gdh-migrate"',
761
- 'description: "Preview and apply GDH project migrations"',
762
- "metadata:",
763
- ' short-description: "Preview and apply GDH project migrations"',
764
- "---",
765
- "",
766
- "<codex_skill_adapter>",
767
- "## Invocation",
768
- "- This skill is invoked when the user says `/gdh-migrate` or mentions `$gdh-migrate`.",
769
- "- Treat any extra user text as additional migration context.",
770
- "",
771
- "## User questions",
772
- "- Always ask before applying migrations.",
773
- "- If structured user-input tooling is unavailable, ask concise plain-text questions instead.",
774
- "</codex_skill_adapter>",
775
- "",
776
- "<objective>",
777
- "Preview and apply GDH project migrations safely with explicit user approval.",
778
- "</objective>",
779
- "",
780
- "<process>",
781
- "Follow this order:",
782
- "",
783
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} migrate\` to preview pending migrations (this is a dry-run; the JSON \`mode\` field will be \`"preview"\`)`,
784
- "- inspect `compatibility.blockingReasons` vs `compatibility.coupledReasons` — if `blockingReasons` is non-empty, STOP: `migrate --apply` cannot fix them (recommend `/gdh-update` or manual intervention per each reason's recovery hint); if only `coupledReasons` is non-empty, proceed",
785
- '- explain what each migration step will change and why (use "would" verb forms — "would delete", "would create", "would refresh")',
786
- `- offer to run \`npx -y @skillcap/gdh@${pinnedVersion} migrate --apply\` if the user approves — after apply, the JSON \`mode\` field becomes \`"applied"\` and verbs switch to past tense ("deleted", "created", "refreshed")`,
787
- "- after apply, read `terminal.state` in the stdout JSON",
788
- "- if `terminal.state` is `healthy`, confirm no further migration action is required and stop",
789
- "- if `terminal.state` is `follow_up_required`, run the surfaced `terminal.commands`, then run the surfaced `terminal.validationCommands`, and confirm the follow-up results before stopping",
790
- "- if `terminal.state` is `manual_review_required`, run any surfaced `terminal.commands` first because they are auto-applicable, then run the surfaced `terminal.validationCommands`, explain the remaining `terminal.manualSteps`, and stop for review instead of improvising a repair",
791
- "- if `terminal.state` is `blocked`, surface `terminal.summary` plus the reasons and stop",
792
- "</process>",
793
- "",
794
- "<rules>",
795
- "- Never apply migrations without explicit user approval.",
796
- "- Show the dry-run output first.",
797
- "- Keep explanations concise.",
798
- "</rules>",
799
- "",
800
- ].join("\n");
801
- }
802
- export function renderCursorMigrateSkill(pinnedVersion) {
803
- return [
804
- "---",
805
- "name: gdh-migrate",
806
- 'description: "Preview and apply GDH project migrations"',
807
- "---",
808
- "",
809
- "<cursor_skill_adapter>",
810
- "## Invocation",
811
- "- This skill is invoked when the user says `/gdh-migrate` or mentions `gdh-migrate`.",
812
- "- Treat any extra user text as additional migration context.",
813
- "",
814
- "## User questions",
815
- "- Always ask before applying migrations.",
816
- "- Keep questions conversational and concise.",
817
- "</cursor_skill_adapter>",
818
- "",
819
- "<objective>",
820
- "Preview and apply GDH project migrations safely with explicit user approval.",
821
- "</objective>",
822
- "",
823
- "<process>",
824
- "Follow this order:",
825
- "",
826
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} migrate\` to preview pending migrations (this is a dry-run; the JSON \`mode\` field will be \`"preview"\`)`,
827
- "- inspect `compatibility.blockingReasons` vs `compatibility.coupledReasons` — if `blockingReasons` is non-empty, STOP: `migrate --apply` cannot fix them (recommend `/gdh-update` or manual intervention per each reason's recovery hint); if only `coupledReasons` is non-empty, proceed",
828
- '- explain what each migration step will change and why (use "would" verb forms — "would delete", "would create", "would refresh")',
829
- `- offer to run \`npx -y @skillcap/gdh@${pinnedVersion} migrate --apply\` if the user approves — after apply, the JSON \`mode\` field becomes \`"applied"\` and verbs switch to past tense ("deleted", "created", "refreshed")`,
830
- "- after apply, read `terminal.state` in the stdout JSON",
831
- "- if `terminal.state` is `healthy`, confirm no further migration action is required and stop",
832
- "- if `terminal.state` is `follow_up_required`, run the surfaced `terminal.commands`, then run the surfaced `terminal.validationCommands`, and confirm the follow-up results before stopping",
833
- "- if `terminal.state` is `manual_review_required`, run any surfaced `terminal.commands` first because they are auto-applicable, then run the surfaced `terminal.validationCommands`, explain the remaining `terminal.manualSteps`, and stop for review instead of improvising a repair",
834
- "- if `terminal.state` is `blocked`, surface `terminal.summary` plus the reasons and stop",
835
- "</process>",
836
- "",
837
- "<rules>",
838
- "- Never apply migrations without explicit user approval.",
839
- "- Show the dry-run output first.",
840
- "- Keep explanations concise.",
841
- "</rules>",
842
- "",
843
- ].join("\n");
844
- }
845
- // --- gdh-update skill renders (Phase 13 SELF-01) ---
846
- //
847
- // D-10 invariant: every rendered body shells out to the LITERAL string
848
- // `@skillcap/gdh@latest` in every npx line (dry-run, apply, verify drift).
849
- // The `pinnedVersion` parameter is accepted for planSkillInstallAction
850
- // signature symmetry with every other renderer, but MUST NOT be interpolated
851
- // into the shellout — running the OLD pinned CLI (potentially pre-Phase-12
852
- // and lacking bumpAndRebakePin entirely) to perform its own update is the
853
- // failure mode Phase 13 exists to close. Check 44 in scripts/validate-docs.mjs
854
- // enforces both the @latest presence AND the @${pinnedVersion} absence.
855
- //
856
- // Phase 41 update-flow policy: preview first, then explicit approval before
857
- // apply, then terminal-driven follow-through. The renderers still avoid
858
- // adapter-specific branching logic here — they all consume the same
859
- // structured `preview` JSON from `gdh self-update --dry-run`, then after
860
- // apply they use `terminal.state` as the final truth for whether the update
861
- // is healthy, needs follow-up commands, needs manual review, or is blocked.
862
- //
863
- // D-12: accept an optional positional version forwarded verbatim to the CLI.
864
- // `/gdh-update` = latest; `/gdh-update 0.6.0` = pin that version.
865
- //
866
- // D-13: the three rendered skill files are EXCLUDED from VERIFY_DRIFT_SCANNED_FILES
867
- // because @latest is not a semver literal — the baked-version scanner would
868
- // permanently report no_baked_version. See rationale comments adjacent to the
869
- // VERIFY_DRIFT_SCANNED_FILES declaration in packages/cli/src/index.ts.
870
- export function renderClaudeUpdateCommand(_pinnedVersion) {
871
- return [
872
- "---",
873
- "name: gdh:update",
874
- "description: Update GDH to npm latest (bump pinned version + re-bake managed surfaces)",
875
- "allowed-tools:",
876
- " - Read",
877
- " - Bash",
878
- "---",
879
- "<objective>",
880
- "Update this project's GDH pinning to npm latest and re-bake every managed surface at the new pin.",
881
- "Treat any positional argument (e.g., `/gdh-update 0.6.0`) as an explicit version; otherwise default to npm latest.",
882
- "</objective>",
883
- "",
884
- "<process>",
885
- "Follow this order:",
886
- "",
887
- "1. Preview: run `npx -y @skillcap/gdh@latest self-update [version] --dry-run` (omit `[version]` to preview against npm latest).",
888
- "2. Read the `preview` field in the stdout JSON. If `preview.state` is `blocked`, surface the issues and stop. If `preview.state` is `noop`, explain the project is already at the target version and stop.",
889
- "3. When `preview.state` is `ready`, summarize the current version, target version, intervening releases, bounded release highlights, ordered steps, and which work is `mechanical`, `agent_reasoning`, or `manual_review`.",
890
- "4. Ask for explicit approval before apply.",
891
- "5. Apply: run `npx -y @skillcap/gdh@latest self-update [version]` (omit `[version]` to apply against npm latest; forward whatever positional the user passed to `/gdh-update`).",
892
- "6. If this chat or editor keeps a long-lived GDH MCP session alive, do the MCP cleanup yourself before trusting MCP follow-up output: stop stale `gdh mcp serve` / `@skillcap/gdh ... mcp serve` processes for this target when possible, then let the next MCP connection restart from the updated config. If the client owns reconnection and the process cannot be controlled from Bash, report that limitation after attempting cleanup.",
893
- "7. Verify baked pinning: run `npx -y @skillcap/gdh@latest verify drift` to confirm every managed skill/command surface matches the new pin. This does not validate runtime bridge or other lifecycle surfaces.",
894
- "8. Read `terminal.state` in the apply stdout JSON and treat it as the lifecycle/runtime truth.",
895
- "9. If `terminal.state` is `healthy`, confirm the update completed and stop.",
896
- "10. If `terminal.state` is `follow_up_required`, run the surfaced `terminal.commands`, then run the surfaced `terminal.validationCommands`, and confirm the follow-up results before stopping.",
897
- "11. If `terminal.state` is `manual_review_required`, run any surfaced `terminal.commands` first because they are auto-applicable, then run the surfaced `terminal.validationCommands`, explain the remaining `terminal.manualSteps`, and stop for review instead of inventing a repair.",
898
- "12. If `terminal.state` is `blocked`, surface `terminal.summary` plus the reasons and stop.",
899
- "</process>",
900
- "",
901
- "<rules>",
902
- "- Do ask for explicit approval after the structured preview and before apply.",
903
- "- Do not invent migration steps from prose docs; use the machine-readable `preview` payload.",
904
- "- Do treat `terminal.state` as the primary apply truth; the additive compatibility fields are not the main follow-through contract.",
905
- "- `terminal.commands` contains only GDH-classified auto-applicable follow-up; project-owned review stays in `terminal.manualSteps`.",
906
- "- Bake literal `@latest` in the shellout so the new CLI performs the update, not the old one.",
907
- "- If `self-update` returns `rolled_back` or `blocked`, surface the failure reason and stop (do not retry).",
908
- "- If `self-update` returns `skipped_dev_mode`, explain that dev-from-source mode bypasses pinning; no action needed.",
909
- "</rules>",
910
- "",
911
- ].join("\n");
337
+ return renderClaudeMigrateSkill(pinnedVersion);
912
338
  }
913
- export function renderCodexUpdateSkill(_pinnedVersion) {
914
- return [
915
- "---",
916
- 'name: "gdh-update"',
917
- 'description: "Update GDH to npm latest (bump pinned version + re-bake managed surfaces)"',
918
- "metadata:",
919
- ' short-description: "Update GDH to npm latest"',
920
- "---",
921
- "",
922
- "<codex_skill_adapter>",
923
- "## Invocation",
924
- "- This skill is invoked when the user says `/gdh-update` or mentions `$gdh-update`.",
925
- "- Treat any positional argument (e.g., `/gdh-update 0.6.0`) as an explicit version; otherwise default to npm latest.",
926
- "</codex_skill_adapter>",
927
- "",
928
- "<objective>",
929
- "Update this project's GDH pinning to npm latest and re-bake every managed surface at the new pin.",
930
- "</objective>",
931
- "",
932
- "<process>",
933
- "Follow this order:",
934
- "",
935
- "1. Preview: run `npx -y @skillcap/gdh@latest self-update [version] --dry-run` (omit `[version]` to preview against npm latest).",
936
- "2. Read the `preview` field in the stdout JSON. If `preview.state` is `blocked`, surface the issues and stop. If `preview.state` is `noop`, explain the project is already at the target version and stop.",
937
- "3. When `preview.state` is `ready`, summarize the current version, target version, intervening releases, bounded release highlights, ordered steps, and which work is `mechanical`, `agent_reasoning`, or `manual_review`.",
938
- "4. Ask for explicit approval before apply.",
939
- "5. Apply: run `npx -y @skillcap/gdh@latest self-update [version]` (omit `[version]` to apply against npm latest; forward whatever positional the user passed to `/gdh-update`).",
940
- "6. If this chat or editor keeps a long-lived GDH MCP session alive, do the MCP cleanup yourself before trusting MCP follow-up output: stop stale `gdh mcp serve` / `@skillcap/gdh ... mcp serve` processes for this target when possible, then let the next MCP connection restart from the updated config. If the client owns reconnection and the process cannot be controlled from Bash, report that limitation after attempting cleanup.",
941
- "7. Verify baked pinning: run `npx -y @skillcap/gdh@latest verify drift` to confirm every managed skill/command surface matches the new pin. This does not validate runtime bridge or other lifecycle surfaces.",
942
- "8. Read `terminal.state` in the apply stdout JSON and treat it as the lifecycle/runtime truth.",
943
- "9. If `terminal.state` is `healthy`, confirm the update completed and stop.",
944
- "10. If `terminal.state` is `follow_up_required`, run the surfaced `terminal.commands`, then run the surfaced `terminal.validationCommands`, and confirm the follow-up results before stopping.",
945
- "11. If `terminal.state` is `manual_review_required`, run any surfaced `terminal.commands` first because they are auto-applicable, then run the surfaced `terminal.validationCommands`, explain the remaining `terminal.manualSteps`, and stop for review instead of inventing a repair.",
946
- "12. If `terminal.state` is `blocked`, surface `terminal.summary` plus the reasons and stop.",
947
- "</process>",
948
- "",
949
- "<rules>",
950
- "- Do ask for explicit approval after the structured preview and before apply.",
951
- "- Do not invent migration steps from prose docs; use the machine-readable `preview` payload.",
952
- "- Do treat `terminal.state` as the primary apply truth; the additive compatibility fields are not the main follow-through contract.",
953
- "- `terminal.commands` contains only GDH-classified auto-applicable follow-up; project-owned review stays in `terminal.manualSteps`.",
954
- "- Bake literal `@latest` in the shellout so the new CLI performs the update, not the old one.",
955
- "- If `self-update` returns `rolled_back` or `blocked`, surface the failure reason and stop (do not retry).",
956
- "- If `self-update` returns `skipped_dev_mode`, explain that dev-from-source mode bypasses pinning; no action needed.",
957
- "</rules>",
958
- "",
959
- ].join("\n");
339
+ export function renderClaudeUpdateCommand(pinnedVersion) {
340
+ return renderClaudeUpdateSkill(pinnedVersion);
960
341
  }
961
- export function renderCursorUpdateSkill(_pinnedVersion) {
962
- return [
963
- "---",
964
- "name: gdh-update",
965
- 'description: "Update GDH to npm latest (bump pinned version + re-bake managed surfaces)"',
966
- "---",
967
- "",
968
- "<cursor_skill_adapter>",
969
- "## Invocation",
970
- "- This skill is invoked when the user says `/gdh-update` or mentions `gdh-update`.",
971
- "- Treat any positional argument (e.g., `gdh-update 0.6.0`) as an explicit version; otherwise default to npm latest.",
972
- "</cursor_skill_adapter>",
973
- "",
974
- "<objective>",
975
- "Update this project's GDH pinning to npm latest and re-bake every managed surface at the new pin.",
976
- "</objective>",
977
- "",
978
- "<process>",
979
- "Follow this order:",
980
- "",
981
- "1. Preview: run `npx -y @skillcap/gdh@latest self-update [version] --dry-run` (omit `[version]` to preview against npm latest).",
982
- "2. Read the `preview` field in the stdout JSON. If `preview.state` is `blocked`, surface the issues and stop. If `preview.state` is `noop`, explain the project is already at the target version and stop.",
983
- "3. When `preview.state` is `ready`, summarize the current version, target version, intervening releases, bounded release highlights, ordered steps, and which work is `mechanical`, `agent_reasoning`, or `manual_review`.",
984
- "4. Ask for explicit approval before apply.",
985
- "5. Apply: run `npx -y @skillcap/gdh@latest self-update [version]` (omit `[version]` to apply against npm latest; forward whatever positional the user passed to `/gdh-update`).",
986
- "6. If this chat or editor keeps a long-lived GDH MCP session alive, do the MCP cleanup yourself before trusting MCP follow-up output: stop stale `gdh mcp serve` / `@skillcap/gdh ... mcp serve` processes for this target when possible, then let the next MCP connection restart from the updated config. If the client owns reconnection and the process cannot be controlled from Bash, report that limitation after attempting cleanup.",
987
- "7. Verify baked pinning: run `npx -y @skillcap/gdh@latest verify drift` to confirm every managed skill/command surface matches the new pin. This does not validate runtime bridge or other lifecycle surfaces.",
988
- "8. Read `terminal.state` in the apply stdout JSON and treat it as the lifecycle/runtime truth.",
989
- "9. If `terminal.state` is `healthy`, confirm the update completed and stop.",
990
- "10. If `terminal.state` is `follow_up_required`, run the surfaced `terminal.commands`, then run the surfaced `terminal.validationCommands`, and confirm the follow-up results before stopping.",
991
- "11. If `terminal.state` is `manual_review_required`, run any surfaced `terminal.commands` first because they are auto-applicable, then run the surfaced `terminal.validationCommands`, explain the remaining `terminal.manualSteps`, and stop for review instead of inventing a repair.",
992
- "12. If `terminal.state` is `blocked`, surface `terminal.summary` plus the reasons and stop.",
993
- "</process>",
994
- "",
995
- "<rules>",
996
- "- Do ask for explicit approval after the structured preview and before apply.",
997
- "- Do not invent migration steps from prose docs; use the machine-readable `preview` payload.",
998
- "- Do treat `terminal.state` as the primary apply truth; the additive compatibility fields are not the main follow-through contract.",
999
- "- `terminal.commands` contains only GDH-classified auto-applicable follow-up; project-owned review stays in `terminal.manualSteps`.",
1000
- "- Bake literal `@latest` in the shellout so the new CLI performs the update, not the old one.",
1001
- "- If `self-update` returns `rolled_back` or `blocked`, surface the failure reason and stop (do not retry).",
1002
- "- If `self-update` returns `skipped_dev_mode`, explain that dev-from-source mode bypasses pinning; no action needed.",
1003
- "</rules>",
1004
- "",
1005
- ].join("\n");
1006
- }
1007
- // --- gdh-check skill renders ---
1008
342
  export function renderClaudeCheckCommand(pinnedVersion) {
1009
- return [
1010
- "---",
1011
- "name: gdh:check",
1012
- "description: Run GDH authoring checks and explain diagnostics",
1013
- "allowed-tools:",
1014
- " - Read",
1015
- " - Grep",
1016
- " - Glob",
1017
- " - Bash",
1018
- "---",
1019
- "<objective>",
1020
- "Run GDH authoring checks and explain diagnostics in human-readable terms.",
1021
- "</objective>",
1022
- "",
1023
- "<process>",
1024
- "Follow this order:",
1025
- "",
1026
- `1. Run \`npx -y @skillcap/gdh@${pinnedVersion} lsp status\` only for lifecycle visibility; do not treat lifecycle readiness as diagnostic evidence.`,
1027
- `2. Run \`npx -y @skillcap/gdh@${pinnedVersion} authoring check\` to collect validator evidence.`,
1028
- "3. Explain each diagnostic finding with severity, provenance, and validator family (`gdscript_lsp` for `.gd`, `godot_scene_resource` for `.tscn`/`.tres`).",
1029
- "4. Surface any import-state caveats or editor-side warnings.",
1030
- `5. If stale managed LSP state is suspected, use bounded GDH cleanup such as \`npx -y @skillcap/gdh@${pinnedVersion} lsp prune\` or \`npx -y @skillcap/gdh@${pinnedVersion} lsp stop\`; do not hand-manage Godot LSP processes.`,
1031
- "6. If issues found, suggest concrete remediation steps.",
1032
- "</process>",
1033
- "",
1034
- "<rules>",
1035
- "- Do not fix issues automatically unless asked.",
1036
- "- Do not hand-manage Godot LSP processes; use GDH lifecycle commands.",
1037
- "- The gdh lsp lifecycle commands are status, prune, and stop.",
1038
- "- Explain diagnostics in human-readable terms.",
1039
- "- A ready `authoring.lsp` lifecycle is not proof that the authoring check collected diagnostics.",
1040
- "- Report both hard failures and informational caveats.",
1041
- "</rules>",
1042
- "",
1043
- ].join("\n");
1044
- }
1045
- export function renderCodexCheckSkill(pinnedVersion) {
1046
- return [
1047
- "---",
1048
- 'name: "gdh-check"',
1049
- 'description: "Run GDH authoring checks and explain diagnostics"',
1050
- "metadata:",
1051
- ' short-description: "Run GDH authoring checks and explain diagnostics"',
1052
- "---",
1053
- "",
1054
- "<codex_skill_adapter>",
1055
- "## Invocation",
1056
- "- This skill is invoked when the user says `/gdh-check` or mentions `$gdh-check`.",
1057
- "- Treat any extra user text as additional check context.",
1058
- "",
1059
- "## User questions",
1060
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
1061
- "- If structured user-input tooling is unavailable, ask concise plain-text questions instead.",
1062
- "</codex_skill_adapter>",
1063
- "",
1064
- "<objective>",
1065
- "Run GDH authoring checks and explain diagnostics in human-readable terms.",
1066
- "</objective>",
1067
- "",
1068
- "<process>",
1069
- "Follow this order:",
1070
- "",
1071
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} lsp status\` only for lifecycle visibility; do not treat lifecycle readiness as diagnostic evidence`,
1072
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} authoring check\` to collect validator evidence`,
1073
- "- explain each diagnostic finding with severity, provenance, and validator family (`gdscript_lsp` for `.gd`, `godot_scene_resource` for `.tscn`/`.tres`)",
1074
- "- surface any import-state caveats or editor-side warnings",
1075
- `- if stale managed LSP state is suspected, use bounded GDH cleanup such as \`npx -y @skillcap/gdh@${pinnedVersion} lsp prune\` or \`npx -y @skillcap/gdh@${pinnedVersion} lsp stop\`; do not hand-manage Godot LSP processes`,
1076
- "- if issues found, suggest concrete remediation steps",
1077
- "</process>",
1078
- "",
1079
- "<rules>",
1080
- "- Do not fix issues automatically unless asked.",
1081
- "- Do not hand-manage Godot LSP processes; use GDH lifecycle commands.",
1082
- "- The gdh lsp lifecycle commands are status, prune, and stop.",
1083
- "- Explain diagnostics in human-readable terms.",
1084
- "- A ready `authoring.lsp` lifecycle is not proof that the authoring check collected diagnostics.",
1085
- "- Report both hard failures and informational caveats.",
1086
- "</rules>",
1087
- "",
1088
- ].join("\n");
343
+ return renderClaudeCheckSkill(pinnedVersion);
1089
344
  }
1090
- export function renderCursorCheckSkill(pinnedVersion) {
1091
- return [
1092
- "---",
1093
- "name: gdh-check",
1094
- 'description: "Run GDH authoring checks and explain diagnostics"',
1095
- "---",
1096
- "",
1097
- "<cursor_skill_adapter>",
1098
- "## Invocation",
1099
- "- This skill is invoked when the user says `/gdh-check` or mentions `gdh-check`.",
1100
- "- Treat any extra user text as additional check context.",
1101
- "",
1102
- "## User questions",
1103
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
1104
- "- Keep questions conversational and concise.",
1105
- "</cursor_skill_adapter>",
1106
- "",
1107
- "<objective>",
1108
- "Run GDH authoring checks and explain diagnostics in human-readable terms.",
1109
- "</objective>",
1110
- "",
1111
- "<process>",
1112
- "Follow this order:",
1113
- "",
1114
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} lsp status\` only for lifecycle visibility; do not treat lifecycle readiness as diagnostic evidence`,
1115
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} authoring check\` to collect validator evidence`,
1116
- "- explain each diagnostic finding with severity, provenance, and validator family (`gdscript_lsp` for `.gd`, `godot_scene_resource` for `.tscn`/`.tres`)",
1117
- "- surface any import-state caveats or editor-side warnings",
1118
- `- if stale managed LSP state is suspected, use bounded GDH cleanup such as \`npx -y @skillcap/gdh@${pinnedVersion} lsp prune\` or \`npx -y @skillcap/gdh@${pinnedVersion} lsp stop\`; do not hand-manage Godot LSP processes`,
1119
- "- if issues found, suggest concrete remediation steps",
1120
- "</process>",
1121
- "",
1122
- "<rules>",
1123
- "- Do not fix issues automatically unless asked.",
1124
- "- Do not hand-manage Godot LSP processes; use GDH lifecycle commands.",
1125
- "- The gdh lsp lifecycle commands are status, prune, and stop.",
1126
- "- Explain diagnostics in human-readable terms.",
1127
- "- A ready `authoring.lsp` lifecycle is not proof that the authoring check collected diagnostics.",
1128
- "- Report both hard failures and informational caveats.",
1129
- "</rules>",
1130
- "",
1131
- ].join("\n");
1132
- }
1133
- // --- gdh-prepare skill renders ---
1134
345
  export function renderClaudePrepareCommand(pinnedVersion) {
1135
- return [
1136
- "---",
1137
- "name: gdh:prepare",
1138
- "description: Prepare a Godot target for authoring or runtime work",
1139
- "allowed-tools:",
1140
- " - Read",
1141
- " - Grep",
1142
- " - Glob",
1143
- " - Bash",
1144
- " - AskUserQuestion",
1145
- "---",
1146
- "<objective>",
1147
- "Prepare a Godot target for authoring or runtime work using GDH target preparation.",
1148
- "</objective>",
1149
- "",
1150
- "<process>",
1151
- "Follow this order:",
1152
- "",
1153
- `1. Run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare --dry-run\` first to preview planned actions.`,
1154
- "2. Explain what hydration and import refresh will do.",
1155
- `3. If the user approves, run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare\`.`,
1156
- "4. If a `--source-target` is relevant, explain when and why to use it.",
1157
- `5. Verify preparation succeeded with \`npx -y @skillcap/gdh@${pinnedVersion} status\`.`,
1158
- "</process>",
1159
- "",
1160
- "<rules>",
1161
- "- Always show dry-run first.",
1162
- "- Explain worktree hydration context.",
1163
- "- Do not skip import refresh without explicit reason.",
1164
- "</rules>",
1165
- "",
1166
- ].join("\n");
1167
- }
1168
- export function renderCodexPrepareSkill(pinnedVersion) {
1169
- return [
1170
- "---",
1171
- 'name: "gdh-prepare"',
1172
- 'description: "Prepare a Godot target for authoring or runtime work"',
1173
- "metadata:",
1174
- ' short-description: "Prepare a Godot target for authoring or runtime work"',
1175
- "---",
1176
- "",
1177
- "<codex_skill_adapter>",
1178
- "## Invocation",
1179
- "- This skill is invoked when the user says `/gdh-prepare` or mentions `$gdh-prepare`.",
1180
- "- Treat any extra user text as additional preparation context.",
1181
- "",
1182
- "## User questions",
1183
- "- Ask before running preparation if the user has not explicitly approved.",
1184
- "- If structured user-input tooling is unavailable, ask concise plain-text questions instead.",
1185
- "</codex_skill_adapter>",
1186
- "",
1187
- "<objective>",
1188
- "Prepare a Godot target for authoring or runtime work using GDH target preparation.",
1189
- "</objective>",
1190
- "",
1191
- "<process>",
1192
- "Follow this order:",
1193
- "",
1194
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare --dry-run\` first to preview planned actions`,
1195
- "- explain what hydration and import refresh will do",
1196
- `- if the user approves, run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare\``,
1197
- "- if a `--source-target` is relevant, explain when and why to use it",
1198
- `- verify preparation succeeded with \`npx -y @skillcap/gdh@${pinnedVersion} status\``,
1199
- "</process>",
1200
- "",
1201
- "<rules>",
1202
- "- Always show dry-run first.",
1203
- "- Explain worktree hydration context.",
1204
- "- Do not skip import refresh without explicit reason.",
1205
- "</rules>",
1206
- "",
1207
- ].join("\n");
1208
- }
1209
- export function renderCursorPrepareSkill(pinnedVersion) {
1210
- return [
1211
- "---",
1212
- "name: gdh-prepare",
1213
- 'description: "Prepare a Godot target for authoring or runtime work"',
1214
- "---",
1215
- "",
1216
- "<cursor_skill_adapter>",
1217
- "## Invocation",
1218
- "- This skill is invoked when the user says `/gdh-prepare` or mentions `gdh-prepare`.",
1219
- "- Treat any extra user text as additional preparation context.",
1220
- "",
1221
- "## User questions",
1222
- "- Ask before running preparation if the user has not explicitly approved.",
1223
- "- Keep questions conversational and concise.",
1224
- "</cursor_skill_adapter>",
1225
- "",
1226
- "<objective>",
1227
- "Prepare a Godot target for authoring or runtime work using GDH target preparation.",
1228
- "</objective>",
1229
- "",
1230
- "<process>",
1231
- "Follow this order:",
1232
- "",
1233
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare --dry-run\` first to preview planned actions`,
1234
- "- explain what hydration and import refresh will do",
1235
- `- if the user approves, run \`npx -y @skillcap/gdh@${pinnedVersion} target prepare\``,
1236
- "- if a `--source-target` is relevant, explain when and why to use it",
1237
- `- verify preparation succeeded with \`npx -y @skillcap/gdh@${pinnedVersion} status\``,
1238
- "</process>",
1239
- "",
1240
- "<rules>",
1241
- "- Always show dry-run first.",
1242
- "- Explain worktree hydration context.",
1243
- "- Do not skip import refresh without explicit reason.",
1244
- "</rules>",
1245
- "",
1246
- ].join("\n");
1247
- }
1248
- // --- gdh-verify skill renders ---
1249
- export function renderClaudeVerifyCommand(pinnedVersion) {
1250
- return [
1251
- "---",
1252
- "name: gdh:verify",
1253
- "description: Evaluate verification readiness and done-policy for changed files",
1254
- "allowed-tools:",
1255
- " - Read",
1256
- " - Grep",
1257
- " - Glob",
1258
- " - Bash",
1259
- "---",
1260
- "<objective>",
1261
- "Evaluate verification readiness and done-policy for changed files using GDH verification surfaces.",
1262
- "</objective>",
1263
- "",
1264
- "<process>",
1265
- "Follow this order:",
1266
- "",
1267
- "1. Identify changed files from git diff or user input.",
1268
- `2. Run \`npx -y @skillcap/gdh@${pinnedVersion} verify recommend\` with those files to get recommended validation kinds.`,
1269
- `3. Run \`npx -y @skillcap/gdh@${pinnedVersion} verify done\` with performed validations to check done eligibility.`,
1270
- "4. For authoring checks, explain validator-family expectations: `gdscript_lsp` for `.gd`, `godot_scene_resource` for `.tscn`/`.tres`, and manual validation for unsupported authoring files.",
1271
- "5. Summarize gaps between recommended and performed validation, including unavailable/degraded authoring evidence.",
1272
- "6. Suggest specific next verification steps.",
1273
- "</process>",
1274
- "",
1275
- "<rules>",
1276
- "- Do not mark work as done if done-policy is not satisfied.",
1277
- "- Surface all recommended validation kinds.",
1278
- "- Keep the summary actionable.",
1279
- "</rules>",
1280
- "",
1281
- ].join("\n");
1282
- }
1283
- export function renderCodexVerifySkill(pinnedVersion) {
1284
- return [
1285
- "---",
1286
- 'name: "gdh-verify"',
1287
- 'description: "Evaluate verification readiness and done-policy for changed files"',
1288
- "metadata:",
1289
- ' short-description: "Evaluate verification readiness and done-policy for changed files"',
1290
- "---",
1291
- "",
1292
- "<codex_skill_adapter>",
1293
- "## Invocation",
1294
- "- This skill is invoked when the user says `/gdh-verify` or mentions `$gdh-verify`.",
1295
- "- Treat any extra user text as additional verification context.",
1296
- "",
1297
- "## User questions",
1298
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
1299
- "- If structured user-input tooling is unavailable, ask concise plain-text questions instead.",
1300
- "</codex_skill_adapter>",
1301
- "",
1302
- "<objective>",
1303
- "Evaluate verification readiness and done-policy for changed files using GDH verification surfaces.",
1304
- "</objective>",
1305
- "",
1306
- "<process>",
1307
- "Follow this order:",
1308
- "",
1309
- "- identify changed files from git diff or user input",
1310
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} verify recommend\` with those files to get recommended validation kinds`,
1311
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} verify done\` with performed validations to check done eligibility`,
1312
- "- for authoring checks, explain validator-family expectations: `gdscript_lsp` for `.gd`, `godot_scene_resource` for `.tscn`/`.tres`, and manual validation for unsupported authoring files",
1313
- "- summarize gaps between recommended and performed validation, including unavailable/degraded authoring evidence",
1314
- "- suggest specific next verification steps",
1315
- "</process>",
1316
- "",
1317
- "<rules>",
1318
- "- Do not mark work as done if done-policy is not satisfied.",
1319
- "- Surface all recommended validation kinds.",
1320
- "- Keep the summary actionable.",
1321
- "</rules>",
1322
- "",
1323
- ].join("\n");
1324
- }
1325
- export function renderCursorVerifySkill(pinnedVersion) {
1326
- return [
1327
- "---",
1328
- "name: gdh-verify",
1329
- 'description: "Evaluate verification readiness and done-policy for changed files"',
1330
- "---",
1331
- "",
1332
- "<cursor_skill_adapter>",
1333
- "## Invocation",
1334
- "- This skill is invoked when the user says `/gdh-verify` or mentions `gdh-verify`.",
1335
- "- Treat any extra user text as additional verification context.",
1336
- "",
1337
- "## User questions",
1338
- "- Ask only narrow follow-up questions when GDH cannot infer the missing fact safely.",
1339
- "- Keep questions conversational and concise.",
1340
- "</cursor_skill_adapter>",
1341
- "",
1342
- "<objective>",
1343
- "Evaluate verification readiness and done-policy for changed files using GDH verification surfaces.",
1344
- "</objective>",
1345
- "",
1346
- "<process>",
1347
- "Follow this order:",
1348
- "",
1349
- "- identify changed files from git diff or user input",
1350
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} verify recommend\` with those files to get recommended validation kinds`,
1351
- `- run \`npx -y @skillcap/gdh@${pinnedVersion} verify done\` with performed validations to check done eligibility`,
1352
- "- for authoring checks, explain validator-family expectations: `gdscript_lsp` for `.gd`, `godot_scene_resource` for `.tscn`/`.tres`, and manual validation for unsupported authoring files",
1353
- "- summarize gaps between recommended and performed validation, including unavailable/degraded authoring evidence",
1354
- "- suggest specific next verification steps",
1355
- "</process>",
1356
- "",
1357
- "<rules>",
1358
- "- Do not mark work as done if done-policy is not satisfied.",
1359
- "- Surface all recommended validation kinds.",
1360
- "- Keep the summary actionable.",
1361
- "</rules>",
1362
- "",
1363
- ].join("\n");
346
+ return renderClaudePrepareSkill(pinnedVersion);
1364
347
  }
1365
348
  async function inspectProjectMcpSupport(targetPath, options) {
1366
349
  const projectConfig = await readProjectConfig(targetPath);
@@ -1588,34 +571,94 @@ function inspectCodexSkillSurface(targetPath, relativePath, content, expectedCon
1588
571
  }),
1589
572
  ];
1590
573
  }
1591
- function inspectClaudeCommandSurface(targetPath, relativePath, content, expectedContent, commandName) {
574
+ function inspectCodexAuthoringHookConfig(targetPath, content, enabled) {
575
+ if (!enabled) {
576
+ return createSurfaceStatus({
577
+ kind: "hook_config",
578
+ scope: "repo",
579
+ targetPath,
580
+ relativePath: CODEX_PROJECT_CONFIG_RELATIVE_PATH,
581
+ present: content !== null,
582
+ state: "ready",
583
+ summary: "Codex authoring hooks are disabled because project MCP config is disabled.",
584
+ version: null,
585
+ });
586
+ }
587
+ const ready = content !== null &&
588
+ /^\s*codex_hooks\s*=\s*true\s*$/m.test(content) &&
589
+ content.includes("# BEGIN GDH managed authoring hooks") &&
590
+ content.includes(CODEX_AUTHORING_HOOK_RELATIVE_PATH);
591
+ return createSurfaceStatus({
592
+ kind: "hook_config",
593
+ scope: "repo",
594
+ targetPath,
595
+ relativePath: CODEX_PROJECT_CONFIG_RELATIVE_PATH,
596
+ present: content !== null,
597
+ state: content === null ? "missing" : ready ? "ready" : "misconfigured",
598
+ summary: content === null
599
+ ? "Codex project config is missing and should register GDH authoring hooks."
600
+ : ready
601
+ ? "Codex project config enables GDH PostToolUse and Stop authoring hooks."
602
+ : "Codex project config exists but is missing the managed GDH authoring hook block.",
603
+ version: null,
604
+ });
605
+ }
606
+ function inspectManagedHookSurface(agent, targetPath, relativePath, content, expectedContent, hookName) {
607
+ if (expectedContent === null) {
608
+ return createSurfaceStatus({
609
+ kind: "hook_file",
610
+ scope: "repo",
611
+ targetPath,
612
+ relativePath,
613
+ present: content !== null,
614
+ state: "missing",
615
+ summary: `${agentLabel(agent)} ${hookName} hook cannot be validated yet: no \`gdh_version\` is pinned (run \`gdh setup\` or \`gdh migrate --apply\`).`,
616
+ version: null,
617
+ });
618
+ }
619
+ return createSurfaceStatus({
620
+ kind: "hook_file",
621
+ scope: "repo",
622
+ targetPath,
623
+ relativePath,
624
+ present: content !== null,
625
+ state: content === null ? "missing" : content === expectedContent ? "ready" : "misconfigured",
626
+ summary: content === null
627
+ ? `${agentLabel(agent)} ${hookName} hook file is missing.`
628
+ : content === expectedContent
629
+ ? `${agentLabel(agent)} ${hookName} hook file is managed and current.`
630
+ : `${agentLabel(agent)} ${hookName} hook file exists but no longer matches the managed GDH hook.`,
631
+ version: null,
632
+ });
633
+ }
634
+ function inspectClaudeSkillSurface(targetPath, relativePath, content, expectedContent, skillName) {
1592
635
  if (expectedContent === null) {
1593
636
  return [
1594
637
  createSurfaceStatus({
1595
- kind: "command_file",
638
+ kind: "skill_file",
1596
639
  scope: "repo",
1597
640
  targetPath,
1598
641
  relativePath,
1599
642
  present: content !== null,
1600
643
  state: "missing",
1601
- summary: `Claude ${commandName} command cannot be validated yet: no \`gdh_version\` is pinned (run \`gdh setup\` or \`gdh migrate --apply\`).`,
644
+ summary: `Claude ${skillName} skill cannot be validated yet: no \`gdh_version\` is pinned (run \`gdh setup\` or \`gdh migrate --apply\`).`,
1602
645
  version: null,
1603
646
  }),
1604
647
  ];
1605
648
  }
1606
649
  return [
1607
650
  createSurfaceStatus({
1608
- kind: "command_file",
651
+ kind: "skill_file",
1609
652
  scope: "repo",
1610
653
  targetPath,
1611
654
  relativePath,
1612
655
  present: content !== null,
1613
656
  state: content === null ? "missing" : content === expectedContent ? "ready" : "misconfigured",
1614
657
  summary: content === null
1615
- ? `Claude \`/${commandName}\` command is missing and should install under .claude/commands/gdh/.`
658
+ ? `Claude \`/${skillName}\` skill is missing and should install under .claude/skills/.`
1616
659
  : content === expectedContent
1617
- ? `Claude can discover the managed \`/${commandName}\` command.`
1618
- : `Claude \`/${commandName}\` command exists but no longer matches the expected managed GDH command.`,
660
+ ? `Claude can discover the managed \`/${skillName}\` skill.`
661
+ : `Claude \`/${skillName}\` skill exists but no longer matches the expected managed GDH skill.`,
1619
662
  version: null,
1620
663
  }),
1621
664
  ];
@@ -1674,20 +717,29 @@ async function inspectCodexAdapter(targetPath, guidance, projectMcp, pinnedVersi
1674
717
  const codexPrepareContent = await fs
1675
718
  .readFile(path.join(targetPath, CODEX_PREPARE_SKILL_RELATIVE_PATH), "utf8")
1676
719
  .catch(() => null);
1677
- const codexVerifyContent = await fs
1678
- .readFile(path.join(targetPath, CODEX_VERIFY_SKILL_RELATIVE_PATH), "utf8")
1679
- .catch(() => null);
1680
720
  const codexScanContent = await fs
1681
721
  .readFile(path.join(targetPath, CODEX_SCAN_SKILL_RELATIVE_PATH), "utf8")
1682
722
  .catch(() => null);
723
+ const codexAuthoringHookContent = await fs
724
+ .readFile(path.join(projectMcp.integrationRootPath, CODEX_AUTHORING_HOOK_RELATIVE_PATH), "utf8")
725
+ .catch(() => null);
726
+ const codexProjectConfigContent = await fs
727
+ .readFile(path.join(projectMcp.integrationRootPath, CODEX_PROJECT_CONFIG_RELATIVE_PATH), "utf8")
728
+ .catch(() => null);
1683
729
  const expectedCodexOnboardSkill = pinnedVersion === null ? null : renderCodexOnboardSkill(pinnedVersion);
1684
730
  const expectedCodexStatusSkill = pinnedVersion === null ? null : renderCodexStatusSkill(pinnedVersion);
1685
731
  const expectedCodexMigrateSkill = pinnedVersion === null ? null : renderCodexMigrateSkill(pinnedVersion);
1686
732
  const expectedCodexUpdateSkill = pinnedVersion === null ? null : renderCodexUpdateSkill(pinnedVersion);
1687
733
  const expectedCodexCheckSkill = pinnedVersion === null ? null : renderCodexCheckSkill(pinnedVersion);
1688
734
  const expectedCodexPrepareSkill = pinnedVersion === null ? null : renderCodexPrepareSkill(pinnedVersion);
1689
- const expectedCodexVerifySkill = pinnedVersion === null ? null : renderCodexVerifySkill(pinnedVersion);
1690
735
  const expectedCodexScanSkill = pinnedVersion === null ? null : renderCodexScanSkill(pinnedVersion);
736
+ const expectedCodexAuthoringHook = pinnedVersion === null
737
+ ? null
738
+ : renderGdhAuthoringHook({
739
+ pinnedVersion,
740
+ targetRelativePath: path.relative(projectMcp.integrationRootPath, targetPath) || ".",
741
+ agent: "codex",
742
+ });
1691
743
  const surfaces = [
1692
744
  createSurfaceStatus({
1693
745
  kind: "canonical_entrypoint",
@@ -1734,8 +786,9 @@ async function inspectCodexAdapter(targetPath, guidance, projectMcp, pinnedVersi
1734
786
  ...inspectCodexSkillSurface(targetPath, CODEX_UPDATE_SKILL_RELATIVE_PATH, codexUpdateContent, expectedCodexUpdateSkill, "gdh-update"),
1735
787
  ...inspectCodexSkillSurface(targetPath, CODEX_CHECK_SKILL_RELATIVE_PATH, codexCheckContent, expectedCodexCheckSkill, "gdh-check"),
1736
788
  ...inspectCodexSkillSurface(targetPath, CODEX_PREPARE_SKILL_RELATIVE_PATH, codexPrepareContent, expectedCodexPrepareSkill, "gdh-prepare"),
1737
- ...inspectCodexSkillSurface(targetPath, CODEX_VERIFY_SKILL_RELATIVE_PATH, codexVerifyContent, expectedCodexVerifySkill, "gdh-verify"),
1738
789
  ...inspectCodexSkillSurface(targetPath, CODEX_SCAN_SKILL_RELATIVE_PATH, codexScanContent, expectedCodexScanSkill, "gdh-scan"),
790
+ inspectManagedHookSurface("codex", projectMcp.integrationRootPath, CODEX_AUTHORING_HOOK_RELATIVE_PATH, codexAuthoringHookContent, expectedCodexAuthoringHook, "authoring guard"),
791
+ inspectCodexAuthoringHookConfig(projectMcp.integrationRootPath, codexProjectConfigContent, projectMcp.enabled),
1739
792
  ];
1740
793
  if (projectMcp.enabled) {
1741
794
  surfaces.push(createSurfaceStatus({
@@ -1775,7 +828,7 @@ async function inspectClaudeAdapter(targetPath, guidance, projectMcp, pinnedVers
1775
828
  const claudeMigrateContent = await fs
1776
829
  .readFile(path.join(targetPath, CLAUDE_MIGRATE_COMMAND_RELATIVE_PATH), "utf8")
1777
830
  .catch(() => null);
1778
- // Phase 13 Plan 13-03 deliverable — /gdh-update slash command for Claude.
831
+ // Phase 13 Plan 13-03 deliverable — /gdh-update skill for Claude.
1779
832
  // Inspection wiring is required so planSkillInstallAction can see the surface
1780
833
  // state; otherwise the planner returns `unchanged` for a missing file and
1781
834
  // install becomes a no-op (Plan 13-05 integration-test Rule 2 fix).
@@ -1788,9 +841,6 @@ async function inspectClaudeAdapter(targetPath, guidance, projectMcp, pinnedVers
1788
841
  const claudePrepareContent = await fs
1789
842
  .readFile(path.join(targetPath, CLAUDE_PREPARE_COMMAND_RELATIVE_PATH), "utf8")
1790
843
  .catch(() => null);
1791
- const claudeVerifyContent = await fs
1792
- .readFile(path.join(targetPath, CLAUDE_VERIFY_COMMAND_RELATIVE_PATH), "utf8")
1793
- .catch(() => null);
1794
844
  const claudeScanContent = await fs
1795
845
  .readFile(path.join(targetPath, CLAUDE_SCAN_COMMAND_RELATIVE_PATH), "utf8")
1796
846
  .catch(() => null);
@@ -1803,6 +853,9 @@ async function inspectClaudeAdapter(targetPath, guidance, projectMcp, pinnedVers
1803
853
  const claudeStatuslineContent = await fs
1804
854
  .readFile(path.join(targetPath, CLAUDE_STATUSLINE_RELATIVE_PATH), "utf8")
1805
855
  .catch(() => null);
856
+ const claudeAuthoringHookContent = await fs
857
+ .readFile(path.join(targetPath, CLAUDE_AUTHORING_HOOK_RELATIVE_PATH), "utf8")
858
+ .catch(() => null);
1806
859
  let detectedTarget = null;
1807
860
  if (lstat?.isSymbolicLink()) {
1808
861
  detectedTarget = await fs.readlink(absolutePath).catch(() => null);
@@ -1811,12 +864,18 @@ async function inspectClaudeAdapter(targetPath, guidance, projectMcp, pinnedVers
1811
864
  const expectedClaudeCheckUpdateHook = pinnedVersion === null ? null : renderClaudeCheckUpdateHook(pinnedVersion);
1812
865
  const expectedClaudeCheckUpdateWorker = pinnedVersion === null ? null : renderClaudeCheckUpdateWorker(pinnedVersion);
1813
866
  const expectedClaudeStatusline = pinnedVersion === null ? null : renderClaudeUpdateStatusline(pinnedVersion);
867
+ const expectedClaudeAuthoringHook = pinnedVersion === null
868
+ ? null
869
+ : renderGdhAuthoringHook({
870
+ pinnedVersion,
871
+ targetRelativePath: ".",
872
+ agent: "claude",
873
+ });
1814
874
  const expectedClaudeStatusCommand = pinnedVersion === null ? null : renderClaudeStatusCommand(pinnedVersion);
1815
875
  const expectedClaudeMigrateCommand = pinnedVersion === null ? null : renderClaudeMigrateCommand(pinnedVersion);
1816
876
  const expectedClaudeUpdateCommand = pinnedVersion === null ? null : renderClaudeUpdateCommand(pinnedVersion);
1817
877
  const expectedClaudeCheckCommand = pinnedVersion === null ? null : renderClaudeCheckCommand(pinnedVersion);
1818
878
  const expectedClaudePrepareCommand = pinnedVersion === null ? null : renderClaudePrepareCommand(pinnedVersion);
1819
- const expectedClaudeVerifyCommand = pinnedVersion === null ? null : renderClaudeVerifyCommand(pinnedVersion);
1820
879
  const expectedClaudeScanCommand = pinnedVersion === null ? null : renderClaudeScanCommand(pinnedVersion);
1821
880
  const surfaces = [
1822
881
  createSurfaceStatus({
@@ -1840,7 +899,7 @@ async function inspectClaudeAdapter(targetPath, guidance, projectMcp, pinnedVers
1840
899
  detectedTarget,
1841
900
  }),
1842
901
  createSurfaceStatus({
1843
- kind: "command_file",
902
+ kind: "skill_file",
1844
903
  scope: "repo",
1845
904
  targetPath,
1846
905
  relativePath: CLAUDE_ONBOARD_COMMAND_RELATIVE_PATH,
@@ -1853,24 +912,24 @@ async function inspectClaudeAdapter(targetPath, guidance, projectMcp, pinnedVers
1853
912
  ? "ready"
1854
913
  : "misconfigured",
1855
914
  summary: onboardCommandContent === null
1856
- ? "Claude onboarding handoff is missing and should install `/gdh-onboard` under .claude/commands/."
915
+ ? "Claude onboarding handoff is missing and should install `/gdh-onboard` under .claude/skills/."
1857
916
  : expectedClaudeOnboardCommand === null
1858
917
  ? "Claude onboarding handoff cannot be validated yet: no `gdh_version` is pinned (run `gdh setup` or `gdh migrate --apply`)."
1859
918
  : onboardCommandContent === expectedClaudeOnboardCommand
1860
- ? "Claude can discover the managed `/gdh-onboard` handoff command."
1861
- : "Claude onboarding handoff exists but no longer matches the expected managed GDH command.",
919
+ ? "Claude can discover the managed `/gdh-onboard` handoff skill."
920
+ : "Claude onboarding handoff exists but no longer matches the expected managed GDH skill.",
1862
921
  version: null,
1863
922
  }),
1864
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_STATUS_COMMAND_RELATIVE_PATH, claudeStatusContent, expectedClaudeStatusCommand, "gdh-status"),
1865
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_MIGRATE_COMMAND_RELATIVE_PATH, claudeMigrateContent, expectedClaudeMigrateCommand, "gdh-migrate"),
1866
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_UPDATE_COMMAND_RELATIVE_PATH, claudeUpdateContent, expectedClaudeUpdateCommand, "gdh-update"),
1867
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_CHECK_COMMAND_RELATIVE_PATH, claudeCheckContent, expectedClaudeCheckCommand, "gdh-check"),
1868
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_PREPARE_COMMAND_RELATIVE_PATH, claudePrepareContent, expectedClaudePrepareCommand, "gdh-prepare"),
1869
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_VERIFY_COMMAND_RELATIVE_PATH, claudeVerifyContent, expectedClaudeVerifyCommand, "gdh-verify"),
1870
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_SCAN_COMMAND_RELATIVE_PATH, claudeScanContent, expectedClaudeScanCommand, "gdh-scan"),
1871
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_CHECK_UPDATE_HOOK_RELATIVE_PATH, claudeCheckUpdateHookContent, expectedClaudeCheckUpdateHook, "gdh-check-update-hook"),
1872
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_CHECK_UPDATE_WORKER_RELATIVE_PATH, claudeCheckUpdateWorkerContent, expectedClaudeCheckUpdateWorker, "gdh-check-update-worker"),
1873
- ...inspectClaudeCommandSurface(targetPath, CLAUDE_STATUSLINE_RELATIVE_PATH, claudeStatuslineContent, expectedClaudeStatusline, "gdh-statusline"),
923
+ ...inspectClaudeSkillSurface(targetPath, CLAUDE_STATUS_COMMAND_RELATIVE_PATH, claudeStatusContent, expectedClaudeStatusCommand, "gdh-status"),
924
+ ...inspectClaudeSkillSurface(targetPath, CLAUDE_MIGRATE_COMMAND_RELATIVE_PATH, claudeMigrateContent, expectedClaudeMigrateCommand, "gdh-migrate"),
925
+ ...inspectClaudeSkillSurface(targetPath, CLAUDE_UPDATE_COMMAND_RELATIVE_PATH, claudeUpdateContent, expectedClaudeUpdateCommand, "gdh-update"),
926
+ ...inspectClaudeSkillSurface(targetPath, CLAUDE_CHECK_COMMAND_RELATIVE_PATH, claudeCheckContent, expectedClaudeCheckCommand, "gdh-check"),
927
+ ...inspectClaudeSkillSurface(targetPath, CLAUDE_PREPARE_COMMAND_RELATIVE_PATH, claudePrepareContent, expectedClaudePrepareCommand, "gdh-prepare"),
928
+ ...inspectClaudeSkillSurface(targetPath, CLAUDE_SCAN_COMMAND_RELATIVE_PATH, claudeScanContent, expectedClaudeScanCommand, "gdh-scan"),
929
+ inspectManagedHookSurface("claude", targetPath, CLAUDE_CHECK_UPDATE_HOOK_RELATIVE_PATH, claudeCheckUpdateHookContent, expectedClaudeCheckUpdateHook, "gdh-check-update-hook"),
930
+ inspectManagedHookSurface("claude", targetPath, CLAUDE_CHECK_UPDATE_WORKER_RELATIVE_PATH, claudeCheckUpdateWorkerContent, expectedClaudeCheckUpdateWorker, "gdh-check-update-worker"),
931
+ inspectManagedHookSurface("claude", targetPath, CLAUDE_STATUSLINE_RELATIVE_PATH, claudeStatuslineContent, expectedClaudeStatusline, "gdh-statusline"),
932
+ inspectManagedHookSurface("claude", targetPath, CLAUDE_AUTHORING_HOOK_RELATIVE_PATH, claudeAuthoringHookContent, expectedClaudeAuthoringHook, "authoring guard"),
1874
933
  ];
1875
934
  if (projectMcp.enabled) {
1876
935
  surfaces.push(createSurfaceStatus({
@@ -1912,9 +971,6 @@ async function inspectCursorAdapter(targetPath, guidance, projectMcp, pinnedVers
1912
971
  const cursorPrepareContent = await fs
1913
972
  .readFile(path.join(targetPath, CURSOR_PREPARE_SKILL_RELATIVE_PATH), "utf8")
1914
973
  .catch(() => null);
1915
- const cursorVerifyContent = await fs
1916
- .readFile(path.join(targetPath, CURSOR_VERIFY_SKILL_RELATIVE_PATH), "utf8")
1917
- .catch(() => null);
1918
974
  const cursorScanContent = await fs
1919
975
  .readFile(path.join(targetPath, CURSOR_SCAN_SKILL_RELATIVE_PATH), "utf8")
1920
976
  .catch(() => null);
@@ -1926,7 +982,6 @@ async function inspectCursorAdapter(targetPath, guidance, projectMcp, pinnedVers
1926
982
  const expectedCursorUpdateSkill = pinnedVersion === null ? null : renderCursorUpdateSkill(pinnedVersion);
1927
983
  const expectedCursorCheckSkill = pinnedVersion === null ? null : renderCursorCheckSkill(pinnedVersion);
1928
984
  const expectedCursorPrepareSkill = pinnedVersion === null ? null : renderCursorPrepareSkill(pinnedVersion);
1929
- const expectedCursorVerifySkill = pinnedVersion === null ? null : renderCursorVerifySkill(pinnedVersion);
1930
985
  const expectedCursorScanSkill = pinnedVersion === null ? null : renderCursorScanSkill(pinnedVersion);
1931
986
  const surfaces = [
1932
987
  createSurfaceStatus({
@@ -1970,7 +1025,6 @@ async function inspectCursorAdapter(targetPath, guidance, projectMcp, pinnedVers
1970
1025
  ...inspectCursorSkillSurface(targetPath, CURSOR_UPDATE_SKILL_RELATIVE_PATH, cursorUpdateContent, expectedCursorUpdateSkill, "gdh-update"),
1971
1026
  ...inspectCursorSkillSurface(targetPath, CURSOR_CHECK_SKILL_RELATIVE_PATH, cursorCheckContent, expectedCursorCheckSkill, "gdh-check"),
1972
1027
  ...inspectCursorSkillSurface(targetPath, CURSOR_PREPARE_SKILL_RELATIVE_PATH, cursorPrepareContent, expectedCursorPrepareSkill, "gdh-prepare"),
1973
- ...inspectCursorSkillSurface(targetPath, CURSOR_VERIFY_SKILL_RELATIVE_PATH, cursorVerifyContent, expectedCursorVerifySkill, "gdh-verify"),
1974
1028
  ...inspectCursorSkillSurface(targetPath, CURSOR_SCAN_SKILL_RELATIVE_PATH, cursorScanContent, expectedCursorScanSkill, "gdh-scan"),
1975
1029
  ];
1976
1030
  if (projectMcp.enabled) {
@@ -2079,6 +1133,7 @@ async function planInstallActions(targetPath, adapters, requestedAgents, options
2079
1133
  actions.push(...planCursorInstallActions(targetPath, adapter, options.pinnedVersion));
2080
1134
  }
2081
1135
  }
1136
+ actions.push(...planRetiredVerifySurfaceCleanupActions(targetPath));
2082
1137
  return dedupeInstallActions(actions);
2083
1138
  }
2084
1139
  function planSharedRepoInstallActions(targetPath, projectMcp, agent, effectiveDevRepoPath, integrationRootPath, pinnedVersion) {
@@ -2155,7 +1210,7 @@ function planSkillInstallAction(agent, targetPath, adapter, relativePath, render
2155
1210
  relativePath,
2156
1211
  state: "unchanged",
2157
1212
  mode: "unchanged",
2158
- summary: `The managed ${agentLabel(agent)} \`/${skillName}\` ${agent === "claude" ? "command" : "skill"} already matches the expected GDH content.`,
1213
+ summary: `The managed ${agentLabel(agent)} \`/${skillName}\` skill already matches the expected GDH content.`,
2159
1214
  content: renderFn(pinnedVersion),
2160
1215
  });
2161
1216
  }
@@ -2168,8 +1223,37 @@ function planSkillInstallAction(agent, targetPath, adapter, relativePath, render
2168
1223
  state: "planned",
2169
1224
  mode: surface.present ? "replace" : "create",
2170
1225
  summary: surface.present
2171
- ? `Replace the existing ${agentLabel(agent)} \`/${skillName}\` ${agent === "claude" ? "command" : "skill"} with the managed GDH ${agent === "claude" ? "command" : "skill"}.`
2172
- : `Create the managed ${agentLabel(agent)} \`/${skillName}\` ${agent === "claude" ? "command" : "skill"}.`,
1226
+ ? `Replace the existing ${agentLabel(agent)} \`/${skillName}\` skill with the managed GDH skill.`
1227
+ : `Create the managed ${agentLabel(agent)} \`/${skillName}\` skill.`,
1228
+ content: renderFn(pinnedVersion),
1229
+ });
1230
+ }
1231
+ function planHookInstallAction(agent, targetPath, adapter, relativePath, renderFn, hookName, pinnedVersion) {
1232
+ const surface = adapter.surfaces.find((entry) => entry.relativePath === relativePath);
1233
+ if (!surface || surface.state === "ready") {
1234
+ return createInstallAction({
1235
+ agent,
1236
+ kind: "write_file",
1237
+ scope: "repo",
1238
+ targetPath,
1239
+ relativePath,
1240
+ state: "unchanged",
1241
+ mode: "unchanged",
1242
+ summary: `${agentLabel(agent)} ${hookName} hook already matches the managed GDH hook.`,
1243
+ content: renderFn(pinnedVersion),
1244
+ });
1245
+ }
1246
+ return createInstallAction({
1247
+ agent,
1248
+ kind: "write_file",
1249
+ scope: "repo",
1250
+ targetPath,
1251
+ relativePath,
1252
+ state: "planned",
1253
+ mode: surface.present ? "replace" : "create",
1254
+ summary: surface.present
1255
+ ? `Replace the existing ${agentLabel(agent)} ${hookName} hook with the managed GDH hook.`
1256
+ : `Create the managed ${agentLabel(agent)} ${hookName} hook.`,
2173
1257
  content: renderFn(pinnedVersion),
2174
1258
  });
2175
1259
  }
@@ -2191,8 +1275,12 @@ function planCodexRepoInstallActions(targetPath, adapter, pinnedVersion, project
2191
1275
  planSkillInstallAction("codex", targetPath, adapter, CODEX_UPDATE_SKILL_RELATIVE_PATH, renderCodexUpdateSkill, "gdh-update", pinnedVersion),
2192
1276
  planSkillInstallAction("codex", targetPath, adapter, CODEX_CHECK_SKILL_RELATIVE_PATH, renderCodexCheckSkill, "gdh-check", pinnedVersion),
2193
1277
  planSkillInstallAction("codex", targetPath, adapter, CODEX_PREPARE_SKILL_RELATIVE_PATH, renderCodexPrepareSkill, "gdh-prepare", pinnedVersion),
2194
- planSkillInstallAction("codex", targetPath, adapter, CODEX_VERIFY_SKILL_RELATIVE_PATH, renderCodexVerifySkill, "gdh-verify", pinnedVersion),
2195
1278
  planSkillInstallAction("codex", targetPath, adapter, CODEX_SCAN_SKILL_RELATIVE_PATH, renderCodexScanSkill, "gdh-scan", pinnedVersion),
1279
+ planSkillInstallAction("codex", integrationRootPath, adapter, CODEX_AUTHORING_HOOK_RELATIVE_PATH, (version) => renderGdhAuthoringHook({
1280
+ pinnedVersion: version,
1281
+ targetRelativePath: path.relative(integrationRootPath, targetPath) || ".",
1282
+ agent: "codex",
1283
+ }), "authoring guard", pinnedVersion),
2196
1284
  ];
2197
1285
  if (projectMcp.enabled && projectMcp.codexProjectFile.state !== "ready") {
2198
1286
  const absolutePath = path.join(integrationRootPath, CODEX_PROJECT_CONFIG_RELATIVE_PATH);
@@ -2216,19 +1304,77 @@ function planCodexRepoInstallActions(targetPath, adapter, pinnedVersion, project
2216
1304
  actions.push(...planLegacyCodexSkillCleanupActions(targetPath, pinnedVersion));
2217
1305
  return actions;
2218
1306
  }
2219
- // The signature embedded in every codex skill render body via the
2220
- // `<codex_skill_adapter>` block. Detecting this marker lets the legacy
2221
- // cleanup recognize a managed file regardless of which prior GDH version
2222
- // rendered it, so stale-version skills at `.codex/skills/...` get removed
2223
- // during migrate even when their pinned-npx string no longer matches the
2224
- // current `pinnedVersion` (D-22 fix; see Session 7 dogfooding follow-up).
2225
- const CODEX_MANAGED_SKILL_MARKER = "<codex_skill_adapter>";
1307
+ // Current skill renders use a neutral Markdown-safe GDH_MANAGED_AGENT_SKILL
1308
+ // marker. Legacy renders used provider-specific XML-ish marker blocks. Cleanup
1309
+ // accepts both so old managed files can migrate without deleting user-authored
1310
+ // files based only on path.
1311
+ const LEGACY_CODEX_MANAGED_SKILL_MARKER = "<codex_skill_adapter>";
1312
+ const LEGACY_CURSOR_MANAGED_SKILL_MARKER = "<cursor_skill_adapter>";
1313
+ function isManagedAgentSkillContent(content) {
1314
+ return (content.includes(GDH_MANAGED_AGENT_SKILL_MARKER) ||
1315
+ content.includes(LEGACY_CODEX_MANAGED_SKILL_MARKER) ||
1316
+ content.includes(LEGACY_CURSOR_MANAGED_SKILL_MARKER));
1317
+ }
2226
1318
  function isManagedLegacyCodexSkillContent(content) {
2227
- return content.includes(CODEX_MANAGED_SKILL_MARKER);
1319
+ return (content.includes(GDH_MANAGED_AGENT_SKILL_MARKER) ||
1320
+ content.includes(LEGACY_CODEX_MANAGED_SKILL_MARKER));
1321
+ }
1322
+ function isManagedLegacyClaudeCommandContent(content, skillName) {
1323
+ const slashName = skillName.replace("gdh-", "gdh:");
1324
+ return (content.includes(`name: ${slashName}`) &&
1325
+ (content.includes("@skillcap/gdh@") ||
1326
+ content.includes(GDH_MANAGED_AGENT_SKILL_MARKER) ||
1327
+ content.includes("<objective>") ||
1328
+ content.includes("<process>") ||
1329
+ content.includes("<rules>")));
1330
+ }
1331
+ const RETIRED_VERIFY_SURFACE_RELATIVE_PATHS = [
1332
+ {
1333
+ agent: "codex",
1334
+ relativePath: ".agents/skills/gdh-verify/SKILL.md",
1335
+ skillName: "gdh-verify",
1336
+ isManaged: isManagedAgentSkillContent,
1337
+ },
1338
+ {
1339
+ agent: "cursor",
1340
+ relativePath: ".cursor/skills/gdh-verify/SKILL.md",
1341
+ skillName: "gdh-verify",
1342
+ isManaged: isManagedAgentSkillContent,
1343
+ },
1344
+ {
1345
+ agent: "claude",
1346
+ relativePath: ".claude/commands/gdh/verify.md",
1347
+ skillName: "gdh-verify",
1348
+ isManaged: (content) => content.includes("name: gdh:verify") &&
1349
+ (content.includes("@skillcap/gdh@") || content.includes("gdh verify recommend")),
1350
+ },
1351
+ ];
1352
+ function planRetiredVerifySurfaceCleanupActions(targetPath) {
1353
+ const actions = [];
1354
+ for (const entry of RETIRED_VERIFY_SURFACE_RELATIVE_PATHS) {
1355
+ const absolutePath = path.join(targetPath, entry.relativePath);
1356
+ const content = fsSync.existsSync(absolutePath)
1357
+ ? fsSync.readFileSync(absolutePath, "utf8")
1358
+ : null;
1359
+ if (content === null || !entry.isManaged(content)) {
1360
+ continue;
1361
+ }
1362
+ actions.push(createInstallAction({
1363
+ agent: entry.agent,
1364
+ kind: "remove_file",
1365
+ scope: "repo",
1366
+ targetPath,
1367
+ relativePath: entry.relativePath,
1368
+ state: "planned",
1369
+ mode: "delete",
1370
+ summary: `Remove retired managed \`/${entry.skillName}\` surface. Agents should use \`/gdh-check\` for code-validity evidence.`,
1371
+ }));
1372
+ }
1373
+ return actions;
2228
1374
  }
2229
1375
  function planLegacyCodexSkillCleanupActions(targetPath, _pinnedVersion) {
2230
1376
  const actions = [];
2231
- for (const [relativePath, _renderFn, skillName] of LEGACY_CODEX_SKILL_RELATIVE_PATHS) {
1377
+ for (const [relativePath, skillName] of LEGACY_CODEX_SKILL_RELATIVE_PATHS) {
2232
1378
  const absolutePath = path.join(targetPath, relativePath);
2233
1379
  const content = fsSync.existsSync(absolutePath)
2234
1380
  ? fsSync.readFileSync(absolutePath, "utf8")
@@ -2255,6 +1401,29 @@ function planLegacyCodexSkillCleanupActions(targetPath, _pinnedVersion) {
2255
1401
  }
2256
1402
  return actions;
2257
1403
  }
1404
+ function planLegacyClaudeCommandCleanupActions(targetPath) {
1405
+ const actions = [];
1406
+ for (const [relativePath, skillName] of LEGACY_CLAUDE_SKILL_COMMAND_RELATIVE_PATHS) {
1407
+ const absolutePath = path.join(targetPath, relativePath);
1408
+ const content = fsSync.existsSync(absolutePath)
1409
+ ? fsSync.readFileSync(absolutePath, "utf8")
1410
+ : null;
1411
+ if (content === null || !isManagedLegacyClaudeCommandContent(content, skillName)) {
1412
+ continue;
1413
+ }
1414
+ actions.push(createInstallAction({
1415
+ agent: "claude",
1416
+ kind: "remove_file",
1417
+ scope: "repo",
1418
+ targetPath,
1419
+ relativePath,
1420
+ state: "planned",
1421
+ mode: "delete",
1422
+ summary: `Remove legacy managed Claude \`/${skillName}\` command after installing the provider-recommended .claude/skills surface.`,
1423
+ }));
1424
+ }
1425
+ return actions;
1426
+ }
2258
1427
  function planCodexUserInstallActions(targetPath, projectMcp, integrationRootPath, pinnedVersion) {
2259
1428
  if (!projectMcp.enabled || projectMcp.codexServerName === null) {
2260
1429
  return [];
@@ -2333,14 +1502,18 @@ function planClaudeInstallActions(targetPath, adapter, pinnedVersion) {
2333
1502
  expectedTarget: "AGENTS.md",
2334
1503
  }));
2335
1504
  }
2336
- actions.push(planSkillInstallAction("claude", targetPath, adapter, CLAUDE_ONBOARD_COMMAND_RELATIVE_PATH, renderClaudeOnboardCommand, "gdh-onboard", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_STATUS_COMMAND_RELATIVE_PATH, renderClaudeStatusCommand, "gdh-status", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_MIGRATE_COMMAND_RELATIVE_PATH, renderClaudeMigrateCommand, "gdh-migrate", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_UPDATE_COMMAND_RELATIVE_PATH, renderClaudeUpdateCommand, "gdh-update", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_CHECK_COMMAND_RELATIVE_PATH, renderClaudeCheckCommand, "gdh-check", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_PREPARE_COMMAND_RELATIVE_PATH, renderClaudePrepareCommand, "gdh-prepare", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_VERIFY_COMMAND_RELATIVE_PATH, renderClaudeVerifyCommand, "gdh-verify", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_SCAN_COMMAND_RELATIVE_PATH, renderClaudeScanCommand, "gdh-scan", pinnedVersion),
1505
+ actions.push(planSkillInstallAction("claude", targetPath, adapter, CLAUDE_ONBOARD_COMMAND_RELATIVE_PATH, renderClaudeOnboardCommand, "gdh-onboard", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_STATUS_COMMAND_RELATIVE_PATH, renderClaudeStatusCommand, "gdh-status", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_MIGRATE_COMMAND_RELATIVE_PATH, renderClaudeMigrateCommand, "gdh-migrate", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_UPDATE_COMMAND_RELATIVE_PATH, renderClaudeUpdateCommand, "gdh-update", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_CHECK_COMMAND_RELATIVE_PATH, renderClaudeCheckCommand, "gdh-check", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_PREPARE_COMMAND_RELATIVE_PATH, renderClaudePrepareCommand, "gdh-prepare", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_SCAN_COMMAND_RELATIVE_PATH, renderClaudeScanCommand, "gdh-scan", pinnedVersion),
2337
1506
  // UPD-01 managed hook surfaces baked at the pinned version.
2338
- planSkillInstallAction("claude", targetPath, adapter, CLAUDE_CHECK_UPDATE_HOOK_RELATIVE_PATH, renderClaudeCheckUpdateHook, "gdh-check-update-hook", pinnedVersion), planSkillInstallAction("claude", targetPath, adapter, CLAUDE_CHECK_UPDATE_WORKER_RELATIVE_PATH, renderClaudeCheckUpdateWorker, "gdh-check-update-worker", pinnedVersion),
1507
+ planHookInstallAction("claude", targetPath, adapter, CLAUDE_CHECK_UPDATE_HOOK_RELATIVE_PATH, renderClaudeCheckUpdateHook, "gdh-check-update-hook", pinnedVersion), planHookInstallAction("claude", targetPath, adapter, CLAUDE_CHECK_UPDATE_WORKER_RELATIVE_PATH, renderClaudeCheckUpdateWorker, "gdh-check-update-worker", pinnedVersion),
2339
1508
  // UPD-02 managed statusline surface baked at the pinned version. The .js
2340
1509
  // file is ALWAYS baked, even when settings.json statusLine is not owned
2341
1510
  // by GDH (write-if-absent below) — users can manually point their config
2342
1511
  // at gdh-statusline.js later; the baked file is a no-op until wired.
2343
- planSkillInstallAction("claude", targetPath, adapter, CLAUDE_STATUSLINE_RELATIVE_PATH, renderClaudeUpdateStatusline, "gdh-statusline", pinnedVersion));
1512
+ planHookInstallAction("claude", targetPath, adapter, CLAUDE_STATUSLINE_RELATIVE_PATH, renderClaudeUpdateStatusline, "gdh-statusline", pinnedVersion), planHookInstallAction("claude", targetPath, adapter, CLAUDE_AUTHORING_HOOK_RELATIVE_PATH, (version) => renderGdhAuthoringHook({
1513
+ pinnedVersion: version,
1514
+ targetRelativePath: ".",
1515
+ agent: "claude",
1516
+ }), "authoring guard", pinnedVersion));
2344
1517
  // UPD-01 + UPD-02 .claude/settings.json composite patch action.
2345
1518
  // - Plan 02 (Strategy A, planner-lock #1): patch-merge the SessionStart
2346
1519
  // hook entry by exact command-literal match, preserving siblings.
@@ -2360,7 +1533,7 @@ function planClaudeInstallActions(targetPath, adapter, pinnedVersion) {
2360
1533
  catch {
2361
1534
  existingSettingsContent = "";
2362
1535
  }
2363
- const patchedSettings = patchClaudeSettingsForGdhStatusline(patchClaudeSettingsForGdhSessionStart(existingSettingsContent));
1536
+ const patchedSettings = patchClaudeSettingsForGdhStatusline(patchClaudeSettingsForGdhAuthoringHooks(patchClaudeSettingsForGdhSessionStart(existingSettingsContent)));
2364
1537
  const settingsIsUnchanged = existingSettingsContent === patchedSettings;
2365
1538
  const settingsExistedOnDisk = existingSettingsContent.length > 0;
2366
1539
  actions.push(createInstallAction({
@@ -2372,12 +1545,13 @@ function planClaudeInstallActions(targetPath, adapter, pinnedVersion) {
2372
1545
  state: settingsIsUnchanged ? "unchanged" : "planned",
2373
1546
  mode: settingsIsUnchanged ? "unchanged" : settingsExistedOnDisk ? "replace" : "create",
2374
1547
  summary: settingsIsUnchanged
2375
- ? "GDH SessionStart hook + statusline already registered in .claude/settings.json."
1548
+ ? "GDH SessionStart hook, authoring guard hooks, and statusline already registered in .claude/settings.json."
2376
1549
  : settingsExistedOnDisk
2377
- ? "Register the GDH SessionStart hook and statusline (write-if-absent) in .claude/settings.json while preserving sibling content (patch-merge)."
2378
- : "Create .claude/settings.json with the GDH SessionStart hook + statusline registration.",
1550
+ ? "Register the GDH SessionStart hook, authoring guard hooks, and statusline (write-if-absent) in .claude/settings.json while preserving sibling content (patch-merge)."
1551
+ : "Create .claude/settings.json with the GDH SessionStart hook, authoring guard hooks, and statusline registration.",
2379
1552
  content: patchedSettings,
2380
1553
  }));
1554
+ actions.push(...planLegacyClaudeCommandCleanupActions(targetPath));
2381
1555
  return actions;
2382
1556
  }
2383
1557
  function planCursorInstallActions(targetPath, adapter, pinnedVersion) {
@@ -2413,7 +1587,7 @@ function planCursorInstallActions(targetPath, adapter, pinnedVersion) {
2413
1587
  content: renderCursorRule(),
2414
1588
  }));
2415
1589
  }
2416
- actions.push(planSkillInstallAction("cursor", targetPath, adapter, CURSOR_ONBOARD_SKILL_RELATIVE_PATH, renderCursorOnboardSkill, "gdh-onboard", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_STATUS_SKILL_RELATIVE_PATH, renderCursorStatusSkill, "gdh-status", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_MIGRATE_SKILL_RELATIVE_PATH, renderCursorMigrateSkill, "gdh-migrate", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_UPDATE_SKILL_RELATIVE_PATH, renderCursorUpdateSkill, "gdh-update", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_CHECK_SKILL_RELATIVE_PATH, renderCursorCheckSkill, "gdh-check", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_PREPARE_SKILL_RELATIVE_PATH, renderCursorPrepareSkill, "gdh-prepare", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_VERIFY_SKILL_RELATIVE_PATH, renderCursorVerifySkill, "gdh-verify", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_SCAN_SKILL_RELATIVE_PATH, renderCursorScanSkill, "gdh-scan", pinnedVersion));
1590
+ actions.push(planSkillInstallAction("cursor", targetPath, adapter, CURSOR_ONBOARD_SKILL_RELATIVE_PATH, renderCursorOnboardSkill, "gdh-onboard", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_STATUS_SKILL_RELATIVE_PATH, renderCursorStatusSkill, "gdh-status", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_MIGRATE_SKILL_RELATIVE_PATH, renderCursorMigrateSkill, "gdh-migrate", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_UPDATE_SKILL_RELATIVE_PATH, renderCursorUpdateSkill, "gdh-update", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_CHECK_SKILL_RELATIVE_PATH, renderCursorCheckSkill, "gdh-check", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_PREPARE_SKILL_RELATIVE_PATH, renderCursorPrepareSkill, "gdh-prepare", pinnedVersion), planSkillInstallAction("cursor", targetPath, adapter, CURSOR_SCAN_SKILL_RELATIVE_PATH, renderCursorScanSkill, "gdh-scan", pinnedVersion));
2417
1591
  return actions;
2418
1592
  }
2419
1593
  function dedupeInstallActions(actions) {
@@ -2578,19 +1752,23 @@ export function renderManagedCodexProjectSection(pinnedVersion) {
2578
1752
  }
2579
1753
  export function renderManagedCodexProjectConfig(existingContent, pinnedVersion) {
2580
1754
  const section = renderManagedCodexProjectSection(pinnedVersion);
2581
- if (existingContent === null || existingContent.trim() === "") {
2582
- return `${section}\n`;
2583
- }
2584
- const lines = existingContent.split("\n");
1755
+ const withoutManagedHooks = removeManagedCodexAuthoringHookBlock(existingContent ?? "");
1756
+ const withFeature = ensureCodexHooksFeature(withoutManagedHooks);
1757
+ const withMcp = patchManagedCodexProjectSection(withFeature, section);
1758
+ return appendManagedCodexAuthoringHookBlock(withMcp);
1759
+ }
1760
+ function patchManagedCodexProjectSection(content, section) {
1761
+ const lines = content.split("\n");
2585
1762
  const sectionStart = lines.findIndex((line) => /^\[mcp_servers\.gdh\]\s*$/.test(line));
2586
1763
  if (sectionStart === -1) {
2587
- const trailingNewline = existingContent.endsWith("\n") ? "" : "\n";
2588
- const separator = existingContent.length > 0 ? "\n" : "";
2589
- return `${existingContent}${trailingNewline}${separator}${section}\n`;
1764
+ const trailingNewline = content.endsWith("\n") ? "" : "\n";
1765
+ const separator = content.length > 0 ? "\n" : "";
1766
+ return `${content}${trailingNewline}${separator}${section}\n`;
2590
1767
  }
2591
1768
  let sectionEnd = lines.length;
2592
1769
  for (let i = sectionStart + 1; i < lines.length; i++) {
2593
- if (/^\[/.test(lines[i] ?? "")) {
1770
+ if (/^\[/.test(lines[i] ?? "") ||
1771
+ /^# BEGIN GDH managed authoring hooks$/.test(lines[i] ?? "")) {
2594
1772
  sectionEnd = i;
2595
1773
  break;
2596
1774
  }
@@ -2603,6 +1781,62 @@ export function renderManagedCodexProjectConfig(existingContent, pinnedVersion)
2603
1781
  const afterJoin = afterNonEmpty.length > 0 ? `\n\n${afterNonEmpty}` : "\n";
2604
1782
  return `${beforeJoin}${section}${afterJoin}`;
2605
1783
  }
1784
+ function removeManagedCodexAuthoringHookBlock(content) {
1785
+ return content
1786
+ .replace(/(?:^|\n)# BEGIN GDH managed authoring hooks\n[\s\S]*?# END GDH managed authoring hooks\n?/, "\n")
1787
+ .replace(/\n{3,}/g, "\n\n")
1788
+ .trimEnd();
1789
+ }
1790
+ function appendManagedCodexAuthoringHookBlock(content) {
1791
+ const normalized = content.trimEnd();
1792
+ const separator = normalized.length > 0 ? "\n\n" : "";
1793
+ return `${normalized}${separator}${renderManagedCodexAuthoringHookBlock()}`;
1794
+ }
1795
+ function ensureCodexHooksFeature(content) {
1796
+ const lines = content.split("\n");
1797
+ const featuresStart = lines.findIndex((line) => /^\[features\]\s*$/.test(line));
1798
+ if (featuresStart === -1) {
1799
+ const separator = content.trim().length > 0 ? "\n\n" : "";
1800
+ return `${content}${separator}[features]\ncodex_hooks = true`;
1801
+ }
1802
+ let featuresEnd = lines.length;
1803
+ for (let i = featuresStart + 1; i < lines.length; i++) {
1804
+ if (/^\[/.test(lines[i] ?? "")) {
1805
+ featuresEnd = i;
1806
+ break;
1807
+ }
1808
+ }
1809
+ const featureLines = lines.slice(featuresStart, featuresEnd);
1810
+ const codexHooksIndex = featureLines.findIndex((line) => /^\s*codex_hooks\s*=/.test(line));
1811
+ if (codexHooksIndex === -1) {
1812
+ featureLines.push("codex_hooks = true");
1813
+ }
1814
+ else {
1815
+ featureLines[codexHooksIndex] = "codex_hooks = true";
1816
+ }
1817
+ return [...lines.slice(0, featuresStart), ...featureLines, ...lines.slice(featuresEnd)].join("\n");
1818
+ }
1819
+ function renderManagedCodexAuthoringHookBlock() {
1820
+ return [
1821
+ "# BEGIN GDH managed authoring hooks",
1822
+ "[[hooks.PostToolUse]]",
1823
+ 'matcher = "apply_patch|Edit|Write"',
1824
+ "[[hooks.PostToolUse.hooks]]",
1825
+ 'type = "command"',
1826
+ `command = ${JSON.stringify(CODEX_AUTHORING_HOOK_COMMAND)}`,
1827
+ "timeout = 30",
1828
+ 'statusMessage = "Checking GDH authoring edit"',
1829
+ "",
1830
+ "[[hooks.Stop]]",
1831
+ "[[hooks.Stop.hooks]]",
1832
+ 'type = "command"',
1833
+ `command = ${JSON.stringify(CODEX_AUTHORING_HOOK_COMMAND)}`,
1834
+ "timeout = 120",
1835
+ 'statusMessage = "Checking GDH final authoring validation"',
1836
+ "# END GDH managed authoring hooks",
1837
+ "",
1838
+ ].join("\n");
1839
+ }
2606
1840
  function extractManagedCodexSection(content) {
2607
1841
  const lines = content.split("\n");
2608
1842
  const start = lines.findIndex((line) => /^\[mcp_servers\.gdh\]\s*$/.test(line));
@@ -2611,7 +1845,8 @@ function extractManagedCodexSection(content) {
2611
1845
  }
2612
1846
  let end = lines.length;
2613
1847
  for (let i = start + 1; i < lines.length; i++) {
2614
- if (/^\[/.test(lines[i] ?? "")) {
1848
+ if (/^\[/.test(lines[i] ?? "") ||
1849
+ /^# BEGIN GDH managed authoring hooks$/.test(lines[i] ?? "")) {
2615
1850
  end = i;
2616
1851
  break;
2617
1852
  }
@@ -2888,7 +2123,7 @@ async function inspectRulesLifecycleSurface(targetPath, projectConfig) {
2888
2123
  surface: "rules_schema",
2889
2124
  management: "project_owned",
2890
2125
  state: "migration_needed",
2891
- summary: "Rules are missing from .gdh/rules.yaml, so done-policy and guidance enforcement are incomplete.",
2126
+ summary: "Rules are missing from .gdh/rules.yaml, so guidance enforcement is incomplete.",
2892
2127
  reasons: ["rules_missing"],
2893
2128
  probes,
2894
2129
  action: {
@@ -3771,6 +3006,7 @@ function normalizeChangedFiles(files) {
3771
3006
  }
3772
3007
  export { CLAUDE_STATUSLINE_RELATIVE_PATH } from "./claude-statusline-render.js";
3773
3008
  export { CLAUDE_CHECK_UPDATE_HOOK_RELATIVE_PATH } from "./claude-update-hook-render.js";
3009
+ export { CLAUDE_AUTHORING_HOOK_COMMAND, CLAUDE_AUTHORING_HOOK_RELATIVE_PATH, CODEX_AUTHORING_HOOK_COMMAND, CODEX_AUTHORING_HOOK_RELATIVE_PATH, } from "./authoring-hook-render.js";
3774
3010
  export { bumpAndRebakePin, } from "./self-update-mechanics.js";
3775
3011
  // Internal aggregator exposed for Wave 0 unit tests
3776
3012
  // (packages/adapters/src/lifecycle-compatibility.test.ts). Callers outside this