@haposoft/cafekit 0.8.9 → 0.8.11

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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Claude Code-first spec-driven workflow and runtime bundle for AI coding assistants.
4
4
 
5
- [![Version](https://img.shields.io/badge/version-0.8.0-blue.svg)](https://github.com/haposoft/cafekit)
5
+ [![Version](https://img.shields.io/badge/version-0.8.11-blue.svg)](https://github.com/haposoft/cafekit)
6
6
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
7
  [![Claude%20Code](https://img.shields.io/badge/Claude%20Code-Primary-orange.svg)](https://claude.ai/code)
8
8
 
@@ -46,9 +46,11 @@ Claude Code install targets:
46
46
 
47
47
  ```text
48
48
  .claude/
49
+ ├── .gitignore
49
50
  ├── skills/
50
51
  ├── agents/
51
52
  ├── hooks/
53
+ ├── cafekit.json
52
54
  ├── status.cjs
53
55
  ├── runtime.json
54
56
  ├── settings.json
@@ -61,6 +63,13 @@ Managed runtime features include:
61
63
  - rule/context injection
62
64
  - spec state awareness
63
65
  - safe settings merge on reinstall
66
+ - installed CafeKit version tracking in `.claude/cafekit.json`
67
+
68
+ To check the installed CafeKit package version:
69
+
70
+ ```bash
71
+ cat .claude/cafekit.json
72
+ ```
64
73
 
65
74
  ## Core Skills
66
75
 
package/bin/install.js CHANGED
@@ -20,6 +20,7 @@ const os = require('os');
20
20
  const readline = require('readline');
21
21
  const { execSync } = require('child_process');
22
22
  const packageJson = require('../package.json');
23
+ const INSTALL_COMMAND = `npx ${packageJson.name}@${packageJson.version}`;
23
24
 
24
25
  function validateManifestV2(manifest) {
25
26
  if (!manifest || manifest.version !== 2) return false;
@@ -339,6 +340,55 @@ function ensureWorkflowDependencies(platformKey, platform, results, options = {}
339
340
  });
340
341
  }
341
342
 
343
+ function readJsonFile(filePath) {
344
+ if (!fs.existsSync(filePath)) {
345
+ return {};
346
+ }
347
+
348
+ try {
349
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
350
+ } catch {
351
+ return {};
352
+ }
353
+ }
354
+
355
+ function writePlatformVersionMetadata(platformKey, results) {
356
+ const platform = PLATFORMS[platformKey];
357
+ const targetPath = path.join(platform.folder, 'cafekit.json');
358
+ const targetExists = fs.existsSync(targetPath);
359
+ const existingMetadata = readJsonFile(targetPath);
360
+ const now = new Date().toISOString();
361
+ const previousVersion = typeof existingMetadata.version === 'string'
362
+ ? existingMetadata.version
363
+ : null;
364
+
365
+ const metadata = {
366
+ schemaVersion: 1,
367
+ packageName: packageJson.name,
368
+ version: packageJson.version,
369
+ platform: platform.id,
370
+ platformName: platform.name,
371
+ installedAt: existingMetadata.installedAt || now,
372
+ lastInstalledAt: now,
373
+ installCommand: INSTALL_COMMAND
374
+ };
375
+
376
+ if (previousVersion && previousVersion !== packageJson.version) {
377
+ metadata.previousVersion = previousVersion;
378
+ }
379
+
380
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
381
+ fs.writeFileSync(targetPath, `${JSON.stringify(metadata, null, 2)}\n`, 'utf8');
382
+
383
+ if (targetExists) {
384
+ console.log(` ↻ Version metadata updated: ${targetPath}`);
385
+ results.updated++;
386
+ } else {
387
+ console.log(` ✓ Version metadata installed: ${targetPath}`);
388
+ results.copied++;
389
+ }
390
+ }
391
+
342
392
  function getPlatformSpecFiles(platformKey) {
343
393
  if (platformKey === 'claude') {
344
394
  const manifestCommands = CLAUDE_MIGRATION_MANIFEST?.commands?.core;
@@ -701,7 +751,8 @@ function copyClaudeRuntimeFiles(platformKey, results, options = {}) {
701
751
 
702
752
  manifest.runtime.files.forEach(relPath => {
703
753
  const srcPath = path.join(srcBase, relPath);
704
- const targetPath = path.join(targetBase, relPath);
754
+ const targetRelPath = relPath === 'gitignore' ? '.gitignore' : relPath;
755
+ const targetPath = path.join(targetBase, targetRelPath);
705
756
 
706
757
  if (!fs.existsSync(srcPath)) {
707
758
  console.log(` ⚠ Runtime file not found: ${relPath}`);
@@ -717,10 +768,10 @@ function copyClaudeRuntimeFiles(platformKey, results, options = {}) {
717
768
  fs.copyFileSync(srcPath, targetPath);
718
769
 
719
770
  if (targetExists) {
720
- console.log(` ↻ Runtime updated: ${relPath}`);
771
+ console.log(` ↻ Runtime updated: ${targetRelPath}`);
721
772
  results.updated++;
722
773
  } else {
723
- console.log(` ✓ Runtime installed: ${relPath}`);
774
+ console.log(` ✓ Runtime installed: ${targetRelPath}`);
724
775
  results.copied++;
725
776
  }
726
777
  } else {
@@ -1065,6 +1116,8 @@ async function main() {
1065
1116
  copyGeminiFile(platformKey, results, installerOptions);
1066
1117
  }
1067
1118
 
1119
+ writePlatformVersionMetadata(platformKey, results);
1120
+
1068
1121
  results.targets.push(platform.commandsDir);
1069
1122
  console.log();
1070
1123
  }
@@ -1085,6 +1138,7 @@ async function main() {
1085
1138
  console.log();
1086
1139
  console.log(` Copied Files: ${results.copied}`);
1087
1140
  console.log(` Updated Files: ${results.updated}`);
1141
+ console.log(` CafeKit Version: ${packageJson.version}`);
1088
1142
  console.log(` Skipped Files: ${results.skipped}`);
1089
1143
  console.log(` Installed Skills: ${results.installedSkills > 0 ? 'Yes ✓' : 'No'}`);
1090
1144
  console.log(` Dependency Checks: ${results.dependencyChecks}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haposoft/cafekit",
3
- "version": "0.8.9",
3
+ "version": "0.8.11",
4
4
  "description": "Claude Code-first spec-driven workflow for AI coding assistants. Bundles CafeKit hapo: skills, runtime hooks, agents, and installer scaffolding.",
5
5
  "author": "Haposoft <nghialt@haposoft.com>",
6
6
  "license": "MIT",
@@ -7,10 +7,12 @@
7
7
  skills/.venv/
8
8
  .venv/
9
9
  venv/
10
+ skills/**/node_modules/
10
11
  __pycache__/
11
12
  *.pyc
12
13
 
13
- # System generated or logs
14
+ # System generated state, caches, and logs
15
+ session-state/
14
16
  hooks/.logs/
15
17
  agent-memory/
16
18
  settings.bak.json
@@ -68,6 +68,7 @@
68
68
  },
69
69
  "runtime": {
70
70
  "files": [
71
+ "gitignore",
71
72
  "runtime.json",
72
73
  "status.cjs",
73
74
  "hooks/session.cjs",
@@ -86,23 +86,31 @@ function extractRequirementIds(requirementsText) {
86
86
  }
87
87
 
88
88
  function validateTaskSections(taskPath, content, errors) {
89
- const hasContext =
90
- hasHeading(content, 'Context') ||
91
- hasHeading(content, 'Objective') ||
92
- hasHeading(content, 'Goal');
89
+ const hasContext = hasHeading(content, 'Context');
90
+ const hasConstraints = hasHeading(content, 'Constraints');
93
91
  const hasSteps =
94
92
  hasHeading(content, 'Steps') || hasHeading(content, 'Implementation Steps');
95
93
  const hasRequirements =
96
- hasHeading(content, 'Requirements') || /^\*\*Requirement:\*\*/m.test(content);
94
+ hasHeading(content, 'Requirements') || /_Requirements:\s*[^_\n]+_/i.test(content);
95
+ const hasRelatedFiles = hasHeading(content, 'Related Files');
96
+ const hasCompletionCriteria = hasHeading(content, 'Completion Criteria');
97
97
  const hasEvidence =
98
98
  hasHeading(content, 'Evidence') ||
99
99
  hasHeading(content, 'Task Test Plan & Verification Evidence') ||
100
100
  hasHeading(content, 'Verification & Evidence');
101
+ const hasRiskAssessment = hasHeading(content, 'Risk Assessment');
101
102
 
102
- if (!hasContext) errors.push(`${taskPath}: missing Context/Objective/Goal`);
103
+ if (!hasContext) errors.push(`${taskPath}: missing Context`);
104
+ if (!hasConstraints) errors.push(`${taskPath}: missing Constraints`);
103
105
  if (!hasSteps) errors.push(`${taskPath}: missing Steps/Implementation Steps`);
104
106
  if (!hasRequirements) errors.push(`${taskPath}: missing Requirements mapping`);
107
+ if (!hasRelatedFiles) errors.push(`${taskPath}: missing Related Files`);
108
+ if (!hasCompletionCriteria) errors.push(`${taskPath}: missing Completion Criteria`);
105
109
  if (!hasEvidence) errors.push(`${taskPath}: missing Evidence or task test plan`);
110
+ if (!hasRiskAssessment) errors.push(`${taskPath}: missing Risk Assessment`);
111
+ if (hasEvidence && !/Runtime reachability verification/i.test(content)) {
112
+ errors.push(`${taskPath}: missing Runtime reachability verification`);
113
+ }
106
114
  }
107
115
 
108
116
  function validateSpec(specDir) {
@@ -187,6 +195,28 @@ function validateSpec(specDir) {
187
195
  errors.push('tasks/: feature work cannot be entirely R0; reserve R0 for shared foundation tasks');
188
196
  }
189
197
 
198
+ const validationRecommended = spec.design_context?.validation_recommended === true;
199
+ if (taskFiles.length >= 5 && !validationRecommended) {
200
+ errors.push('spec.json.design_context.validation_recommended: must be true for specs with 5+ task files');
201
+ }
202
+ if (
203
+ (validationRecommended || taskFiles.length >= 5) &&
204
+ spec.ready_for_implementation === true &&
205
+ spec.validation?.status !== 'completed'
206
+ ) {
207
+ errors.push(
208
+ 'spec.json.ready_for_implementation: cannot be true when validation is recommended but validation.status is not completed',
209
+ );
210
+ }
211
+ if (spec.validation?.status === 'completed') {
212
+ if (!spec.timestamps?.validation_done) {
213
+ errors.push('spec.json.timestamps.validation_done: required when validation.status is completed');
214
+ }
215
+ if (taskFiles.length >= 5 && !spec.timestamps?.review_done) {
216
+ errors.push('spec.json.timestamps.review_done: required for 5+ task specs after validation');
217
+ }
218
+ }
219
+
190
220
  const requirementsPath = path.join(specDir, 'requirements.md');
191
221
  const designPath = path.join(specDir, 'design.md');
192
222
  const researchPath = path.join(specDir, 'research.md');
@@ -137,6 +137,7 @@ The system MUST NOT execute Steps 1-8. Instead, load `references/review.md` and
137
137
  5. **MUST NOT create implementation code files** (`.ts`, `.js`, `.py`, etc.). The validate workflow produces ONLY markdown spec documents and reports. If a fix requires a new shared module, describe it in the relevant task file instead of creating the actual code file.
138
138
  6. **MUST NOT over-engineer fixes.** Apply YAGNI — if user says "configure later", add an abstraction note to the task, do NOT generate 4 concrete provider implementations.
139
139
  7. **MUST follow auto-decision table exactly.** Count task files + scan for keywords → pick mode. No self-justification to override the table result.
140
+ 8. **MUST run deterministic validator.** Before reporting validation PASS, run `node .claude/scripts/validate-spec-output.cjs specs/<feature>`. If it exits non-zero, validation is FAIL/BLOCKED, `ready_for_implementation` remains `false`, and output MUST NOT suggest `/hapo:develop`.
140
141
 
141
142
  ## Workflow Diagram
142
143
 
@@ -321,12 +322,15 @@ Each task file MUST be **self-contained and implementation-ready** — detailed
321
322
 
322
323
  **Structure per task file:**
323
324
  1. **Context** — why this task exists, current state, target outcome, relevant exact files.
324
- 2. **Steps** — concise implementation checklist with business intent and code-level detail.
325
- 3. **Requirements** — list requirement IDs and acceptance criteria covered by this task.
326
- 4. **Related Files** — table with exact paths, action type, and descriptions when paths are known; otherwise run scout first.
327
- 5. **Completion Criteria** — observable, testable criteria.
328
- 6. **Evidence** — automated command(s), artifact/runtime proof, negative-path proof, and runtime reachability proof.
329
- 7. **Risk Assessment** — table with risk, severity, mitigation.
325
+ 2. **Constraints** — MUST / SHOULD / MUST NOT / SCOPE guardrails.
326
+ 3. **Steps** — concise implementation checklist with business intent and code-level detail.
327
+ 4. **Requirements** — list requirement IDs and acceptance criteria covered by this task.
328
+ 5. **Related Files** — table with exact paths, action type, and descriptions when paths are known; otherwise run scout first.
329
+ 6. **Completion Criteria** — observable, testable criteria.
330
+ 7. **Evidence** — automated command(s), artifact/runtime proof, negative-path proof, and runtime reachability proof.
331
+ 8. **Risk Assessment** — table with risk, severity, mitigation.
332
+
333
+ **Template fidelity is mandatory:** preserve the task template headings exactly. Do NOT rename `## Context` to `## Objective`, do NOT replace `## Completion Criteria` with prose, do NOT remove `## Related Files`, `## Constraints`, or `## Risk Assessment`, and do NOT collapse `## Evidence` into generic QA scenarios. Compact wording is fine; missing sections are invalid.
330
334
 
331
335
  **Parallel markers:** Append `(P)` to tasks that can run concurrently (no data dependency, no shared files, no prerequisite approval from another task). Tasks serving DIFFERENT requirements are often parallelizable.
332
336
 
@@ -350,6 +354,7 @@ Load: `references/review.md` + `rules/design-review.md`
350
354
  - **PROHIBITION:** The system MUST NOT skip Red Team because of a prior code-auditor review. Code review ≠ Spec review.
351
355
  - **PROHIBITION:** The system MUST NOT create `.ts`, `.js`, `.py` or any implementation files during validation. Spec-only outputs.
352
356
  - **Reconciliation Rule:** `validation.status = "completed"` is forbidden until all accepted findings and validation decisions are physically propagated into `requirements.md`, `design.md`, `tasks/*.md`, and `spec.json` where applicable.
357
+ - **Deterministic Gate:** Run `node .claude/scripts/validate-spec-output.cjs specs/<feature>` after all fixes and before final output. Script failure overrides any LLM checklist result and blocks `ready_for_implementation = true`.
353
358
 
354
359
  ### Step 9.5: Finalization Audit (MANDATORY)
355
360
  - Re-scan the `tasks/` directory and rebuild `spec.json.task_files` from the real filesystem (sorted, relative paths)
@@ -366,6 +371,7 @@ Load: `references/review.md` + `rules/design-review.md`
366
371
  - FAIL if a task creates runtime-facing artifacts but neither proves reachability from an entrypoint/caller nor names a later integration task responsible for wiring them.
367
372
  - FAIL if a UI/app/runtime spec has multiple user-facing task outputs but no final integration/reachability task or final integration section.
368
373
  - FAIL if accepted validation decisions exist in reports but are not reflected in the implementation-facing sections of affected artifacts (`Context`, `Steps`, `Requirements`, `Completion Criteria`, `Evidence`, canonical contracts, or requirements text).
374
+ - FAIL if any generated task replaces the required task template with a reduced `Objective` / `Steps` / `Evidence` shape. `Context`, `Constraints`, `Related Files`, `Completion Criteria`, `Evidence`, and `Risk Assessment` must all remain present.
369
375
  - FAIL if the spec scope/provider was switched away from Anthropic/Claude but `requirements.md`, `design.md`, or `tasks/*.md` still contain stale provider-specific strings such as `Claude API`, `Haiku`, or `haiku_reachable`. `research.md` is the only allowed place for historical cost comparisons.
370
376
  - FAIL if privacy/delete-data work lacks a single canonical deletion policy. The design MUST explicitly choose either:
371
377
  1. hard-delete with no re-registration lock, or
@@ -437,7 +443,7 @@ Task paths that omit the `task-` prefix or use non-padded sequence numbers (for
437
443
  6. `task_registry` matches the real filesystem and does not omit any task file
438
444
  7. If `design_context.validation_recommended = true`, `validation.status = "completed"` (or another explicit user-accepted risk state that is recorded)
439
445
 
440
- If any approval is `false`, `ready_for_implementation` MUST remain `false`.
446
+ If any approval is `false`, `ready_for_implementation` MUST remain `false`. If the spec has 5+ task files, `ready_for_implementation` MUST remain `false` until `/hapo:specs <feature> --validate` completes Red Team + Validate and writes `validation.status = "completed"`.
441
447
 
442
448
  ## Output Structure
443
449
 
@@ -10,6 +10,25 @@ Review a spec before implementation. The system auto-decides the review depth ba
10
10
  2. If not → check active spec (spec with `in_progress` status; accept legacy `in-progress` when reading existing files)
11
11
  3. If nothing found → ask user to specify path
12
12
 
13
+ ## Deterministic Validator Gate (MANDATORY)
14
+
15
+ This gate is the hard source of truth for `hapo:specs --validate`. LLM red-team tables and markdown validation reports are advisory until this script passes.
16
+
17
+ After resolving the spec path, run:
18
+
19
+ ```bash
20
+ node .claude/scripts/validate-spec-output.cjs specs/<feature>
21
+ ```
22
+
23
+ Required behavior:
24
+ 1. Run the validator once before the final PASS decision. If it fails, copy the exact failing categories into the validation findings/blockers and fix the physical spec artifacts.
25
+ 2. Red Team and Validate may continue while fixing issues, but they cannot approve the spec while validator errors remain.
26
+ 3. Run the validator again after every accepted Red Team / Validate fix set and before any final verdict.
27
+ 4. The final report MUST include the validator command and the final PASS/FAIL result.
28
+ 5. If the validator exits non-zero, final verdict is **FAIL / BLOCKED**, `validation.status` MUST NOT become `completed`, `ready_for_implementation` MUST remain `false`, and the output MUST NOT suggest `/hapo:develop`.
29
+ 6. A markdown checklist, manual QA table, or "all required sections present" claim cannot override validator failure.
30
+ 7. For specs with 5+ task files, a pre-review validator PASS only proves artifact shape. It does not mean implementation can start until Red Team + Validate finish, accepted fixes are propagated, and `spec.json.validation.status` is written as `completed`.
31
+
13
32
  ## Auto-Decision: When to Red Team vs Validate
14
33
 
15
34
  The system evaluates the spec and picks the appropriate review mode:
@@ -45,6 +64,7 @@ These rules override any self-reasoning or optimization the system may attempt:
45
64
  7. **Implementation-facing propagation is mandatory.** A decision that affects implementation is NOT considered applied if it only appears in `Risk Assessment`, `validate-log.md`, or `red-team-report.md`. It must update at least one of: `requirements.md`, `Canonical Contracts & Invariants`, `Context`, `Steps`, `Requirements`, `Completion Criteria`, or `Evidence`.
46
65
  8. **CafeKit command dialect only.** Validation output MUST use `/hapo:develop <feature>` as the implementation handoff. Never mention `/sdd:execute-spec`, `/sdd:*`, `/work`, `/code`, `/specs <feature> --approve`, `/hapo:specs <feature> --approve`, or non-CafeKit aliases.
47
66
  9. **CafeKit task filename convention only.** Task files MUST use `tasks/task-R{N}-{SEQ}-<slug>.md` with two-digit `SEQ` (for example `tasks/task-R0-01-project-scaffolding.md`). Files like `tasks/R0-1-project-scaffolding.md` are legacy/foreign format; rename them and update `spec.json.task_files`, `spec.json.task_registry`, and dependency references before passing validation.
67
+ 10. **Deterministic validator is mandatory.** The final validation verdict MUST be derived from `node .claude/scripts/validate-spec-output.cjs specs/<feature>`. If that command fails, report FAIL/BLOCKED and list the script output. Do NOT report PASS.
48
68
 
49
69
  ---
50
70
 
@@ -226,13 +246,15 @@ Save to `reports/validate-log.md`:
226
246
  Before declaring validation complete:
227
247
  1. Re-read `spec.json`, `requirements.md`, `design.md`, and all `tasks/task-*.md`
228
248
  2. Verify every accepted red-team finding and every validation action item is reflected in the correct physical file(s)
229
- 3. Fail the audit if:
249
+ 3. Run `node .claude/scripts/validate-spec-output.cjs specs/<feature>` and keep the raw result visible
250
+ 4. Fail the audit if:
230
251
  - a report says "applied" but the file still contains the old text
231
252
  - stale provider strings remain after a provider change
232
253
  - delete-data/privacy artifacts mix multiple canonical policies
233
254
  - any task path fails the CafeKit `tasks/task-R{N}-{SEQ}-<slug>.md` naming convention
234
255
  - `spec.json.updated_at`, `timestamps.review_done`, or `timestamps.validation_done` do not reflect the final reviewed state
235
- 4. Only after the audit passes may you:
256
+ - deterministic validator exits non-zero
257
+ 5. Only after the audit passes may you:
236
258
  - set `spec.json.validation.status = "completed"`
237
259
  - set `spec.json.timestamps.validation_done`
238
260
  - set `spec.json.timestamps.review_done`
@@ -240,8 +262,10 @@ Before declaring validation complete:
240
262
 
241
263
  #### Step 8: Final Status Write-Back
242
264
  - Update `spec.json.updated_at` to the reconciliation time
265
+ - On final PASS, set `spec.json.validation.status = "completed"`, `spec.json.timestamps.validation_done`, and, when Red Team ran, `spec.json.timestamps.review_done`
266
+ - On final PASS, set `spec.json.ready_for_implementation = true` only after the deterministic validator passes on the final physical artifacts
243
267
  - Ensure `red-team-report.md` and `validate-log.md` do not contradict `spec.json`
244
- - If reconciliation fails, keep `validation.status` as `not-run` or `in_progress` and list blockers explicitly
268
+ - If reconciliation or deterministic validation fails, keep `validation.status` as `not-run` or `in_progress`, keep `ready_for_implementation = false`, list blockers explicitly, and do not provide an implementation handoff.
245
269
 
246
270
  ---
247
271
 
@@ -256,6 +280,7 @@ Red Team: {N} findings ({A} accepted, {R} rejected)
256
280
  Validate: {Q} questions asked, {D} decisions confirmed
257
281
 
258
282
  Files modified: {list}
283
+ Deterministic validator: PASS via `node .claude/scripts/validate-spec-output.cjs specs/<feature>`
259
284
 
260
285
  📌 Next step: /hapo:develop <feature> (ONLY if reconciliation audit passed)
261
286
  ```