@haposoft/cafekit 0.16.7 → 0.18.1

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 (231) hide show
  1. package/README.md +14 -22
  2. package/bin/__tests__/codex-hooks-ownership.test.js +2 -2
  3. package/bin/__tests__/codex-hooks.test.js +169 -272
  4. package/bin/__tests__/codex-native.test.js +100 -202
  5. package/bin/__tests__/develop-contract.test.js +122 -1413
  6. package/bin/__tests__/docs-sync-on-demand.test.js +93 -0
  7. package/bin/__tests__/grok-envelope.test.js +0 -56
  8. package/bin/__tests__/hook-payload.test.js +4 -6
  9. package/bin/__tests__/legacy-authority-decoupled.test.js +154 -0
  10. package/bin/__tests__/legacy-hooks-retired.test.js +221 -0
  11. package/bin/__tests__/omp-bridge.test.js +20 -17
  12. package/bin/__tests__/omp-hooks.test.js +0 -19
  13. package/bin/__tests__/optional-skill-inventory.test.js +112 -4
  14. package/bin/__tests__/orca-session.test.js +0 -2
  15. package/bin/__tests__/package-inventory.test.js +90 -925
  16. package/bin/__tests__/runtime-dir.test.js +0 -3
  17. package/bin/__tests__/runtime-schema.test.js +3 -2
  18. package/bin/__tests__/skill-routing-source.test.js +27 -15
  19. package/bin/__tests__/spec-narrowing.test.js +30 -161
  20. package/bin/__tests__/specs-v2-execution-closeout.test.js +0 -437
  21. package/bin/__tests__/test-runtime-dependency-closure.cjs +1 -2
  22. package/bin/__tests__/ui-ux-skill.test.js +101 -0
  23. package/bin/__tests__/usage-hook-retired.test.js +114 -0
  24. package/bin/__tests__/validator-grounding.test.js +18 -2949
  25. package/bin/lib/managed-writer.js +2 -3
  26. package/bin/phases/codex-runtime.js +27 -0
  27. package/bin/phases/copy-payload.js +13 -28
  28. package/bin/phases/omp-runtime.js +25 -0
  29. package/package.json +2 -3
  30. package/src/claude/CLAUDE.md +3 -10
  31. package/src/claude/agents/brainstormer.md +7 -3
  32. package/src/claude/agents/code-auditor.md +44 -56
  33. package/src/claude/agents/debugger.md +8 -88
  34. package/src/claude/agents/deployer.md +3 -5
  35. package/src/claude/agents/docs-keeper.md +6 -14
  36. package/src/claude/agents/git-ops.md +2 -4
  37. package/src/claude/agents/implementer.md +12 -16
  38. package/src/claude/agents/inspector.md +4 -3
  39. package/src/claude/agents/project-manager.md +9 -17
  40. package/src/claude/agents/researcher.md +9 -3
  41. package/src/claude/agents/spec-maker.md +15 -15
  42. package/src/claude/agents/test-runner.md +8 -11
  43. package/src/claude/agents/ui-ux-designer.md +0 -1
  44. package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -1
  45. package/src/claude/hooks/__tests__/spec-gate.test.js +244 -333
  46. package/src/claude/hooks/__tests__/spec-state-touched.test.js +160 -0
  47. package/src/claude/hooks/__tests__/state.test.js +68 -0
  48. package/src/claude/hooks/__tests__/statusline.test.js +140 -11
  49. package/src/claude/hooks/agent.cjs +2 -1
  50. package/src/claude/hooks/lib/hook-payload.cjs +2 -2
  51. package/src/claude/hooks/rules.cjs +2 -1
  52. package/src/claude/hooks/session.cjs +0 -1
  53. package/src/claude/hooks/spec-gate.cjs +17 -83
  54. package/src/claude/hooks/spec-state.cjs +142 -39
  55. package/src/claude/hooks/state.cjs +21 -2
  56. package/src/claude/migration-manifest.json +42 -22
  57. package/src/claude/output-styles/coding-level-0-eli5.md +9 -9
  58. package/src/claude/output-styles/coding-level-1-junior.md +3 -3
  59. package/src/claude/output-styles/coding-level-2-mid.md +3 -3
  60. package/src/claude/output-styles/coding-level-3-senior.md +2 -2
  61. package/src/claude/output-styles/coding-level-4-lead.md +5 -5
  62. package/src/claude/output-styles/coding-level-5-god.md +6 -6
  63. package/src/claude/rules/ai-dev-rules.md +2 -3
  64. package/src/claude/rules/hook-protocols.md +8 -15
  65. package/src/claude/rules/manage-docs.md +9 -23
  66. package/src/claude/rules/orchestrator.md +3 -4
  67. package/src/claude/rules/review-audit-self-decision.md +3 -3
  68. package/src/claude/rules/skill-domain-routing.md +1 -3
  69. package/src/claude/rules/skill-workflow-routing.md +4 -5
  70. package/src/claude/rules/state-sync.md +3 -12
  71. package/src/claude/rules/workflow.md +11 -19
  72. package/src/claude/runtime.schema.json +5 -3
  73. package/src/claude/scripts/generate-skill-catalog.cjs +7 -6
  74. package/src/claude/scripts/provenance.cjs +23 -5
  75. package/src/claude/scripts/spec-receipt.cjs +24 -121
  76. package/src/claude/scripts/spec-resolver.cjs +41 -458
  77. package/src/claude/scripts/workflow-policy.cjs +3 -1801
  78. package/src/claude/settings/settings.json +1 -32
  79. package/src/claude/skills/agent-browser/SKILL.md +1 -1
  80. package/src/claude/skills/{question → ask}/SKILL.md +9 -75
  81. package/src/claude/skills/brainstorm/SKILL.md +43 -131
  82. package/src/claude/skills/chrome-devtools/SKILL.md +14 -31
  83. package/src/claude/skills/code-review/SKILL.md +29 -81
  84. package/src/claude/skills/code-review/references/spec-compliance-review.md +4 -8
  85. package/src/claude/skills/debug/SKILL.md +29 -149
  86. package/src/claude/skills/develop/SKILL.md +26 -83
  87. package/src/claude/skills/develop/references/parallel-waves.md +0 -8
  88. package/src/claude/skills/develop/references/quality-gate.md +15 -13
  89. package/src/claude/skills/develop/references/subagent-patterns.md +0 -6
  90. package/src/claude/skills/docs/SKILL.md +2 -2
  91. package/src/claude/skills/docs/references/update-workflow.md +1 -1
  92. package/src/claude/skills/fix/SKILL.md +153 -0
  93. package/src/claude/skills/{hotfix → fix}/references/diagnosis-protocol.md +2 -2
  94. package/src/claude/skills/{hotfix → fix}/references/parallel-patterns.md +2 -2
  95. package/src/claude/skills/{hotfix → fix}/references/prevention-gate.md +3 -3
  96. package/src/claude/skills/{hotfix → fix}/references/review-cycle.md +1 -1
  97. package/src/claude/skills/git/SKILL.md +48 -9
  98. package/src/claude/skills/git/references/commit-protocols.md +35 -16
  99. package/src/claude/skills/git/references/worktree-blueprint.md +42 -6
  100. package/src/claude/skills/orca/SKILL.md +9 -8
  101. package/src/claude/skills/research/SKILL.md +17 -46
  102. package/src/claude/skills/scout/SKILL.md +61 -0
  103. package/src/claude/skills/{inspect → scout}/references/internal-inspection.md +26 -10
  104. package/src/claude/skills/specs/SKILL.md +22 -29
  105. package/src/claude/skills/specs/references/review.md +8 -6
  106. package/src/claude/skills/specs/references/templates.md +34 -41
  107. package/src/claude/skills/sync/SKILL.md +16 -45
  108. package/src/claude/skills/sync/references/rebind-and-audit.md +59 -0
  109. package/src/claude/skills/sync/references/sync-protocols.md +4 -13
  110. package/src/claude/skills/test/SKILL.md +39 -104
  111. package/src/claude/skills/test/references/execution-strategy.md +93 -21
  112. package/src/claude/skills/test/references/failure-triage.md +1 -1
  113. package/src/claude/skills/ui-ux/LICENSE +21 -0
  114. package/src/claude/skills/ui-ux/SKILL.md +497 -0
  115. package/src/claude/skills/ui-ux/references/brand-tokens.md +90 -0
  116. package/src/claude/skills/ui-ux/references/budgets.md +113 -0
  117. package/src/claude/skills/ui-ux/references/checklist.md +271 -0
  118. package/src/claude/skills/ui-ux/references/components/accordion.md +246 -0
  119. package/src/claude/skills/ui-ux/references/components/avatar.md +153 -0
  120. package/src/claude/skills/ui-ux/references/components/banner.md +43 -0
  121. package/src/claude/skills/ui-ux/references/components/breadcrumb.md +201 -0
  122. package/src/claude/skills/ui-ux/references/components/button.md +142 -0
  123. package/src/claude/skills/ui-ux/references/components/card.md +113 -0
  124. package/src/claude/skills/ui-ux/references/components/charts.md +376 -0
  125. package/src/claude/skills/ui-ux/references/components/chat.md +132 -0
  126. package/src/claude/skills/ui-ux/references/components/choice-controls.md +369 -0
  127. package/src/claude/skills/ui-ux/references/components/comment-thread.md +17 -0
  128. package/src/claude/skills/ui-ux/references/components/description-list.md +116 -0
  129. package/src/claude/skills/ui-ux/references/components/empty-state.md +98 -0
  130. package/src/claude/skills/ui-ux/references/components/file-upload.md +107 -0
  131. package/src/claude/skills/ui-ux/references/components/inline-edit.md +128 -0
  132. package/src/claude/skills/ui-ux/references/components/input.md +161 -0
  133. package/src/claude/skills/ui-ux/references/components/list-row.md +56 -0
  134. package/src/claude/skills/ui-ux/references/components/loading.md +198 -0
  135. package/src/claude/skills/ui-ux/references/components/logo.md +147 -0
  136. package/src/claude/skills/ui-ux/references/components/otp-input.md +43 -0
  137. package/src/claude/skills/ui-ux/references/components/quantity-input.md +100 -0
  138. package/src/claude/skills/ui-ux/references/components/range-slider.md +16 -0
  139. package/src/claude/skills/ui-ux/references/components/small-controls.md +340 -0
  140. package/src/claude/skills/ui-ux/references/components/sortable-header.md +86 -0
  141. package/src/claude/skills/ui-ux/references/components/tag-input.md +14 -0
  142. package/src/claude/skills/ui-ux/references/components/timeline.md +38 -0
  143. package/src/claude/skills/ui-ux/references/components/tree.md +30 -0
  144. package/src/claude/skills/ui-ux/references/design-process.md +650 -0
  145. package/src/claude/skills/ui-ux/references/layouts/app-kanban.html +303 -0
  146. package/src/claude/skills/ui-ux/references/layouts/app.md +1369 -0
  147. package/src/claude/skills/ui-ux/references/layouts/form.md +430 -0
  148. package/src/claude/skills/ui-ux/references/layouts/overlay.md +552 -0
  149. package/src/claude/skills/ui-ux/references/layouts/pricing.md +204 -0
  150. package/src/claude/skills/ui-ux/references/locked-rules.md +35 -0
  151. package/src/claude/skills/ui-ux/references/principles.md +408 -0
  152. package/src/claude/skills/ui-ux/references/refactor.md +245 -0
  153. package/src/claude/skills/ui-ux/references/responsive.md +195 -0
  154. package/src/claude/skills/ui-ux/references/review.md +528 -0
  155. package/src/claude/skills/ui-ux/references/rules-color.md +623 -0
  156. package/src/claude/skills/ui-ux/references/rules-form.md +235 -0
  157. package/src/claude/skills/ui-ux/references/rules-state.md +680 -0
  158. package/src/claude/skills/ui-ux/references/rules-type.md +369 -0
  159. package/src/claude/skills/ui-ux/references/styles.md +311 -0
  160. package/src/claude/skills/ui-ux/references/system.md +219 -0
  161. package/src/claude/skills/ui-ux/references/tailwind-v4-traps.md +237 -0
  162. package/src/claude/skills/ui-ux/references/tokens.css +362 -0
  163. package/src/claude/skills/ui-ux/scripts/lint-skill.mjs +216 -0
  164. package/src/claude/skills/ui-ux/scripts/package.json +9 -0
  165. package/src/claude/skills/ui-ux/scripts/probe.mjs +4447 -0
  166. package/src/claude/skills/ui-ux-pro-max/SKILL.md +25 -80
  167. package/src/claude/skills/web-testing/SKILL.md +2 -20
  168. package/src/claude/status.cjs +149 -144
  169. package/src/codex/AGENTS.md +8 -13
  170. package/src/codex/hooks/agent.cjs +2 -1
  171. package/src/codex/hooks/lib/spec-receipt.cjs +4 -32
  172. package/src/codex/hooks/lib/spec-utils.cjs +6 -52
  173. package/src/codex/hooks/rules.cjs +2 -1
  174. package/src/codex/hooks/session.cjs +0 -2
  175. package/src/codex/hooks/spec-gate.cjs +13 -81
  176. package/src/codex/hooks/spec-state.cjs +37 -41
  177. package/src/codex/hooks.json +0 -20
  178. package/src/codex/rules/state-sync.md +3 -12
  179. package/src/common/AGENTS.md +6 -12
  180. package/src/omp/extensions/cafekit-bridge.mjs +6 -6
  181. package/bin/__tests__/change-firewall.semantic-firewall.test.js +0 -2133
  182. package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +0 -342
  183. package/bin/__tests__/release-preflight.semantic-firewall.test.js +0 -586
  184. package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +0 -378
  185. package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +0 -665
  186. package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +0 -1132
  187. package/src/claude/hooks/__tests__/completion-authority.test.js +0 -990
  188. package/src/claude/hooks/__tests__/semantic-review-authority.test.js +0 -259
  189. package/src/claude/hooks/completion-authority-check.cjs +0 -56
  190. package/src/claude/hooks/completion-authority-state.cjs +0 -527
  191. package/src/claude/hooks/completion-authority.cjs +0 -163
  192. package/src/claude/hooks/lib/context.cjs +0 -616
  193. package/src/claude/hooks/lib/detect.cjs +0 -474
  194. package/src/claude/hooks/semantic-review-authority.cjs +0 -154
  195. package/src/claude/hooks/task-scaffold-guard.cjs +0 -114
  196. package/src/claude/hooks/usage.cjs +0 -197
  197. package/src/claude/scripts/change-firewall.cjs +0 -1748
  198. package/src/claude/scripts/spec-authoring-digest.cjs +0 -151
  199. package/src/claude/scripts/spec-authoring-validation.cjs +0 -126
  200. package/src/claude/scripts/spec-final-state.cjs +0 -290
  201. package/src/claude/scripts/spec-ground.cjs +0 -650
  202. package/src/claude/scripts/spec-readiness.cjs +0 -425
  203. package/src/claude/scripts/spec-scaffold.cjs +0 -2317
  204. package/src/claude/scripts/spec-semantic-model.cjs +0 -396
  205. package/src/claude/scripts/validate-spec-output.cjs +0 -3941
  206. package/src/claude/skills/code-review/references/verification-gate.md +0 -46
  207. package/src/claude/skills/delegate/SKILL.md +0 -124
  208. package/src/claude/skills/delegate/references/codex-delegation.md +0 -71
  209. package/src/claude/skills/delegate/references/grok-delegation.md +0 -84
  210. package/src/claude/skills/hotfix/SKILL.md +0 -289
  211. package/src/claude/skills/inspect/SKILL.md +0 -142
  212. package/src/claude/skills/loop/SKILL.md +0 -114
  213. package/src/claude/skills/loop/references/bounded-loop-protocol.md +0 -104
  214. package/src/claude/skills/loop/references/metric-and-guard-contract.md +0 -76
  215. package/src/claude/skills/route/SKILL.md +0 -94
  216. package/src/claude/skills/route/references/agent-timing.md +0 -46
  217. package/src/claude/skills/route/references/chaining-patterns.md +0 -53
  218. package/src/claude/skills/route/references/task-taxonomy.md +0 -48
  219. package/src/claude/skills/specs/templates/design.md +0 -82
  220. package/src/claude/skills/specs/templates/requirements-init.md +0 -8
  221. package/src/claude/skills/specs/templates/requirements.md +0 -42
  222. package/src/claude/skills/specs/templates/spec-state.json +0 -56
  223. package/src/claude/skills/specs/templates/task.md +0 -47
  224. package/src/codex/hooks/completion-authority-check.cjs +0 -67
  225. package/src/codex/hooks/completion-authority-state.cjs +0 -527
  226. package/src/codex/hooks/completion-authority.cjs +0 -109
  227. package/src/codex/hooks/semantic-review-authority.cjs +0 -130
  228. package/src/codex/hooks/task-scaffold-guard.cjs +0 -63
  229. /package/src/claude/skills/{question → ask}/templates/question.md +0 -0
  230. /package/src/claude/skills/{hotfix → fix}/references/escalation-tactics.md +0 -0
  231. /package/src/claude/skills/{hotfix → fix}/references/workflow-specialized.md +0 -0
@@ -117,25 +117,6 @@ test('an unevaluable access denies rather than allows', () => {
117
117
  }
118
118
  });
119
119
 
120
- test('a write to a scaffolded task path is guarded under omp lowercase names too', () => {
121
- // The guard is no longer an overlay file, so this is a behaviour case on the tree an
122
- // install produces: omp sends `write`, and the shared reader has to make it reach the
123
- // rule that was authored against Claude's `Write`.
124
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'cafekit-omp-guard-'));
125
- try {
126
- const target = path.join(root, 'specs', 'demo', 'tasks', 'task-R0-01-x.md');
127
- fs.mkdirSync(path.dirname(target), { recursive: true });
128
- fs.cpSync(path.join(PACKAGE_ROOT, 'src/claude/scripts'), path.join(INSTALLED_ROOT, '.omp', 'scripts'),
129
- { recursive: true, force: true });
130
- const r = verdict(path.join(INSTALLED, 'task-scaffold-guard.cjs'),
131
- { tool_name: 'write', tool_input: { file_path: target }, cwd: root });
132
- assert.equal(r.code, 2, "omp sends `write`; an exact 'Write' comparison would skip the guard entirely");
133
- assert.equal(r.decision, 'deny');
134
- } finally {
135
- fs.rmSync(root, { recursive: true, force: true });
136
- }
137
- });
138
-
139
120
  /** Every file under a directory, relative and sorted. */
140
121
  function walk(dir, prefix = '') {
141
122
  return fs.readdirSync(dir).flatMap((name) => {
@@ -50,7 +50,7 @@ function silentUi() {
50
50
 
51
51
  test('manifest separates core, optional documents, and retired skills', () => {
52
52
  const manifest = loadClaudeMigrationManifest();
53
- assert.equal(manifest.skills.required.includes('route'), true);
53
+ assert.equal(manifest.skills.required.includes('route'), false);
54
54
  assert.deepEqual(manifest.skills.bundles.documentSkills, [
55
55
  'ai-multimodal', 'docs', 'docx', 'pdf', 'pptx', 'xlsx'
56
56
  ]);
@@ -59,7 +59,8 @@ test('manifest separates core, optional documents, and retired skills', () => {
59
59
  }
60
60
  assert.deepEqual(manifest.obsolete.skills, [
61
61
  'backend-development', 'frontend-development', 'frontend-design',
62
- 'mobile-development', 'devops', 'react-best-practices'
62
+ 'mobile-development', 'devops', 'react-best-practices',
63
+ 'inspect', 'hotfix', 'question', 'loop', 'route', 'delegate'
63
64
  ]);
64
65
  });
65
66
 
@@ -167,7 +168,7 @@ test('fresh combined install defaults optional bundle OFF', () => {
167
168
  for (const platformKey of ['claude', 'codex']) {
168
169
  const platform = PLATFORMS[platformKey];
169
170
  assert.equal(fs.existsSync(path.join(platform.skillsDir, 'docs')), false);
170
- assert.equal(fs.existsSync(path.join(platform.skillsDir, 'route', 'SKILL.md')), true);
171
+ assert.equal(fs.existsSync(path.join(platform.skillsDir, 'route', 'SKILL.md')), false);
171
172
  const metadata = JSON.parse(fs.readFileSync(path.join(platform.folder, 'cafekit.json'), 'utf8'));
172
173
  assert.equal(metadata.schemaVersion, 2);
173
174
  assert.equal(metadata.documentSkills.enabled, false);
@@ -193,7 +194,7 @@ test('explicit opt-in installs all six optional skills on both runtimes', () =>
193
194
  ], { cwd: root, encoding: 'utf8' });
194
195
  assert.equal(catalog.status, 0, catalog.stderr);
195
196
  const catalogData = JSON.parse(catalog.stdout);
196
- assert.equal(catalogData.skills.some((skill) => skill.public_id === 'cf:route'), true);
197
+ assert.equal(catalogData.skills.some((skill) => skill.public_id === 'cf:route'), false);
197
198
  assert.equal(catalogData.skills.some((skill) => skill.public_id === 'cf:docs'), true);
198
199
  const metadata = JSON.parse(fs.readFileSync(path.join(platform.folder, 'cafekit.json'), 'utf8'));
199
200
  assert.deepEqual(metadata.documentSkills, {
@@ -247,3 +248,110 @@ test('modified retired skill is preserved but excluded from automatic routing',
247
248
  item.directory === 'backend-development' && item.code === 'retired_skill'));
248
249
  });
249
250
  });
251
+
252
+ for (const platformKey of ['claude', 'codex']) {
253
+ test(`${platformKey} upgrade retires the inspect, hotfix and question directories`, () => {
254
+ withTempProject((root) => {
255
+ const platform = PLATFORMS[platformKey];
256
+ const recordRoot = platform.ownership?.recordRoot || platform.folder;
257
+ const key = (file) => path.relative(recordRoot, file).replace(/\\/g, '/');
258
+ const ownership = { schemaVersion: 1, version: 'old', files: {} };
259
+ for (const old of ['inspect', 'hotfix', 'question']) {
260
+ const file = path.join(platform.skillsDir, old, 'SKILL.md');
261
+ fs.mkdirSync(path.dirname(file), { recursive: true });
262
+ fs.writeFileSync(file, `pristine ${old}\n`);
263
+ ownership.files[key(file)] = { sha256: manifestLib.hashFile(file), version: 'old' };
264
+ }
265
+ const ctx = {
266
+ manifest: loadClaudeMigrationManifest(),
267
+ documentSkills: { [platformKey]: { enabled: true, selectionSource: 'cli-opt-in' } },
268
+ ownership: { [platform.folder]: ownership },
269
+ trackers: { [platformKey]: manifestLib.createTracker(platform.folder, 'next', platform.ownership) },
270
+ dryRun: false,
271
+ ui: silentUi(),
272
+ results: { updated: 0, preserved: 0, preservedFiles: [] }
273
+ };
274
+ reconcileSkillInventory(ctx, platformKey);
275
+ for (const old of ['inspect', 'hotfix', 'question']) {
276
+ assert.equal(fs.existsSync(path.join(root, platform.skillsDir, old)), false, old);
277
+ }
278
+ assert.equal(ctx.results.updated, 3);
279
+
280
+ // A user-modified retired copy survives with a warning, and the catalog serves cf:fix from fix/
281
+ // while marking the old directory retired rather than reporting a folder mismatch.
282
+ const edited = path.join(root, platform.skillsDir, 'hotfix', 'SKILL.md');
283
+ fs.mkdirSync(path.dirname(edited), { recursive: true });
284
+ fs.writeFileSync(edited, [
285
+ '---', `name: ${platformKey === 'codex' ? 'cf-fix' : 'cf:fix'}`,
286
+ 'description: "User-modified retired copy."', '---', '# Preserved', '',
287
+ ].join('\n'));
288
+ const result = spawnSync(process.execPath, [
289
+ installerPath, '--platform', platformKey, '--yes'
290
+ ], { cwd: root, encoding: 'utf8' });
291
+ assert.equal(result.status, 0, result.stderr || result.stdout);
292
+ assert.equal(fs.existsSync(edited), true);
293
+ assert.match(`${result.stdout}\n${result.stderr}`, /Preserved user-owned skill: .*hotfix/);
294
+ for (const renamed of ['scout', 'fix', 'ask']) {
295
+ assert.equal(fs.existsSync(path.join(root, platform.skillsDir, renamed, 'SKILL.md')), true, renamed);
296
+ }
297
+ const scriptRoot = platformKey === 'codex' ? '.codex' : '.claude';
298
+ const catalog = spawnSync(process.execPath, [
299
+ path.join(root, scriptRoot, 'scripts', 'generate-skill-catalog.cjs'), '--json'
300
+ ], { cwd: root, encoding: 'utf8' });
301
+ assert.equal(catalog.status, 0, catalog.stderr);
302
+ const parsed = JSON.parse(catalog.stdout);
303
+ for (const id of ['cf:scout', 'cf:fix', 'cf:ask']) {
304
+ assert.ok(parsed.skills.some((skill) => skill.public_id === id), id);
305
+ }
306
+ assert.equal(parsed.skills.find((skill) => skill.public_id === 'cf:fix').directory, 'fix');
307
+ assert.ok(parsed.diagnostics.some((item) => item.directory === 'hotfix' && item.code === 'retired_skill'));
308
+ assert.equal(parsed.diagnostics.some((item) => item.code === 'duplicate_public_name'), false);
309
+ });
310
+ });
311
+ }
312
+
313
+ for (const platformKey of ['claude', 'codex']) {
314
+ test(`${platformKey} upgrade retires the removed loop, route and delegate directories`, () => {
315
+ withTempProject((root) => {
316
+ const platform = PLATFORMS[platformKey];
317
+ const recordRoot = platform.ownership?.recordRoot || platform.folder;
318
+ const key = (file) => path.relative(recordRoot, file).replace(/\\/g, '/');
319
+ const ownership = { schemaVersion: 1, version: 'old', files: {} };
320
+ const removed = ['loop', 'route', 'delegate'];
321
+ for (const old of removed) {
322
+ const file = path.join(platform.skillsDir, old, 'SKILL.md');
323
+ fs.mkdirSync(path.dirname(file), { recursive: true });
324
+ fs.writeFileSync(file, `pristine ${old}\n`);
325
+ ownership.files[key(file)] = { sha256: manifestLib.hashFile(file), version: 'old' };
326
+ }
327
+ // A user-edited copy has no matching ownership hash, so it must survive the upgrade.
328
+ const edited = path.join(platform.skillsDir, 'route', 'references', 'my-notes.md');
329
+ fs.mkdirSync(path.dirname(edited), { recursive: true });
330
+ fs.writeFileSync(edited, 'user notes\n');
331
+ const ctx = {
332
+ manifest: loadClaudeMigrationManifest(),
333
+ documentSkills: { [platformKey]: { enabled: true, selectionSource: 'cli-opt-in' } },
334
+ ownership: { [platform.folder]: ownership },
335
+ trackers: { [platformKey]: manifestLib.createTracker(platform.folder, 'next', platform.ownership) },
336
+ dryRun: false,
337
+ ui: silentUi(),
338
+ results: { updated: 0, preserved: 0, preservedFiles: [] }
339
+ };
340
+ reconcileSkillInventory(ctx, platformKey);
341
+ assert.equal(fs.existsSync(path.join(root, platform.skillsDir, 'loop')), false, 'loop');
342
+ assert.equal(fs.existsSync(path.join(root, platform.skillsDir, 'delegate')), false, 'delegate');
343
+ assert.equal(fs.existsSync(path.join(root, edited)), true, 'user-edited route copy is preserved');
344
+ assert.equal(ctx.results.updated, 2);
345
+ assert.equal(ctx.results.preserved, 1);
346
+ });
347
+ });
348
+ }
349
+
350
+ test('the catalog retires exactly the directories the manifest retires', () => {
351
+ const source = fs.readFileSync(
352
+ path.resolve(__dirname, '..', '..', 'src', 'claude', 'scripts', 'generate-skill-catalog.cjs'), 'utf8');
353
+ const block = source.match(/const RETIRED_DIRECTORIES = new Set\(\[([\s\S]*?)\]\);/);
354
+ assert.ok(block, 'RETIRED_DIRECTORIES not found');
355
+ const retired = [...block[1].matchAll(/'([^']+)'/g)].map((match) => match[1]);
356
+ assert.deepEqual([...retired].sort(), [...loadClaudeMigrationManifest().obsolete.skills].sort());
357
+ });
@@ -145,8 +145,6 @@ function composeCodexHookTree(root) {
145
145
  const hooksDir = path.join(root, '.codex', 'hooks');
146
146
  fs.mkdirSync(path.join(hooksDir, 'lib'), { recursive: true });
147
147
  fs.copyFileSync(path.join(PACKAGE_ROOT, 'src/codex/hooks/session.cjs'), path.join(hooksDir, 'session.cjs'));
148
- fs.copyFileSync(path.join(PACKAGE_ROOT, 'src/codex/hooks/completion-authority-state.cjs'),
149
- path.join(hooksDir, 'completion-authority-state.cjs'));
150
148
  fs.copyFileSync(path.join(PACKAGE_ROOT, 'src/codex/hooks/lib/hook-context.cjs'),
151
149
  path.join(hooksDir, 'lib', 'hook-context.cjs'));
152
150
  fs.copyFileSync(path.join(PACKAGE_ROOT, 'src/codex/hooks/lib/privacy-state.cjs'),