@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
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: cf:ui-ux-pro-max
3
- description: "UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples."
3
+ description: "Searchable UI/UX lookup database for web and mobile products: 50+ visual styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, 25 chart types, Google Fonts, and React Native stack guidance. Use to pick or justify a palette, font pairing, visual style, chart type, or UX guideline for a product type. It does not build, review, or redesign screens; that is cf:ui-ux, which can consult this skill for lookups."
4
4
  user-invocable: true
5
5
  when_to_use: "Invoke to look up color palettes, font pairings, product-type styles, or UX guidelines; to build or review a screen use cf:ui-ux."
6
6
  category: frontend
@@ -11,45 +11,13 @@ metadata:
11
11
  ---
12
12
  # UI/UX Pro Max - Design Intelligence
13
13
 
14
- Comprehensive design guide for web and mobile applications. Contains 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, and 25 chart types across 10 technology stacks. Searchable database with priority-based recommendations.
14
+ Searchable design database for web and mobile products: 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, 25 chart types, and stack guidance for React Native only.
15
15
 
16
16
  ## When to Apply
17
17
 
18
- This Skill should be used when the task involves **UI structure, visual design decisions, interaction patterns, or user experience quality control**.
18
+ Use this skill to look something up: a palette, font pairing, or visual style for a product type, a chart type, or the UX guideline that applies to a pattern.
19
19
 
20
- ### Must Use
21
-
22
- This Skill must be invoked in the following situations:
23
-
24
- - Designing new pages (Landing Page, Dashboard, Admin, SaaS, Mobile App)
25
- - Creating or refactoring UI components (buttons, modals, forms, tables, charts, etc.)
26
- - Choosing color schemes, typography systems, spacing standards, or layout systems
27
- - Reviewing UI code for user experience, accessibility, or visual consistency
28
- - Implementing navigation structures, animations, or responsive behavior
29
- - Making product-level design decisions (style, information hierarchy, brand expression)
30
- - Improving perceived quality, clarity, or usability of interfaces
31
-
32
- ### Recommended
33
-
34
- This Skill is recommended in the following situations:
35
-
36
- - UI looks "not professional enough" but the reason is unclear
37
- - Receiving feedback on usability or experience
38
- - Pre-launch UI quality optimization
39
- - Aligning cross-platform design (Web / iOS / Android)
40
- - Building design systems or reusable component libraries
41
-
42
- ### Skip
43
-
44
- This Skill is not needed in the following situations:
45
-
46
- - Pure backend logic development
47
- - Only involving API or database design
48
- - Performance optimization unrelated to the interface
49
- - Infrastructure or DevOps work
50
- - Non-visual scripts or automation tasks
51
-
52
- **Decision criteria**: If the task will change how a feature **looks, feels, moves, or is interacted with**, this Skill should be used.
20
+ Building, reviewing, or redesigning a screen belongs to `cf:ui-ux`, which follows the project's own components and measures the page; it can call this skill when it needs a lookup. Backend, API, infrastructure, and non-visual work need neither skill.
53
21
 
54
22
  ## Rule Categories by Priority
55
23
 
@@ -313,28 +281,7 @@ Search specific domains using the CLI tool below.
313
281
 
314
282
  ## Prerequisites
315
283
 
316
- Check if Python is installed:
317
-
318
- ```bash
319
- python3 --version || python --version
320
- ```
321
-
322
- If Python is not installed, install it based on user's OS:
323
-
324
- **macOS:**
325
- ```bash
326
- brew install python3
327
- ```
328
-
329
- **Ubuntu/Debian:**
330
- ```bash
331
- sudo apt update && sudo apt install python3
332
- ```
333
-
334
- **Windows:**
335
- ```powershell
336
- winget install Python.Python.3.12
337
- ```
284
+ Run `search.py` from the project root with `python3 .claude/skills/ui-ux-pro-max/scripts/search.py` (Windows: `python .claude\skills\ui-ux-pro-max\scripts\search.py`). It uses only the Python standard library, so no venv or extra install is needed.
338
285
 
339
286
  ---
340
287
 
@@ -362,14 +309,14 @@ Extract key information from user request:
362
309
  - **Product type**: Entertainment (social, video, music, gaming), Tool (scanner, editor, converter), Productivity (task manager, notes, calendar), or hybrid
363
310
  - **Target audience**: C-end consumer users; consider age group, usage context (commute, leisure, work)
364
311
  - **Style keywords**: playful, vibrant, minimal, dark mode, content-first, immersive, etc.
365
- - **Stack**: React Native (this project's only tech stack)
312
+ - **Stack**: the target project's stack; `--stack` guidance exists only for `react-native`
366
313
 
367
- ### Step 2: Generate Design System (REQUIRED)
314
+ ### Step 2: Generate Design System
368
315
 
369
- **Always start with `--design-system`** to get comprehensive recommendations with reasoning:
316
+ Start with `--design-system` when choosing a whole direction (style, palette, type) for a new product or page; for a single lookup go straight to Step 3:
370
317
 
371
318
  ```bash
372
- python3 skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
319
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
373
320
  ```
374
321
 
375
322
  This command:
@@ -380,7 +327,7 @@ This command:
380
327
 
381
328
  **Example:**
382
329
  ```bash
383
- python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
330
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
384
331
  ```
385
332
 
386
333
  ### Step 2b: Persist Design System (Master + Overrides Pattern)
@@ -388,7 +335,7 @@ python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --d
388
335
  To save the design system for **hierarchical retrieval across sessions**, add `--persist`:
389
336
 
390
337
  ```bash
391
- python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
338
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
392
339
  ```
393
340
 
394
341
  This creates:
@@ -397,7 +344,7 @@ This creates:
397
344
 
398
345
  **With page-specific override:**
399
346
  ```bash
400
- python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
347
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
401
348
  ```
402
349
 
403
350
  This also creates:
@@ -422,7 +369,7 @@ Now, generate the code...
422
369
  After getting the design system, use domain searches to get additional details:
423
370
 
424
371
  ```bash
425
- python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
372
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
426
373
  ```
427
374
 
428
375
  **When to use detailed searches:**
@@ -440,14 +387,13 @@ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n
440
387
  | Landing structure | `landing` | `--domain landing "hero social-proof"` |
441
388
  | React Native perf | `react` | `--domain react "rerender memo list"` |
442
389
  | App interface a11y | `web` | `--domain web "accessibilityLabel touch safe-areas"` |
443
- | AI prompt / CSS keywords | `prompt` | `--domain prompt "minimalism"` |
444
390
 
445
- ### Step 4: Stack Guidelines (React Native)
391
+ ### Step 4: Stack Guidelines (React Native projects only)
446
392
 
447
- Get React Native implementation-specific best practices:
393
+ For a React Native project, get implementation-specific best practices:
448
394
 
449
395
  ```bash
450
- python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
396
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
451
397
  ```
452
398
 
453
399
  ---
@@ -468,7 +414,6 @@ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
468
414
  | `google-fonts` | Individual Google Fonts lookup | sans serif, monospace, japanese, variable font, popular |
469
415
  | `react` | React/Next.js performance | waterfall, bundle, suspense, memo, rerender, cache |
470
416
  | `web` | App interface guidelines (iOS/Android/React Native) | accessibilityLabel, touch targets, safe areas, Dynamic Type |
471
- | `prompt` | AI prompts, CSS keywords | (style name) |
472
417
 
473
418
  ### Available Stacks
474
419
 
@@ -488,10 +433,10 @@ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
488
433
  - Style keywords: modern, minimal, content-first, dark mode
489
434
  - Stack: React Native
490
435
 
491
- ### Step 2: Generate Design System (REQUIRED)
436
+ ### Step 2: Generate Design System
492
437
 
493
438
  ```bash
494
- python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
439
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
495
440
  ```
496
441
 
497
442
  **Output:** Complete design system with pattern, style, colors, typography, effects, and anti-patterns.
@@ -500,16 +445,16 @@ python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" -
500
445
 
501
446
  ```bash
502
447
  # Get style options for a modern tool product
503
- python3 skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
448
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
504
449
 
505
450
  # Get UX best practices for search interaction and loading
506
- python3 skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
451
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
507
452
  ```
508
453
 
509
454
  ### Step 4: Stack Guidelines
510
455
 
511
456
  ```bash
512
- python3 skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
457
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
513
458
  ```
514
459
 
515
460
  **Then:** Synthesize design system + detailed searches and implement the design.
@@ -522,10 +467,10 @@ The `--design-system` flag supports two output formats:
522
467
 
523
468
  ```bash
524
469
  # ASCII box (default) - best for terminal display
525
- python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
470
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
526
471
 
527
472
  # Markdown - best for documentation
528
- python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
473
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
529
474
  ```
530
475
 
531
476
  ---
@@ -537,7 +482,7 @@ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
537
482
  - Use **multi-dimensional keywords** — combine product + industry + tone + density: `"entertainment social vibrant content-dense"` not just `"app"`
538
483
  - Try different keywords for the same need: `"playful neon"` → `"vibrant dark"` → `"content-first minimal"`
539
484
  - Use `--design-system` first for full recommendations, then `--domain` to deep-dive any dimension you're unsure about
540
- - Always add `--stack react-native` for implementation-specific guidance
485
+ - Add `--stack react-native` only when the target project is React Native
541
486
 
542
487
  ### Common Sticking Points
543
488
 
@@ -26,15 +26,9 @@ npx @axe-core/cli https://example.com # Accessibility
26
26
  npx lighthouse https://example.com # Performance
27
27
  ```
28
28
 
29
- ## Testing Strategy (Choose Your Model)
29
+ ## Testing Strategy
30
30
 
31
- | Model | Structure | Best For |
32
- |-------|-----------|----------|
33
- | Pyramid | Unit 70% > Integration 20% > E2E 10% | Monoliths |
34
- | Trophy | Integration-heavy | Modern SPAs |
35
- | Honeycomb | Contract-centric | Microservices |
36
-
37
- → `./references/testing-pyramid-strategy.md`
31
+ Choosing between pyramid, trophy, and honeycomb: `./references/testing-pyramid-strategy.md`
38
32
 
39
33
  ## Reference Documentation
40
34
 
@@ -88,15 +82,3 @@ node ./scripts/analyze-test-results.js \
88
82
  --output markdown
89
83
  ```
90
84
  Parses Playwright/Vitest/JUnit results into unified summary.
91
-
92
- ## CI/CD Integration
93
-
94
- ```yaml
95
- jobs:
96
- test:
97
- steps:
98
- - run: npm run test:unit # Gate 1: Fast fail
99
- - run: npm run test:e2e # Gate 2: After unit pass
100
- - run: npm run test:a11y # Accessibility
101
- - run: npx lhci autorun # Performance
102
- ```
@@ -37,8 +37,8 @@ function loadSharedReceipt() {
37
37
  'spec-receipt.cjs',
38
38
  'spec-receipt.cjs',
39
39
  (receipt) => {
40
- if (typeof receipt?.checkTaskReceipt !== 'function') {
41
- throw new Error('shared spec receipt helper has no checkTaskReceipt function');
40
+ if (typeof receipt?.checkWorkflowTaskReceipt !== 'function') {
41
+ throw new Error('shared spec receipt helper has no checkWorkflowTaskReceipt function');
42
42
  }
43
43
  },
44
44
  'shared spec receipt helper is missing'
@@ -55,7 +55,6 @@ function receiptHelper() {
55
55
  return loaded.receipt;
56
56
  }
57
57
 
58
- function evidenceBody(text) { return receiptHelper().evidenceBody(text, getSharedPolicy() || {}); }
59
58
  function safeTaskFile(featureDir, taskPath) {
60
59
  const result = receiptHelper().safeRead(featureDir, taskPath);
61
60
  return result.status === 'ok' ? result.path : null;
@@ -64,11 +63,6 @@ function validateCanonicalReceipt(body, options = {}) {
64
63
  const validate = getSharedValidate();
65
64
  return validate ? validate(body, options) : ['shared_validator'];
66
65
  }
67
- function checkReceiptDetails(featureDir, taskPath, task, runtimeContext) {
68
- const policy = getSharedPolicy();
69
- if (!policy) return { failures: ['shared_validator'], status: 'missing' };
70
- return receiptHelper().checkTaskReceipt(featureDir, taskPath, task, runtimeContext, policy);
71
- }
72
66
  function checkWorkflowReceiptDetails(featureDir, taskPath, runtimeContext) {
73
67
  const policy = getSharedPolicy();
74
68
  const receipt = receiptHelper();
@@ -85,40 +79,18 @@ function checkWorkflowReceiptSet(candidates, projectRoot, runtimeSession) {
85
79
  }
86
80
  return receipt.checkWorkflowReceiptSet(candidates, projectRoot, runtimeSession, policy);
87
81
  }
88
- function checkReceipt(featureDir, taskPath, task, runtimeContext) {
89
- const map = {
90
- unsafe_path: 'a', missing_receipt: 'b', task_status: 'a', completed_at: 'd',
91
- verification_state: 'c', placeholder: 'c', validator_unavailable: 'c',
92
- command: 'e', command_identity: 'e', exit_result: 'f', provenance: 'g',
93
- artifact_hash: 'h', artifact_declaration: 'h',
94
- };
95
- return [...new Set(checkReceiptDetails(featureDir, taskPath, task, runtimeContext).failures.map((failure) => map[failure] || failure))];
96
- }
97
- function checkFeatureReceipt(featureDir, runtimeContext) {
98
- const policy = getSharedPolicy();
99
- if (!policy) return { failures: ['shared_validator'], status: 'missing' };
100
- return receiptHelper().checkFeatureReceipt(featureDir, runtimeContext, policy);
101
- }
102
82
  function receiptFixHint(failures, body) {
103
83
  const helper = receiptHelper();
104
84
  return typeof helper.receiptFixHint === 'function' ? helper.receiptFixHint(failures, body) : null;
105
85
  }
106
- function readTaskProof(featureDir, taskPath) {
107
- return receiptHelper().readTaskProof(featureDir, taskPath, getSharedPolicy() || {});
108
- }
109
86
 
110
87
  module.exports = {
111
- checkFeatureReceipt,
112
- checkReceipt,
113
- checkReceiptDetails,
114
88
  checkWorkflowReceiptDetails,
115
89
  checkWorkflowReceiptSet,
116
- evidenceBody,
117
90
  getSharedPolicy,
118
91
  getSharedValidate,
119
92
  loadSharedPolicy,
120
93
  loadSharedReceipt,
121
- readTaskProof,
122
94
  receiptFixHint,
123
95
  safeTaskFile,
124
96
  validateCanonicalReceipt,
@@ -66,8 +66,8 @@ function sharedResolver() {
66
66
  // Use canonical realpath for require to avoid symlink hijack
67
67
  const realCandidate = canonicalRealpath(candidate);
68
68
  const resolver = require(realCandidate);
69
- if (typeof resolver?.resolveActiveSpec !== 'function') {
70
- throw new Error('shared spec resolver has no resolveActiveSpec function');
69
+ if (typeof resolver?.resolveWorkflowCandidate !== 'function') {
70
+ throw new Error('shared spec resolver has no resolveWorkflowCandidate function');
71
71
  }
72
72
  return resolver;
73
73
  } catch (error) {
@@ -80,31 +80,13 @@ function specsDirectory(projectRoot, runtime) {
80
80
  return sharedResolver().specsDirectory(projectRoot, runtime);
81
81
  }
82
82
 
83
- function findAllActiveSpecs(projectRoot, runtime) {
84
- return sharedResolver().findAllActiveSpecs(projectRoot, runtime);
85
- }
86
-
87
- function findAllSpecCandidates(projectRoot, runtime) {
88
- return sharedResolver().findAllSpecCandidates(projectRoot, runtime);
89
- }
90
-
91
- function resolveActiveSpec(projectRoot, runtime, explicitFeature, explicitPath) {
92
- if (projectRoot && typeof projectRoot === 'object') {
93
- return sharedResolver().resolveActiveSpec(projectRoot);
94
- }
95
- return sharedResolver().resolveActiveSpec({
96
- projectRoot,
97
- runtime,
98
- explicitFeature,
99
- explicitPath,
100
- });
83
+ function findLegacyPackets(projectRoot, runtime) {
84
+ const resolver = sharedResolver();
85
+ return typeof resolver.findLegacyPackets === 'function' ? resolver.findLegacyPackets(projectRoot, runtime) : [];
101
86
  }
102
87
 
103
88
  function resolveWorkflowCandidate(projectRoot, runtime, explicitFeature, explicitPath) {
104
89
  const resolver = sharedResolver();
105
- if (typeof resolver.resolveWorkflowCandidate !== 'function') {
106
- return resolveActiveSpec(projectRoot, runtime, explicitFeature, explicitPath);
107
- }
108
90
  if (projectRoot && typeof projectRoot === 'object') {
109
91
  return resolver.resolveWorkflowCandidate(projectRoot);
110
92
  }
@@ -123,23 +105,6 @@ function refineWorkflowGateResolution(resolved) {
123
105
  : resolved;
124
106
  }
125
107
 
126
- function findActiveSpec(projectRoot, runtime) {
127
- const resolved = resolveActiveSpec(projectRoot, runtime);
128
- if (!resolved) return null;
129
- if (resolved.error === 'multiple_active' || resolved.error === 'invalid_specs') return resolved;
130
- if (resolved.error) return null;
131
- return resolved;
132
- }
133
-
134
- function taskStatusMap(spec) {
135
- return Object.fromEntries(
136
- Object.entries(spec.task_registry || {}).map(([taskPath, task]) => [
137
- taskPath,
138
- task?.status || 'pending',
139
- ]),
140
- );
141
- }
142
-
143
108
  function extractExplicitTarget(...sources) {
144
109
  const resolver = sharedResolver();
145
110
  if (typeof resolver.extractExplicitTarget !== 'function') return null;
@@ -153,14 +118,10 @@ function readActiveFeatureTarget(options) {
153
118
  }
154
119
 
155
120
  module.exports = {
156
- findActiveSpec,
157
121
  extractExplicitTarget,
122
+ findLegacyPackets,
158
123
  readActiveFeatureTarget,
159
- findAllActiveSpecs,
160
- findAllSpecCandidates,
161
- resolveActiveSpec,
162
124
  resolveWorkflowCandidate,
163
125
  refineWorkflowGateResolution,
164
126
  specsDirectory,
165
- taskStatusMap,
166
127
  };
@@ -11,14 +11,11 @@ const {
11
11
  readPayload
12
12
  } = require('./lib/hook-context.cjs');
13
13
  const {
14
- checkFeatureReceipt,
15
- checkReceiptDetails,
16
14
  checkWorkflowReceiptDetails,
17
15
  checkWorkflowReceiptSet,
18
16
  loadSharedPolicy,
19
17
  receiptFixHint,
20
18
  } = require('./lib/spec-receipt.cjs');
21
- const { taskStatusMap } = require('./lib/spec-utils.cjs');
22
19
 
23
20
  function emitBlock(reason) {
24
21
  process.stdout.write(`${JSON.stringify({ decision: 'block', reason })}\n`);
@@ -45,7 +42,7 @@ try {
45
42
  }
46
43
  const POLICY = loaded.policy;
47
44
  const { projectRoot, runtime } = getHookContext(payload);
48
- if (typeof POLICY.completionDecisionForSpec !== 'function') {
45
+ if (typeof POLICY.deriveRuntimeContext !== 'function') {
49
46
  throw new Error('shared workflow policy lacks completion authority functions');
50
47
  }
51
48
  const resolver = require('./lib/spec-utils.cjs');
@@ -88,7 +85,7 @@ try {
88
85
  if (resolved.error === 'invalid_specs') {
89
86
  process.stdout.write(`${JSON.stringify({
90
87
  decision: 'block',
91
- reason: `Completion gate: invalid spec JSON detected (${resolved.candidates.join(', ')}): ${resolved.reason}. Fix or remove malformed spec.json before completing tasks.`
88
+ reason: `Completion gate: invalid workflow packet detected (${resolved.candidates.join(', ')}): ${resolved.reason}. Fix the packet's plan.md or task files before completing tasks.`
92
89
  })}\n`);
93
90
  process.exit(0);
94
91
  }
@@ -101,20 +98,10 @@ try {
101
98
  }
102
99
  if (resolved.error) process.exit(0);
103
100
  const active = resolved;
104
- const activeSpec = active.spec || {};
105
- const processWorkflow = active.layoutKind === 'process-v3';
106
- const lifecyclePhase = activeSpec.current_phase || activeSpec.phase;
107
- const explicitCloseout = ['done', 'completed', 'complete'].includes(activeSpec.status)
108
- || ['closeout', 'completion', 'completed', 'complete'].includes(lifecyclePhase);
109
- // Legacy 2.1 closeout is retired; a 2.1 packet mid-execution keeps the ordinary receipt checks.
110
- if (!processWorkflow && activeSpec.schema_version === '2.1' && explicitCloseout) {
111
- emitBlock('Completion gate: Legacy spec.json closeout is no longer supported; move the packet to plan.md with flat task files');
112
- process.exit(0);
113
- }
114
101
  const runtimeContext = POLICY.deriveRuntimeContext({
115
102
  projectRoot,
116
103
  specsRoot: active.specsDir,
117
- specFile: active.stateFile || active.specFile || path.join(active.specsDir, active.featureName, 'spec.json'),
104
+ specFile: active.stateFile,
118
105
  featureName: active.featureName,
119
106
  runtimeSession: sessionIdentity(payload),
120
107
  });
@@ -123,10 +110,10 @@ try {
123
110
  emitBlock('Completion gate: runtime.spec.completion_gate is a worker-writable flag, not an authorization; no completion-gate bypass is supported. Remove the flag and satisfy the gate.');
124
111
  process.exit(0);
125
112
  }
126
- const registry = active.taskRegistry || activeSpec.task_registry || {};
127
- const currentStatuses = processWorkflow
128
- ? Object.fromEntries(Object.entries(registry).map(([taskPath, task]) => [taskPath, task?.status || 'pending']))
129
- : taskStatusMap(activeSpec);
113
+ const registry = active.taskRegistry || {};
114
+ const currentStatuses = Object.fromEntries(
115
+ Object.entries(registry).map(([taskPath, task]) => [taskPath, task?.status || 'pending']),
116
+ );
130
117
  const cacheFile = path.join(hookStateDir(projectRoot), 'spec-gate-last.json');
131
118
  const cacheExists = fs.existsSync(cacheFile);
132
119
  let cache = {};
@@ -152,16 +139,6 @@ try {
152
139
  const previous = cacheExists && cacheEntries[runtimeContext.context_id]
153
140
  ? cacheEntries[runtimeContext.context_id].tasks || {}
154
141
  : {};
155
- const staleFlashTasks = processWorkflow ? [] : Object.entries(registry)
156
- .filter(([, task]) => POLICY.isStaleFlashDone(task))
157
- .map(([taskPath]) => taskPath);
158
- if (staleFlashTasks.length > 0) {
159
- process.stdout.write(`${JSON.stringify({
160
- decision: 'block',
161
- reason: `Completion gate: ${staleFlashTasks.length} task(s) marked done with FLASH_UNVERIFIED (${staleFlashTasks.join(', ')}). Run /cf:test, then use explicit sync-finalize.`
162
- })}\n`);
163
- process.exit(0);
164
- }
165
142
  const allDoneTasks = Object.keys(registry).filter((taskPath) => (
166
143
  currentStatuses[taskPath] === 'done'
167
144
  ));
@@ -169,9 +146,7 @@ try {
169
146
  const receiptBodies = new Map();
170
147
  const failures = allDoneTasks
171
148
  .map((taskPath) => {
172
- const proof = processWorkflow
173
- ? checkWorkflowReceiptDetails(featureDir, taskPath, runtimeContext)
174
- : checkReceiptDetails(featureDir, taskPath, registry[taskPath], runtimeContext);
149
+ const proof = checkWorkflowReceiptDetails(featureDir, taskPath, runtimeContext);
175
150
  if (proof.body) receiptBodies.set(taskPath, proof.body);
176
151
  return {
177
152
  taskPath,
@@ -180,52 +155,20 @@ try {
180
155
  })
181
156
  .filter((result) => result.failures.length);
182
157
 
183
- const featureCloseoutRequired = !processWorkflow && explicitCloseout && allDoneTasks.length > 0;
184
- const featureReceipt = featureCloseoutRequired
185
- ? checkFeatureReceipt(featureDir, runtimeContext)
186
- : null;
187
- if (featureReceipt && featureReceipt.failures.length) {
188
- failures.push({ taskPath: 'feature-receipt.md', failures: featureReceipt.failures });
189
- }
190
- const completion = featureCloseoutRequired && featureReceipt?.failures.length === 0
191
- && Object.prototype.hasOwnProperty.call(active.spec, 'workflow_policy')
192
- ? POLICY.completionDecisionForSpec(active.spec, {
193
- runtimeContext,
194
- executionReceipt: featureReceipt.body,
195
- taskContext: {},
196
- })
197
- : null;
198
-
199
158
  const next = { ...previous, ...currentStatuses };
200
159
  for (const result of failures) {
201
160
  if (previous[result.taskPath] === undefined) delete next[result.taskPath];
202
161
  else next[result.taskPath] = previous[result.taskPath];
203
162
  }
204
163
  atomicWrite(cacheFile, `${JSON.stringify({
205
- schema_version: '2',
206
164
  entries: { ...cacheEntries, [runtimeContext.context_id]: { identity: cacheIdentity, tasks: next } },
207
165
  })}\n`);
208
166
 
209
- const completionBlocked = completion && completion.completion !== 'complete' && completion.completion !== 'not_applicable';
210
- if (!failures.length && !completionBlocked) process.exit(0);
211
- const lines = [
212
- failures.length > 0
213
- ? `Completion gate: ${failures.length} done task(s) lack a verification receipt.`
214
- : 'Completion gate: workflow completion proof is incomplete.'
215
- ];
167
+ if (!failures.length) process.exit(0);
168
+ const lines = [`Completion gate: ${failures.length} done task(s) lack a verification receipt.`];
216
169
  for (const result of failures) {
217
170
  lines.push(`- \`${result.taskPath}\`: failed check(s) ${result.failures.join(', ')}`);
218
- lines.push(result.taskPath === 'feature-receipt.md'
219
- ? ` Run final integration proof, then write \`specs/${active.featureName}/feature-receipt.md\`.`
220
- : processWorkflow
221
- ? ` In \`specs/${active.featureName}/${path.posix.basename(result.taskPath)}\`: ${receiptFixHint(result.failures, result.body) || 'write a runtime-bound `## Receipt` with command output'}.`
222
- : ` Write canonical proof to \`specs/${active.featureName}/receipts/${path.posix.basename(result.taskPath)}\`; legacy \`## Evidence\` remains read-compatible.`);
223
- }
224
- if (completionBlocked) {
225
- lines.push(`- Completion decision unfinished: ${completion.blocker || 'required workflow proof is missing.'}`);
226
- if (Array.isArray(completion.missingProof) && completion.missingProof.length > 0) {
227
- lines.push(` Missing proof: ${completion.missingProof.join(', ')}`);
228
- }
171
+ lines.push(` In \`specs/${active.featureName}/${path.posix.basename(result.taskPath)}\`: ${receiptFixHint(result.failures, result.body) || 'write a runtime-bound `## Receipt` with command output'}.`);
229
172
  }
230
173
  process.stdout.write(`${JSON.stringify({
231
174
  decision: 'block',