@haposoft/cafekit 0.18.0 → 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 (83) hide show
  1. package/README.md +1 -1
  2. package/bin/__tests__/codex-hooks.test.js +169 -236
  3. package/bin/__tests__/codex-native.test.js +54 -114
  4. package/bin/__tests__/develop-contract.test.js +101 -1361
  5. package/bin/__tests__/legacy-authority-decoupled.test.js +14 -19
  6. package/bin/__tests__/package-inventory.test.js +1 -395
  7. package/bin/__tests__/spec-narrowing.test.js +30 -134
  8. package/bin/__tests__/specs-v2-execution-closeout.test.js +0 -372
  9. package/bin/__tests__/test-runtime-dependency-closure.cjs +1 -2
  10. package/bin/__tests__/validator-grounding.test.js +17 -2929
  11. package/bin/lib/managed-writer.js +2 -3
  12. package/bin/phases/codex-runtime.js +6 -3
  13. package/bin/phases/copy-payload.js +13 -28
  14. package/bin/phases/omp-runtime.js +6 -3
  15. package/package.json +2 -3
  16. package/src/claude/agents/code-auditor.md +9 -6
  17. package/src/claude/agents/debugger.md +3 -9
  18. package/src/claude/agents/docs-keeper.md +4 -7
  19. package/src/claude/agents/git-ops.md +2 -4
  20. package/src/claude/agents/implementer.md +6 -7
  21. package/src/claude/agents/inspector.md +2 -0
  22. package/src/claude/agents/project-manager.md +2 -2
  23. package/src/claude/agents/spec-maker.md +4 -4
  24. package/src/claude/agents/test-runner.md +8 -11
  25. package/src/claude/agents/ui-ux-designer.md +0 -1
  26. package/src/claude/hooks/__tests__/spec-gate.test.js +170 -330
  27. package/src/claude/hooks/__tests__/spec-state-touched.test.js +26 -0
  28. package/src/claude/hooks/spec-gate.cjs +8 -63
  29. package/src/claude/hooks/spec-state.cjs +47 -38
  30. package/src/claude/migration-manifest.json +12 -7
  31. package/src/claude/output-styles/coding-level-0-eli5.md +9 -9
  32. package/src/claude/output-styles/coding-level-1-junior.md +3 -3
  33. package/src/claude/output-styles/coding-level-2-mid.md +3 -3
  34. package/src/claude/output-styles/coding-level-3-senior.md +2 -2
  35. package/src/claude/output-styles/coding-level-4-lead.md +5 -5
  36. package/src/claude/output-styles/coding-level-5-god.md +6 -6
  37. package/src/claude/rules/ai-dev-rules.md +1 -2
  38. package/src/claude/rules/workflow.md +1 -1
  39. package/src/claude/scripts/spec-receipt.cjs +0 -114
  40. package/src/claude/scripts/spec-resolver.cjs +41 -457
  41. package/src/claude/scripts/workflow-policy.cjs +3 -1801
  42. package/src/claude/skills/agent-browser/SKILL.md +1 -1
  43. package/src/claude/skills/chrome-devtools/SKILL.md +14 -31
  44. package/src/claude/skills/code-review/SKILL.md +25 -108
  45. package/src/claude/skills/code-review/references/spec-compliance-review.md +4 -7
  46. package/src/claude/skills/develop/SKILL.md +22 -70
  47. package/src/claude/skills/develop/references/subagent-patterns.md +0 -6
  48. package/src/claude/skills/research/SKILL.md +24 -55
  49. package/src/claude/skills/sync/SKILL.md +12 -34
  50. package/src/claude/skills/sync/references/rebind-and-audit.md +2 -2
  51. package/src/claude/skills/test/SKILL.md +39 -123
  52. package/src/claude/skills/test/references/execution-strategy.md +11 -22
  53. package/src/claude/skills/ui-ux/SKILL.md +1 -1
  54. package/src/claude/skills/ui-ux-pro-max/SKILL.md +24 -79
  55. package/src/claude/skills/web-testing/SKILL.md +2 -20
  56. package/src/codex/hooks/lib/spec-receipt.cjs +2 -30
  57. package/src/codex/hooks/lib/spec-utils.cjs +6 -45
  58. package/src/codex/hooks/spec-gate.cjs +11 -68
  59. package/src/codex/hooks/spec-state.cjs +37 -41
  60. package/src/common/AGENTS.md +4 -10
  61. package/bin/__tests__/change-firewall.semantic-firewall.test.js +0 -2133
  62. package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +0 -342
  63. package/bin/__tests__/release-preflight.semantic-firewall.test.js +0 -586
  64. package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +0 -378
  65. package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +0 -665
  66. package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +0 -1132
  67. package/src/claude/hooks/lib/context.cjs +0 -527
  68. package/src/claude/hooks/lib/detect.cjs +0 -474
  69. package/src/claude/scripts/change-firewall.cjs +0 -1748
  70. package/src/claude/scripts/spec-authoring-digest.cjs +0 -151
  71. package/src/claude/scripts/spec-authoring-validation.cjs +0 -126
  72. package/src/claude/scripts/spec-final-state.cjs +0 -290
  73. package/src/claude/scripts/spec-ground.cjs +0 -650
  74. package/src/claude/scripts/spec-readiness.cjs +0 -425
  75. package/src/claude/scripts/spec-scaffold.cjs +0 -2317
  76. package/src/claude/scripts/spec-semantic-model.cjs +0 -396
  77. package/src/claude/scripts/validate-spec-output.cjs +0 -3914
  78. package/src/claude/skills/code-review/references/verification-gate.md +0 -41
  79. package/src/claude/skills/specs/templates/design.md +0 -82
  80. package/src/claude/skills/specs/templates/requirements-init.md +0 -8
  81. package/src/claude/skills/specs/templates/requirements.md +0 -42
  82. package/src/claude/skills/specs/templates/spec-state.json +0 -56
  83. package/src/claude/skills/specs/templates/task.md +0 -47
@@ -40,7 +40,28 @@ try {
40
40
  const RECEIPT = receiptLoaded.receipt;
41
41
  const { projectRoot, runtime } = getHookContext(payload);
42
42
  if (runtime.spec?.tollgate === false) process.exit(0);
43
- const { resolveWorkflowCandidate } = require('./lib/spec-utils.cjs');
43
+ const { findLegacyPackets, resolveWorkflowCandidate } = require('./lib/spec-utils.cjs');
44
+ const sessionId = payload.session_id || payload.sessionId || payload.sessionID || payload.session?.id;
45
+ // A legacy packet (a specs/<x>/ directory without plan.md that the old flow left
46
+ // behind) is no longer read. Say so once per session instead of on every prompt.
47
+ const legacyPackets = findLegacyPackets(projectRoot, runtime);
48
+ if (legacyPackets.length > 0) {
49
+ const noticeFile = sessionId
50
+ ? path.join(hookStateDir(projectRoot), `legacy-notice-${crypto.createHash('sha256').update(String(sessionId)).digest('hex').slice(0, 16)}.json`)
51
+ : null;
52
+ let noticed = [];
53
+ if (noticeFile) {
54
+ try { noticed = JSON.parse(fs.readFileSync(noticeFile, 'utf8')); } catch { noticed = []; }
55
+ if (!Array.isArray(noticed)) noticed = [];
56
+ }
57
+ const fresh = legacyPackets.filter((name) => !noticed.includes(name));
58
+ for (const name of fresh) {
59
+ process.stdout.write(`> ⚠️ \`specs/${name}\` is a legacy Specs packet without plan.md; CafeKit no longer reads it. Move ongoing work to a process-first plan.md packet.\n`);
60
+ }
61
+ if (noticeFile && fresh.length > 0) {
62
+ try { atomicWrite(noticeFile, `${JSON.stringify([...noticed, ...fresh].sort())}\n`); } catch { /* repeats the notice */ }
63
+ }
64
+ }
44
65
  const explicitFeature = payload.featureName || payload.feature || payload.explicitFeature || null;
45
66
  const explicitPath = payload.specPath || payload.spec_path || payload.featurePath || null;
46
67
  const resolved = resolveWorkflowCandidate(projectRoot, runtime, explicitFeature, explicitPath);
@@ -50,7 +71,7 @@ try {
50
71
  process.exit(0);
51
72
  }
52
73
  if (resolved.error === 'invalid_specs') {
53
- process.stdout.write(`> ⚠️ Invalid spec JSON detected: ${resolved.candidates.join(', ')}. ${resolved.reason}. Fix or remove malformed spec.json. Tollgate paused.\n`);
74
+ process.stdout.write(`> ⚠️ Invalid workflow packet detected: ${resolved.candidates.join(', ')}. ${resolved.reason}. Fix the packet's plan.md or task files. Tollgate paused.\n`);
54
75
  process.exit(0);
55
76
  }
56
77
  if (resolved.error === 'explicit_not_found' || resolved.error === 'explicit_malformed') {
@@ -60,18 +81,16 @@ try {
60
81
  }
61
82
  if (resolved.error) process.exit(0);
62
83
  const active = resolved;
63
- const processWorkflow = active.layoutKind === 'process-v3';
64
84
  const runtimeContext = POLICY.deriveRuntimeContext({
65
85
  projectRoot,
66
86
  specsRoot: active.specsDir,
67
- specFile: active.stateFile || active.specFile || path.join(active.specsDir, active.featureName, 'spec.json'),
87
+ specFile: active.stateFile,
68
88
  featureName: active.featureName,
69
- runtimeSession: payload.session_id || payload.sessionId || payload.sessionID || payload.session?.id,
89
+ runtimeSession: sessionId,
70
90
  });
71
91
 
72
- const phase = active.phase || active.spec?.current_phase || active.spec?.phase || 'unknown';
73
- const taskRegistry = active.taskRegistry || active.spec?.task_registry || {};
74
- const flashTasks = POLICY.flashState(taskRegistry);
92
+ const phase = active.phase || 'unknown';
93
+ const taskRegistry = active.taskRegistry || {};
75
94
  const tasks = Object.entries(taskRegistry);
76
95
  const counts = tasks.reduce((result, [, task]) => {
77
96
  const status = task?.status || 'pending';
@@ -79,13 +98,7 @@ try {
79
98
  return result;
80
99
  }, {});
81
100
  const featureDir = path.join(active.specsDir, active.featureName);
82
- const statuses = new Map(tasks.map(([taskPath, task]) => [
83
- taskPath,
84
- task?.status || 'pending'
85
- ]));
86
- const dependencyProof = processWorkflow
87
- ? RECEIPT.workflowDependencyProofState(featureDir, taskRegistry, runtimeContext, POLICY)
88
- : {};
101
+ const dependencyProof = RECEIPT.workflowDependencyProofState(featureDir, taskRegistry, runtimeContext, POLICY);
89
102
  const taskState = tasks.map(([taskPath, task]) => [
90
103
  taskPath,
91
104
  task?.status || 'pending',
@@ -101,12 +114,8 @@ try {
101
114
  const next = tasks.find(([, task]) => (
102
115
  active.queueReady !== false
103
116
  && (task?.status || 'pending') === 'pending'
104
- && (task?.dependencies || []).every((dependency) => (
105
- processWorkflow ? dependencyProof[dependency]?.eligible === true : statuses.get(dependency) === 'done'
106
- ))
117
+ && (task?.dependencies || []).every((dependency) => dependencyProof[dependency]?.eligible === true)
107
118
  ));
108
- const featureReceiptPresent = !processWorkflow
109
- && RECEIPT.safeRead(featureDir, 'feature-receipt.md').status === 'ok';
110
119
  const stateKey = JSON.stringify({
111
120
  project_root: runtimeContext.project_root,
112
121
  specs_root: runtimeContext.specs_root,
@@ -124,14 +133,13 @@ try {
124
133
  proof_state: proofState,
125
134
  done: counts.done || 0,
126
135
  total: tasks.length,
127
- feature_receipt_present: featureReceiptPresent,
128
136
  });
129
137
  const cache = cacheFile(projectRoot, runtimeContext.runtime_session);
130
138
  let previous = '';
131
139
  try { previous = fs.readFileSync(cache, 'utf8').trim(); } catch { /* first run */ }
132
140
 
133
141
  if (previous === stateKey) {
134
- const migration = processWorkflow && active.queueReady === false
142
+ const migration = active.queueReady === false
135
143
  ? ' Add `Specs-Contract: process-first-ready-v1` after the plan title before tasks can enter Next.'
136
144
  : '';
137
145
  process.stdout.write(
@@ -147,26 +155,14 @@ try {
147
155
  `- Phase: \`${phase}\` | Tasks: ${counts.done || 0} done / ${tasks.length} total`
148
156
  ];
149
157
  if (next) lines.push(`- Next unblocked: \`${next[0]}\``);
150
- if (flashTasks.length > 0) {
151
- lines.push(`- Flash verification pending: ${flashTasks.map((taskPath) => `\`${taskPath}\``).join(', ')}. A PASS proof keeps the persisted task in_progress until explicit sync-finalize.`);
152
- }
153
- if (processWorkflow) {
154
- if (active.queueReady === false) {
155
- lines.push('- Migration required: add `Specs-Contract: process-first-ready-v1` after the plan title before tasks can enter Next.');
156
- }
157
- lines.push(
158
- '- Sync each flat task `Status:` only after verified work; task proof belongs in that task\'s inline `## Receipt`.',
159
- `- Workflow source: \`specs/${active.featureName}/plan.md\`; Stop re-checks every done receipt, binding Base/Head to the runtime only while a committed task file no longer matches its committed bytes.`,
160
- '- Hooks revalidate receipt bytes but never grant approval.'
161
- );
162
- } else {
163
- lines.push(
164
- '- Sync `spec.json` and task Markdown status only after verified work; task proof belongs in `receipts/<task-basename>.md`.',
165
- `- Create \`feature-receipt.md\` once after final integration proof${featureReceiptPresent ? ' (present)' : ' (not required before closeout)'}.`,
166
- `- Validate with \`node .codex/scripts/validate-spec-output.cjs specs/${active.featureName}\`.`,
167
- '- Hooks revalidate receipt bytes but never grant approval.'
168
- );
158
+ if (active.queueReady === false) {
159
+ lines.push('- Migration required: add `Specs-Contract: process-first-ready-v1` after the plan title before tasks can enter Next.');
169
160
  }
161
+ lines.push(
162
+ '- Sync each flat task `Status:` only after verified work; task proof belongs in that task\'s inline `## Receipt`.',
163
+ `- Workflow source: \`specs/${active.featureName}/plan.md\`; Stop re-checks every done receipt, binding Base/Head to the runtime only while a committed task file no longer matches its committed bytes.`,
164
+ '- Hooks revalidate receipt bytes but never grant approval.'
165
+ );
170
166
  process.stdout.write(`${lines.join('\n')}\n`);
171
167
  } catch (error) {
172
168
  logCrash('spec-state', error);
@@ -33,17 +33,11 @@ Do the work yourself when it takes a handful of tool calls. Delegate genuinely i
33
33
  - Runtime-specific instructions live in that runtime's own managed block, not in `CORE`.
34
34
  - In a combined install, consume `CORE` plus your native block only. Ignore managed blocks not owned by your runtime. If ownership is unclear, treat the file as `CORE`-only (fail-safe).
35
35
 
36
- ## Commands
36
+ ## Project notes
37
37
 
38
- <!-- Add project-specific install, test, lint, and build commands here. Keep commands executable. -->
39
-
40
- ## Do not touch
41
-
42
- <!-- List files, directories, generated artifacts, or secrets that tasks must leave unchanged. -->
43
-
44
- ## Slow or expensive
45
-
46
- <!-- Note commands, environments, or operations that need explicit planning before running. -->
38
+ Write project-specific commands, files tasks must leave unchanged, and slow or
39
+ expensive operations after the `CAFEKIT CORE END` marker. Everything between the
40
+ CafeKit markers is replaced on every install.
47
41
 
48
42
  ## Language Consistency <!-- cafekit:lang -->
49
43