@haposoft/cafekit 0.16.0-rc.6 → 0.16.0-rc.8

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 (87) hide show
  1. package/README.md +21 -58
  2. package/bin/__tests__/change-firewall.semantic-firewall.test.js +4 -5
  3. package/bin/__tests__/codex-hooks.test.js +382 -0
  4. package/bin/__tests__/codex-native.test.js +579 -80
  5. package/bin/__tests__/develop-contract.test.js +155 -76
  6. package/bin/__tests__/installer-safety.test.js +19 -154
  7. package/bin/__tests__/package-inventory.test.js +494 -26
  8. package/bin/__tests__/release-preflight.semantic-firewall.test.js +2 -2
  9. package/bin/__tests__/validator-grounding.test.js +11 -11
  10. package/bin/install.js +2 -7
  11. package/bin/lib/context.js +0 -45
  12. package/bin/lib/copy-utils.js +1 -1
  13. package/bin/lib/i18n.js +0 -3
  14. package/bin/lib/manifest.js +1 -1
  15. package/bin/phases/claude-runtime.js +1 -3
  16. package/bin/phases/codex-runtime.js +4 -2
  17. package/bin/phases/copy-payload.js +3 -15
  18. package/bin/phases/post-install.js +5 -17
  19. package/bin/phases/root-config.js +2 -3
  20. package/bin/phases/select-platform.js +2 -5
  21. package/bin/phases/summary.js +0 -1
  22. package/package.json +2 -5
  23. package/src/claude/CLAUDE.md +19 -6
  24. package/src/claude/agents/project-manager.md +41 -9
  25. package/src/claude/agents/spec-maker.md +82 -155
  26. package/src/claude/gitignore +1 -1
  27. package/src/claude/hooks/__tests__/spec-gate.test.js +238 -0
  28. package/src/claude/hooks/__tests__/state.test.js +249 -3
  29. package/src/claude/hooks/lib/context.cjs +1 -1
  30. package/src/claude/hooks/lib/detect.cjs +1 -1
  31. package/src/claude/hooks/spec-gate.cjs +44 -9
  32. package/src/claude/hooks/spec-state.cjs +51 -13
  33. package/src/claude/hooks/task-scaffold-guard.cjs +1 -1
  34. package/src/claude/migration-manifest.json +17 -3
  35. package/src/claude/rules/manage-docs.md +43 -24
  36. package/src/claude/rules/state-sync.md +57 -62
  37. package/src/claude/rules/workflow.md +30 -13
  38. package/src/claude/scripts/change-firewall.cjs +2 -2
  39. package/src/claude/scripts/generate-skill-catalog.cjs +0 -1
  40. package/src/claude/scripts/spec-receipt.cjs +196 -1
  41. package/src/claude/scripts/spec-resolver.cjs +428 -0
  42. package/src/claude/skills/develop/SKILL.md +89 -125
  43. package/src/claude/skills/develop/references/parallel-waves.md +75 -162
  44. package/src/claude/skills/develop/references/quality-gate.md +61 -121
  45. package/src/claude/skills/develop/references/subagent-patterns.md +31 -38
  46. package/src/claude/skills/question/SKILL.md +1 -1
  47. package/src/claude/skills/specs/SKILL.md +152 -204
  48. package/src/claude/skills/specs/references/review.md +124 -243
  49. package/src/claude/skills/specs/references/templates.md +202 -0
  50. package/src/claude/skills/sync/SKILL.md +66 -90
  51. package/src/claude/skills/sync/references/sync-protocols.md +62 -83
  52. package/src/codex/AGENTS.md +20 -7
  53. package/src/codex/hooks/lib/spec-receipt.cjs +18 -0
  54. package/src/codex/hooks/lib/spec-utils.cjs +25 -0
  55. package/src/codex/hooks/spec-gate.cjs +46 -16
  56. package/src/codex/hooks/spec-state.cjs +54 -16
  57. package/src/codex/rules/state-sync.md +57 -61
  58. package/src/common/AGENTS.md +8 -1
  59. package/bin/__tests__/opencode-spec-gate.test.js +0 -799
  60. package/bin/lib/opencode-install.js +0 -899
  61. package/bin/phases/opencode-runtime.js +0 -38
  62. package/src/claude/skills/specs/references/archive-workflow.md +0 -74
  63. package/src/claude/skills/specs/references/ask-user-question-gates.md +0 -70
  64. package/src/claude/skills/specs/references/codebase-analysis.md +0 -102
  65. package/src/claude/skills/specs/references/cross-spec-dependency.md +0 -76
  66. package/src/claude/skills/specs/references/research-strategy.md +0 -107
  67. package/src/claude/skills/specs/references/scope-inquiry.md +0 -107
  68. package/src/claude/skills/specs/references/translation-mirror.md +0 -83
  69. package/src/claude/skills/specs/rules/design-discovery-full.md +0 -45
  70. package/src/claude/skills/specs/rules/design-discovery-light.md +0 -28
  71. package/src/claude/skills/specs/rules/design-principles.md +0 -138
  72. package/src/claude/skills/specs/rules/design-review.md +0 -55
  73. package/src/claude/skills/specs/rules/ears-format.md +0 -42
  74. package/src/claude/skills/specs/rules/phase-decision-matrix.md +0 -56
  75. package/src/claude/skills/specs/rules/task-scoring-rubric.md +0 -52
  76. package/src/claude/skills/specs/rules/tasks-generation.md +0 -189
  77. package/src/opencode/AGENTS.md +0 -41
  78. package/src/opencode/plugins/docs-sync.ts +0 -175
  79. package/src/opencode/plugins/inspect-block.ts +0 -164
  80. package/src/opencode/plugins/privacy-block.ts +0 -182
  81. package/src/opencode/plugins/rules.ts +0 -155
  82. package/src/opencode/plugins/session.ts +0 -179
  83. package/src/opencode/plugins/spec-gate.ts +0 -457
  84. package/src/opencode/plugins/spec-state.ts +0 -311
  85. package/src/opencode/plugins/state.ts +0 -253
  86. package/src/opencode/plugins/task-scaffold-guard.ts +0 -161
  87. package/src/opencode/plugins/usage.ts +0 -178
@@ -39,10 +39,10 @@ try {
39
39
  const RECEIPT = receiptLoaded.receipt;
40
40
  const { projectRoot, runtime } = getHookContext(payload);
41
41
  if (runtime.spec?.tollgate === false) process.exit(0);
42
- const { resolveActiveSpec } = require('./lib/spec-utils.cjs');
42
+ const { resolveWorkflowCandidate } = require('./lib/spec-utils.cjs');
43
43
  const explicitFeature = payload.featureName || payload.feature || payload.explicitFeature || null;
44
44
  const explicitPath = payload.specPath || payload.spec_path || payload.featurePath || null;
45
- const resolved = resolveActiveSpec(projectRoot, runtime, explicitFeature, explicitPath);
45
+ const resolved = resolveWorkflowCandidate(projectRoot, runtime, explicitFeature, explicitPath);
46
46
  if (!resolved) process.exit(0);
47
47
  if (resolved.error === 'multiple_active') {
48
48
  process.stdout.write(`> ⚠️ Multiple active specs detected: ${resolved.candidates.join(', ')}. Provide explicit feature target or resolve ambiguity. Tollgate paused.\n`);
@@ -59,16 +59,17 @@ try {
59
59
  }
60
60
  if (resolved.error) process.exit(0);
61
61
  const active = resolved;
62
+ const processWorkflow = active.layoutKind === 'process-v3';
62
63
  const runtimeContext = POLICY.deriveRuntimeContext({
63
64
  projectRoot,
64
65
  specsRoot: active.specsDir,
65
- specFile: active.specFile || path.join(active.specsDir, active.featureName, 'spec.json'),
66
+ specFile: active.stateFile || active.specFile || path.join(active.specsDir, active.featureName, 'spec.json'),
66
67
  featureName: active.featureName,
67
68
  runtimeSession: payload.session_id || payload.sessionId || payload.sessionID || payload.session?.id,
68
69
  });
69
70
 
70
- const phase = active.spec.current_phase || active.spec.phase || 'unknown';
71
- const taskRegistry = active.spec.task_registry || {};
71
+ const phase = active.phase || active.spec?.current_phase || active.spec?.phase || 'unknown';
72
+ const taskRegistry = active.taskRegistry || active.spec?.task_registry || {};
72
73
  const flashTasks = POLICY.flashState(taskRegistry);
73
74
  const tasks = Object.entries(taskRegistry);
74
75
  const counts = tasks.reduce((result, [, task]) => {
@@ -76,16 +77,35 @@ try {
76
77
  result[status] = (result[status] || 0) + 1;
77
78
  return result;
78
79
  }, {});
80
+ const featureDir = path.join(active.specsDir, active.featureName);
79
81
  const statuses = new Map(tasks.map(([taskPath, task]) => [
80
82
  taskPath,
81
83
  task?.status || 'pending'
82
84
  ]));
85
+ const dependencyProof = processWorkflow
86
+ ? RECEIPT.workflowDependencyProofState(featureDir, taskRegistry, runtimeContext, POLICY)
87
+ : {};
88
+ const taskState = tasks.map(([taskPath, task]) => [
89
+ taskPath,
90
+ task?.status || 'pending',
91
+ [...(Array.isArray(task?.dependencies) ? task.dependencies : [])].sort(),
92
+ ]).sort(([left], [right]) => left.localeCompare(right));
93
+ const proofState = Object.entries(dependencyProof).map(([taskPath, proof]) => [
94
+ taskPath,
95
+ proof.done,
96
+ proof.valid,
97
+ proof.eligible,
98
+ proof.signature,
99
+ ]);
83
100
  const next = tasks.find(([, task]) => (
84
- (task?.status || 'pending') === 'pending'
85
- && (task?.dependencies || []).every((dependency) => statuses.get(dependency) === 'done')
101
+ active.queueReady !== false
102
+ && (task?.status || 'pending') === 'pending'
103
+ && (task?.dependencies || []).every((dependency) => (
104
+ processWorkflow ? dependencyProof[dependency]?.eligible === true : statuses.get(dependency) === 'done'
105
+ ))
86
106
  ));
87
- const featureDir = path.join(active.specsDir, active.featureName);
88
- const featureReceiptPresent = RECEIPT.safeRead(featureDir, 'feature-receipt.md').status === 'ok';
107
+ const featureReceiptPresent = !processWorkflow
108
+ && RECEIPT.safeRead(featureDir, 'feature-receipt.md').status === 'ok';
89
109
  const stateKey = JSON.stringify({
90
110
  project_root: runtimeContext.project_root,
91
111
  specs_root: runtimeContext.specs_root,
@@ -97,6 +117,10 @@ try {
97
117
  Head: runtimeContext.head,
98
118
  context_id: runtimeContext.context_id,
99
119
  phase,
120
+ workflow_contract: active.workflowContract || null,
121
+ queue_ready: active.queueReady !== false,
122
+ task_state: taskState,
123
+ proof_state: proofState,
100
124
  done: counts.done || 0,
101
125
  total: tasks.length,
102
126
  feature_receipt_present: featureReceiptPresent,
@@ -106,9 +130,12 @@ try {
106
130
  try { previous = fs.readFileSync(cache, 'utf8').trim(); } catch { /* first run */ }
107
131
 
108
132
  if (previous === stateKey) {
133
+ const migration = processWorkflow && active.queueReady === false
134
+ ? ' Add `Specs-Contract: process-first-ready-v1` after the plan title before tasks can enter Next.'
135
+ : '';
109
136
  process.stdout.write(
110
137
  `> Spec \`${active.featureName}\` @ \`${phase}\` `
111
- + `(${counts.done || 0}/${tasks.length} tasks done). Tollgate active.\n`
138
+ + `(${counts.done || 0}/${tasks.length} tasks done). Tollgate active.${migration}\n`
112
139
  );
113
140
  process.exit(0);
114
141
  }
@@ -122,12 +149,23 @@ try {
122
149
  if (flashTasks.length > 0) {
123
150
  lines.push(`- Flash verification pending: ${flashTasks.map((taskPath) => `\`${taskPath}\``).join(', ')}. A PASS proof keeps the persisted task in_progress until explicit sync-finalize.`);
124
151
  }
125
- lines.push(
126
- '- Sync `spec.json` and task Markdown status only after verified work; task proof belongs in `receipts/<task-basename>.md`.',
127
- `- Create \`feature-receipt.md\` once after final integration proof${featureReceiptPresent ? ' (present)' : ' (not required before closeout)'}.`,
128
- `- Validate with \`node .codex/scripts/validate-spec-output.cjs specs/${active.featureName}\`.`,
129
- '- Hooks revalidate receipt bytes but never grant approval.'
130
- );
152
+ if (processWorkflow) {
153
+ if (active.queueReady === false) {
154
+ lines.push('- Migration required: add `Specs-Contract: process-first-ready-v1` after the plan title before tasks can enter Next.');
155
+ }
156
+ lines.push(
157
+ '- Sync each flat task `Status:` only after verified work; task proof belongs in that task\'s inline `## Receipt`.',
158
+ `- Workflow source: \`specs/${active.featureName}/plan.md\`; Stop revalidates every task currently marked done.`,
159
+ '- Hooks revalidate receipt bytes but never grant approval.'
160
+ );
161
+ } else {
162
+ lines.push(
163
+ '- Sync `spec.json` and task Markdown status only after verified work; task proof belongs in `receipts/<task-basename>.md`.',
164
+ `- Create \`feature-receipt.md\` once after final integration proof${featureReceiptPresent ? ' (present)' : ' (not required before closeout)'}.`,
165
+ `- Validate with \`node .codex/scripts/validate-spec-output.cjs specs/${active.featureName}\`.`,
166
+ '- Hooks revalidate receipt bytes but never grant approval.'
167
+ );
168
+ }
131
169
  process.stdout.write(`${lines.join('\n')}\n`);
132
170
  } catch (error) {
133
171
  logCrash('spec-state', error);
@@ -1,61 +1,57 @@
1
- # Specs v2.1 state synchronization
2
-
3
- ## Authority layers
4
-
5
- `spec.json` is machine semantic authority. Requirements, design, conditional
6
- research, and conditional task Markdown are human projections. Host state may
7
- record authority or integrity, but it never supplies product semantics.
8
-
9
- Planning depth and assurance level remain independent. Route artifacts before
10
- discovery: None persists no spec; Compact and Full persist the bounded core;
11
- research and tasks remain absent unless their semantic triggers exist.
12
-
13
- ## Canonical lifecycle
14
-
15
- The feature lifecycle is exactly `in_progress`, `paused`, `blocked`, or `done`.
16
- Authoring state is independently `draft`, `validated`, or `absent`. New 2.1
17
- artifacts never emit legacy lifecycle aliases.
18
-
19
- Technical readiness is not lifecycle completion. `ready_for_implementation`
20
- may change only through the installed machine finalization path after every
21
- routed artifact, projection, semantic review, grounding check, and deterministic
22
- gate passes. The author cannot directly declare readiness, authority, approval,
23
- review capability, execution proof, or closeout.
24
-
25
- ## Projection sync
26
-
27
- After a semantic Markdown edit:
28
-
29
- 1. invoke the explicit installed machine semantic-sync step to promote `semantic_model`;
30
- 2. regenerate or reconcile every affected Markdown projection;
31
- 3. verify requirements, decisions, anchors, task registry, typed boundaries,
32
- and verification refs round-trip without loss; and
33
- 4. rerun applicable deterministic validation and grounding checks.
34
-
35
- For Codex, the isolated promotion is
36
- `node .codex/scripts/spec-scaffold.cjs <feature> --sync-semantic-model`.
37
-
38
- Task Markdown exists only for typed ownership, dependency, transition, proof,
39
- or parallel topology. Its status and dependencies project the matching
40
- `task_registry` entry. Its Verification Plan is prospective, never execution
41
- proof. Typed `coordination.boundaries` alone define topology; legacy trigger
42
- fields, priority markers, related-file lists, and prose do not.
43
-
44
- ## Lifecycle updates
45
-
46
- - Active work uses `in_progress`.
47
- - A deliberate resumable stop uses `paused` with the exact remaining decision.
48
- - An external or semantic blocker uses `blocked` with a concrete cause.
49
- - Task state changes update the registry and matching projection together only
50
- from observed work and verification.
51
- - Feature `done` is reserved for final-state authority after implementation
52
- closeout; authoring or readiness cannot produce it.
53
-
54
- State synchronization never fabricates commands, PASS results, timestamps,
55
- receipts, completed work, reviewer identity, or user approval. When execution
56
- evidence is absent, preserve unfinished state and report the missing proof.
57
- Never hand-author the `semantic_model` shape or treat an unsynchronized Markdown
58
- edit as machine authority.
59
-
60
- Codex-native plan or task state may mirror physical state when available, but
61
- it is never a substitute for `spec.json` or authority to advance lifecycle.
1
+ # Process-first state synchronization
2
+
3
+ ## Primary file state
4
+
5
+ For new work, `specs/<feature>/plan.md` and its direct-child
6
+ `task-NN-*.md` files are canonical, hand-editable state. Task files stay flat
7
+ beside the plan; indexes and host task views are disposable projections.
8
+
9
+ Each task has exactly one `Status:` field using `pending`, `in_progress`,
10
+ `paused`, `blocked`, or `done`. The controller is the sole writer of task
11
+ status and proof. A task's final `## Receipt` is its only canonical execution
12
+ proof.
13
+
14
+ ## Surgical synchronization
15
+
16
+ Before changing state:
17
+
18
+ 1. read the plan row and the task's Outcome, Acceptance, Dependencies,
19
+ Verification Plan, Status, and Receipt;
20
+ 2. confirm every dependency and owned path at the requested boundary;
21
+ 3. edit only the observed Status, concrete blocker, implemented checkbox, or
22
+ Receipt; and
23
+ 4. re-read the file and confirm exactly one Status field and one Receipt
24
+ section.
25
+
26
+ Starting or resuming changes only Status to `in_progress`. Blocking records a
27
+ specific cause without creating proof. Do not replace a whole packet to make a
28
+ state transition.
29
+
30
+ Set `Status: done` only after the inline Receipt passes the
31
+ `validateCanonicalReceipt` contract: exact command, `Exit: 0`,
32
+ `Verification: PASS`, runtime-derived Base and Head values, and a non-empty
33
+ fenced block of current command output. Missing, stale, contradictory,
34
+ placeholder, copied, failure, or zero-test evidence leaves the task unfinished.
35
+
36
+ Synchronization never fabricates commands, output, timestamps, completed
37
+ work, reviewer identity, user approval, or product readiness. A passing command
38
+ proves only the boundary it executed.
39
+
40
+ ## Human gates and workflow ownership
41
+
42
+ - C1 records the user's scope decision before the plan is written.
43
+ - C2 records the user's disposition of deduplicated adversarial findings.
44
+ - Develop starts only after a new explicit user invocation and executes one
45
+ unblocked task at a time.
46
+ - Sync changes only observed file state and never starts implementation.
47
+ - C3 occurs after current receipts and limitations are shown; the user decides
48
+ whether the requested feature is complete.
49
+
50
+ ## Legacy compatibility
51
+
52
+ Existing packets containing `spec.json`, nested `tasks/task-R*.md`, or other
53
+ legacy kernel artifacts stay on their installed adapters. Preserve their
54
+ `task_registry`, `semantic_model`, `planning_depth`, lane,
55
+ `execution_tier`, typed topology, separate receipts, and feature closeout
56
+ contract. Do not migrate that machine authority or storage shape while syncing
57
+ an unrelated process-first packet.
@@ -3,7 +3,14 @@
3
3
  ## Shared CafeKit instructions
4
4
 
5
5
  - Deliver exactly what was asked. Do not expand, polish, or add optional work beyond the request. Match existing code style and structure.
6
- - For Specs v2.1, treat `spec.json` as machine authority and Markdown as human projections. Keep task status and plan synchronized with `task_registry`; derive ownership, dependencies, transitions, proof, and parallelism only from typed `coordination.boundaries`. Never invent proof, readiness, approval, or audit state.
6
+ - For process-first Specs, `plan.md` and flat `task-NN-*.md` files are
7
+ canonical, hand-editable state. Each task has exactly one `Status:` field and
8
+ keeps canonical execution proof in its final inline `## Receipt`.
9
+ - Specs uses three user decisions: C1 for scope, C2 for adversarial findings,
10
+ and C3 for completion. Planning never starts implementation; implementation
11
+ requires a new explicit user invocation.
12
+ - Synchronize only observed task state with surgical edits. Never invent proof,
13
+ readiness, approval, review independence, or completed work.
7
14
  - `NO_TESTS` and `0 tests + exit 0` do not pass when the task requires automated tests.
8
15
  - When a hook blocks an action, that is an instruction boundary — do not work around it.
9
16
  - Use conventional commits. Do not add AI attribution unless requested.