@haposoft/cafekit 0.16.0-rc.3 → 0.16.0-rc.5

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 (98) hide show
  1. package/bin/__tests__/change-firewall.semantic-firewall.test.js +2134 -0
  2. package/bin/__tests__/codex-hooks.test.js +531 -29
  3. package/bin/__tests__/codex-native.test.js +228 -7
  4. package/bin/__tests__/develop-contract.test.js +653 -185
  5. package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +342 -0
  6. package/bin/__tests__/installer-safety.test.js +39 -0
  7. package/bin/__tests__/opencode-spec-gate.test.js +24 -16
  8. package/bin/__tests__/package-inventory.test.js +705 -13
  9. package/bin/__tests__/release-preflight.semantic-firewall.test.js +578 -0
  10. package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +378 -0
  11. package/bin/__tests__/specs-v2-execution-closeout.test.js +468 -0
  12. package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +665 -0
  13. package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +1132 -0
  14. package/bin/__tests__/test-runtime-dependency-closure.cjs +182 -0
  15. package/bin/__tests__/validator-grounding.test.js +2013 -221
  16. package/bin/lib/managed-writer.js +12 -3
  17. package/bin/phases/codex-runtime.js +17 -1
  18. package/package.json +5 -2
  19. package/src/claude/CLAUDE.md +6 -0
  20. package/src/claude/agents/code-auditor.md +20 -0
  21. package/src/claude/agents/spec-maker.md +143 -99
  22. package/src/claude/hooks/__tests__/completion-authority.test.js +321 -58
  23. package/src/claude/hooks/__tests__/privacy-block.test.js +254 -0
  24. package/src/claude/hooks/__tests__/semantic-review-authority.test.js +257 -0
  25. package/src/claude/hooks/__tests__/spec-gate.test.js +115 -40
  26. package/src/claude/hooks/completion-authority-check.cjs +37 -288
  27. package/src/claude/hooks/completion-authority-state.cjs +10 -8
  28. package/src/claude/hooks/completion-authority.cjs +13 -7
  29. package/src/claude/hooks/docs-sync.cjs +5 -2
  30. package/src/claude/hooks/lib/privacy-command-analysis.cjs +393 -0
  31. package/src/claude/hooks/lib/runtime-path-safety.cjs +119 -0
  32. package/src/claude/hooks/privacy-block.cjs +99 -28
  33. package/src/claude/hooks/semantic-review-authority.cjs +152 -0
  34. package/src/claude/hooks/spec-gate.cjs +47 -117
  35. package/src/claude/hooks/spec-state.cjs +8 -2
  36. package/src/claude/migration-manifest.json +9 -1
  37. package/src/claude/rules/state-sync.md +52 -21
  38. package/src/claude/rules/workflow.md +17 -9
  39. package/src/claude/scripts/change-firewall.cjs +1748 -0
  40. package/src/claude/scripts/spec-authoring-digest.cjs +151 -0
  41. package/src/claude/scripts/spec-authoring-validation.cjs +126 -0
  42. package/src/claude/scripts/spec-final-state.cjs +290 -0
  43. package/src/claude/scripts/spec-ground.cjs +571 -173
  44. package/src/claude/scripts/spec-readiness.cjs +425 -0
  45. package/src/claude/scripts/spec-receipt.cjs +162 -0
  46. package/src/claude/scripts/spec-resolver.cjs +67 -16
  47. package/src/claude/scripts/spec-scaffold.cjs +1594 -139
  48. package/src/claude/scripts/spec-semantic-model.cjs +396 -0
  49. package/src/claude/scripts/validate-spec-output.cjs +3110 -218
  50. package/src/claude/scripts/workflow-policy.cjs +501 -183
  51. package/src/claude/settings/settings.json +4 -0
  52. package/src/claude/skills/code-review/SKILL.md +12 -3
  53. package/src/claude/skills/code-review/references/spec-compliance-review.md +10 -2
  54. package/src/claude/skills/code-review/references/verification-gate.md +13 -0
  55. package/src/claude/skills/develop/SKILL.md +47 -60
  56. package/src/claude/skills/develop/references/parallel-waves.md +9 -6
  57. package/src/claude/skills/develop/references/quality-gate.md +19 -12
  58. package/src/claude/skills/specs/SKILL.md +183 -177
  59. package/src/claude/skills/specs/references/ask-user-question-gates.md +27 -18
  60. package/src/claude/skills/specs/references/cross-spec-dependency.md +8 -4
  61. package/src/claude/skills/specs/references/research-strategy.md +4 -1
  62. package/src/claude/skills/specs/references/review.md +214 -262
  63. package/src/claude/skills/specs/references/scope-inquiry.md +18 -5
  64. package/src/claude/skills/specs/rules/design-discovery-full.md +33 -81
  65. package/src/claude/skills/specs/rules/design-discovery-light.md +21 -42
  66. package/src/claude/skills/specs/rules/design-principles.md +136 -180
  67. package/src/claude/skills/specs/rules/design-review.md +42 -97
  68. package/src/claude/skills/specs/rules/ears-format.md +42 -50
  69. package/src/claude/skills/specs/rules/phase-decision-matrix.md +42 -41
  70. package/src/claude/skills/specs/rules/task-scoring-rubric.md +2 -1
  71. package/src/claude/skills/specs/rules/tasks-generation.md +189 -300
  72. package/src/claude/skills/specs/templates/design.md +49 -263
  73. package/src/claude/skills/specs/templates/requirements.md +26 -36
  74. package/src/claude/skills/specs/templates/research.md +9 -98
  75. package/src/claude/skills/specs/templates/spec-state.json +35 -85
  76. package/src/claude/skills/specs/templates/task.md +30 -102
  77. package/src/claude/skills/sync/SKILL.md +33 -10
  78. package/src/claude/skills/sync/references/sync-protocols.md +31 -13
  79. package/src/claude/skills/test/SKILL.md +17 -7
  80. package/src/codex/AGENTS.md +6 -0
  81. package/src/codex/hooks/completion-authority-check.cjs +43 -240
  82. package/src/codex/hooks/completion-authority-state.cjs +10 -8
  83. package/src/codex/hooks/completion-authority.cjs +13 -7
  84. package/src/codex/hooks/lib/hook-context.cjs +16 -2
  85. package/src/codex/hooks/lib/privacy-command-analysis.cjs +3 -0
  86. package/src/codex/hooks/lib/privacy-state.cjs +61 -38
  87. package/src/codex/hooks/lib/runtime-path-safety.cjs +3 -0
  88. package/src/codex/hooks/lib/spec-receipt.cjs +72 -134
  89. package/src/codex/hooks/lib/spec-utils.cjs +56 -5
  90. package/src/codex/hooks/privacy-approval.cjs +6 -2
  91. package/src/codex/hooks/privacy-block.cjs +94 -15
  92. package/src/codex/hooks/semantic-review-authority.cjs +130 -0
  93. package/src/codex/hooks/spec-gate.cjs +49 -34
  94. package/src/codex/hooks/spec-state.cjs +10 -3
  95. package/src/codex/hooks/state.cjs +2 -0
  96. package/src/codex/hooks.json +6 -1
  97. package/src/codex/rules/state-sync.md +47 -27
  98. package/src/common/AGENTS.md +1 -1
@@ -250,9 +250,7 @@ function isPathInsideLegacy(parent, child) {
250
250
  }
251
251
 
252
252
  function explicitTargetValue(value) {
253
- if (typeof value !== 'string') return null;
254
- const trimmed = value.trim();
255
- return trimmed ? trimmed : null;
253
+ return typeof value === 'string' ? value.trim() : value;
256
254
  }
257
255
 
258
256
  /**
@@ -265,12 +263,14 @@ function extractExplicitTarget(...sources) {
265
263
  if (!source || typeof source !== 'object') continue;
266
264
 
267
265
  for (const key of ['explicitFeature', 'featureName', 'feature']) {
268
- const value = explicitTargetValue(source[key]);
269
- if (value) return { explicitFeature: value };
266
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
267
+ return { explicitFeature: explicitTargetValue(source[key]) };
268
+ }
270
269
  }
271
270
  for (const key of ['explicitPath', 'specPath', 'spec_path', 'featurePath']) {
272
- const value = explicitTargetValue(source[key]);
273
- if (value) return { explicitPath: value };
271
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
272
+ return { explicitPath: explicitTargetValue(source[key]) };
273
+ }
274
274
  }
275
275
 
276
276
  const target = source.target;
@@ -278,8 +278,8 @@ function extractExplicitTarget(...sources) {
278
278
  const nested = extractExplicitTarget(target);
279
279
  if (nested) return nested;
280
280
  }
281
- const targetValue = explicitTargetValue(target);
282
- if (targetValue) {
281
+ if (Object.prototype.hasOwnProperty.call(source, 'target')) {
282
+ const targetValue = explicitTargetValue(target);
283
283
  return /[\\/]/.test(targetValue) || /(?:^|[\\/])spec\.json$/.test(targetValue)
284
284
  ? { explicitPath: targetValue }
285
285
  : { explicitFeature: targetValue };
@@ -302,14 +302,23 @@ function resolveActiveSpec({ projectRoot, runtime, explicitFeature, explicitPath
302
302
  if (!projectRoot) throw new TypeError('projectRoot required');
303
303
  const rt = runtime || {};
304
304
  const normalizedTarget = extractExplicitTarget(target);
305
- explicitFeature = explicitFeature || normalizedTarget?.explicitFeature;
306
- explicitPath = explicitPath || normalizedTarget?.explicitPath;
305
+ if (explicitFeature === undefined && normalizedTarget
306
+ && Object.prototype.hasOwnProperty.call(normalizedTarget, 'explicitFeature')) {
307
+ explicitFeature = normalizedTarget.explicitFeature;
308
+ }
309
+ if (explicitPath === undefined && normalizedTarget
310
+ && Object.prototype.hasOwnProperty.call(normalizedTarget, 'explicitPath')) {
311
+ explicitPath = normalizedTarget.explicitPath;
312
+ }
313
+ const hasExplicitFeature = explicitFeature !== undefined && explicitFeature !== null;
314
+ const hasExplicitPath = explicitPath !== undefined && explicitPath !== null;
315
+ const hasExplicitTarget = hasExplicitFeature || hasExplicitPath;
307
316
  let specsDir;
308
317
  try {
309
318
  specsDir = specsDirectory(projectRoot, rt);
310
319
  } catch (error) {
311
320
  return {
312
- error: explicitFeature || explicitPath ? 'explicit_malformed' : 'invalid_specs',
321
+ error: hasExplicitTarget ? 'explicit_malformed' : 'invalid_specs',
313
322
  candidates: ['<specs>'],
314
323
  explicitFeature,
315
324
  explicitPath,
@@ -319,7 +328,7 @@ function resolveActiveSpec({ projectRoot, runtime, explicitFeature, explicitPath
319
328
  let canonicalSpecs;
320
329
  const specsLstat = lstatOptional(specsDir);
321
330
  if (specsLstat.error) {
322
- if (explicitFeature || explicitPath) {
331
+ if (hasExplicitTarget) {
323
332
  return { error: 'explicit_malformed', explicitFeature, explicitPath, reason: `specs lstat error: ${specsLstat.error.message}` };
324
333
  }
325
334
  return { error: 'invalid_specs', candidates: ['<specs>'], invalid: [{ featureName: '<specs>', reason: `specs lstat error: ${specsLstat.error.message}`, specFile: specsDir }], reason: `Invalid spec JSON: <specs>: specs lstat error: ${specsLstat.error.message}` };
@@ -330,14 +339,14 @@ function resolveActiveSpec({ projectRoot, runtime, explicitFeature, explicitPath
330
339
  try {
331
340
  canonicalSpecs = fs.realpathSync(specsDir);
332
341
  } catch (e) {
333
- if (explicitFeature || explicitPath) {
342
+ if (hasExplicitTarget) {
334
343
  return { error: 'explicit_malformed', explicitFeature, explicitPath, reason: `specs root canonicalization error: ${e.message}` };
335
344
  }
336
345
  return { error: 'invalid_specs', candidates: ['<specs>'], invalid: [{ featureName: '<specs>', reason: `specs root canonicalization error: ${e.message}`, specFile: specsDir }], reason: `Invalid spec JSON: <specs>: specs root canonicalization error: ${e.message}` };
337
346
  }
338
347
  }
339
348
 
340
- if (explicitFeature) {
349
+ if (hasExplicitFeature) {
341
350
  if (typeof explicitFeature !== 'string' || explicitFeature.trim() === '' || explicitFeature.includes('/') || explicitFeature.includes('\\') || explicitFeature.includes('..')) {
342
351
  return { error: 'explicit_malformed', explicitFeature, reason: `malformed feature name: ${explicitFeature}` };
343
352
  }
@@ -367,7 +376,7 @@ function resolveActiveSpec({ projectRoot, runtime, explicitFeature, explicitPath
367
376
  }
368
377
  }
369
378
 
370
- if (explicitPath) {
379
+ if (hasExplicitPath) {
371
380
  if (typeof explicitPath !== 'string' || explicitPath.trim() === '') {
372
381
  return { error: 'explicit_malformed', explicitPath, reason: 'empty explicit path' };
373
382
  }
@@ -441,10 +450,52 @@ function resolveActiveSpec({ projectRoot, runtime, explicitFeature, explicitPath
441
450
  };
442
451
  }
443
452
 
453
+ /**
454
+ * Resolve one persisted feature identity. Explicit host targets are inspected
455
+ * directly and never scan siblings; only the no-target path performs a global
456
+ * persisted-candidate scan and therefore owns ambiguity/invalid-sibling errors.
457
+ */
458
+ function resolvePersistedSpec({ projectRoot, runtime, explicitFeature, explicitPath, target } = {}) {
459
+ const normalized = extractExplicitTarget(
460
+ target,
461
+ explicitFeature !== undefined ? { explicitFeature } : null,
462
+ explicitPath !== undefined ? { explicitPath } : null,
463
+ );
464
+ if (normalized) {
465
+ const value = Object.prototype.hasOwnProperty.call(normalized, 'explicitFeature')
466
+ ? normalized.explicitFeature
467
+ : normalized.explicitPath;
468
+ if (value === null || value === undefined) {
469
+ return { error: 'explicit_malformed', ...normalized, reason: 'explicit target must be a non-empty string' };
470
+ }
471
+ return resolveActiveSpec({ projectRoot, runtime, ...normalized });
472
+ }
473
+ try {
474
+ const candidates = findAllSpecCandidates(projectRoot, runtime);
475
+ if (candidates.length === 0) return null;
476
+ if (candidates.length === 1) return candidates[0];
477
+ return {
478
+ error: 'multiple_persisted',
479
+ candidates: candidates.map((candidate) => candidate.featureName),
480
+ reason: `Multiple persisted specs found: ${candidates.map((candidate) => candidate.featureName).join(', ')}. Provide explicit feature.`,
481
+ };
482
+ } catch (error) {
483
+ return {
484
+ error: 'invalid_specs',
485
+ candidates: Array.isArray(error.invalid)
486
+ ? error.invalid.map((entry) => entry.featureName)
487
+ : ['<specs>'],
488
+ invalid: error.invalid || [],
489
+ reason: error.message,
490
+ };
491
+ }
492
+ }
493
+
444
494
  module.exports = {
445
495
  specsDirectory,
446
496
  findAllActiveSpecs,
447
497
  findAllSpecCandidates,
448
498
  extractExplicitTarget,
449
499
  resolveActiveSpec,
500
+ resolvePersistedSpec,
450
501
  };