@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.
- package/README.md +1 -1
- package/bin/__tests__/codex-hooks.test.js +169 -236
- package/bin/__tests__/codex-native.test.js +54 -114
- package/bin/__tests__/develop-contract.test.js +101 -1361
- package/bin/__tests__/legacy-authority-decoupled.test.js +14 -19
- package/bin/__tests__/package-inventory.test.js +1 -395
- package/bin/__tests__/spec-narrowing.test.js +30 -134
- package/bin/__tests__/specs-v2-execution-closeout.test.js +0 -372
- package/bin/__tests__/test-runtime-dependency-closure.cjs +1 -2
- package/bin/__tests__/validator-grounding.test.js +17 -2929
- package/bin/lib/managed-writer.js +2 -3
- package/bin/phases/codex-runtime.js +6 -3
- package/bin/phases/copy-payload.js +13 -28
- package/bin/phases/omp-runtime.js +6 -3
- package/package.json +2 -3
- package/src/claude/agents/code-auditor.md +9 -6
- package/src/claude/agents/debugger.md +3 -9
- package/src/claude/agents/docs-keeper.md +4 -7
- package/src/claude/agents/git-ops.md +2 -4
- package/src/claude/agents/implementer.md +6 -7
- package/src/claude/agents/inspector.md +2 -0
- package/src/claude/agents/project-manager.md +2 -2
- package/src/claude/agents/spec-maker.md +4 -4
- package/src/claude/agents/test-runner.md +8 -11
- package/src/claude/agents/ui-ux-designer.md +0 -1
- package/src/claude/hooks/__tests__/spec-gate.test.js +170 -330
- package/src/claude/hooks/__tests__/spec-state-touched.test.js +26 -0
- package/src/claude/hooks/spec-gate.cjs +8 -63
- package/src/claude/hooks/spec-state.cjs +47 -38
- package/src/claude/migration-manifest.json +12 -7
- package/src/claude/output-styles/coding-level-0-eli5.md +9 -9
- package/src/claude/output-styles/coding-level-1-junior.md +3 -3
- package/src/claude/output-styles/coding-level-2-mid.md +3 -3
- package/src/claude/output-styles/coding-level-3-senior.md +2 -2
- package/src/claude/output-styles/coding-level-4-lead.md +5 -5
- package/src/claude/output-styles/coding-level-5-god.md +6 -6
- package/src/claude/rules/ai-dev-rules.md +1 -2
- package/src/claude/rules/workflow.md +1 -1
- package/src/claude/scripts/spec-receipt.cjs +0 -114
- package/src/claude/scripts/spec-resolver.cjs +41 -457
- package/src/claude/scripts/workflow-policy.cjs +3 -1801
- package/src/claude/skills/agent-browser/SKILL.md +1 -1
- package/src/claude/skills/chrome-devtools/SKILL.md +14 -31
- package/src/claude/skills/code-review/SKILL.md +25 -108
- package/src/claude/skills/code-review/references/spec-compliance-review.md +4 -7
- package/src/claude/skills/develop/SKILL.md +22 -70
- package/src/claude/skills/develop/references/subagent-patterns.md +0 -6
- package/src/claude/skills/research/SKILL.md +24 -55
- package/src/claude/skills/sync/SKILL.md +12 -34
- package/src/claude/skills/sync/references/rebind-and-audit.md +2 -2
- package/src/claude/skills/test/SKILL.md +39 -123
- package/src/claude/skills/test/references/execution-strategy.md +11 -22
- package/src/claude/skills/ui-ux/SKILL.md +1 -1
- package/src/claude/skills/ui-ux-pro-max/SKILL.md +24 -79
- package/src/claude/skills/web-testing/SKILL.md +2 -20
- package/src/codex/hooks/lib/spec-receipt.cjs +2 -30
- package/src/codex/hooks/lib/spec-utils.cjs +6 -45
- package/src/codex/hooks/spec-gate.cjs +11 -68
- package/src/codex/hooks/spec-state.cjs +37 -41
- package/src/common/AGENTS.md +4 -10
- package/bin/__tests__/change-firewall.semantic-firewall.test.js +0 -2133
- package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +0 -342
- package/bin/__tests__/release-preflight.semantic-firewall.test.js +0 -586
- package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +0 -378
- package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +0 -665
- package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +0 -1132
- package/src/claude/hooks/lib/context.cjs +0 -527
- package/src/claude/hooks/lib/detect.cjs +0 -474
- package/src/claude/scripts/change-firewall.cjs +0 -1748
- package/src/claude/scripts/spec-authoring-digest.cjs +0 -151
- package/src/claude/scripts/spec-authoring-validation.cjs +0 -126
- package/src/claude/scripts/spec-final-state.cjs +0 -290
- package/src/claude/scripts/spec-ground.cjs +0 -650
- package/src/claude/scripts/spec-readiness.cjs +0 -425
- package/src/claude/scripts/spec-scaffold.cjs +0 -2317
- package/src/claude/scripts/spec-semantic-model.cjs +0 -396
- package/src/claude/scripts/validate-spec-output.cjs +0 -3914
- package/src/claude/skills/code-review/references/verification-gate.md +0 -41
- package/src/claude/skills/specs/templates/design.md +0 -82
- package/src/claude/skills/specs/templates/requirements-init.md +0 -8
- package/src/claude/skills/specs/templates/requirements.md +0 -42
- package/src/claude/skills/specs/templates/spec-state.json +0 -56
- package/src/claude/skills/specs/templates/task.md +0 -47
|
@@ -6,12 +6,6 @@ const path = require('path');
|
|
|
6
6
|
const { spawnSync } = require('child_process');
|
|
7
7
|
const { annotatedMarkdownLines } = require('./spec-resolver.cjs');
|
|
8
8
|
|
|
9
|
-
const EVIDENCE_HEADINGS = new Set([
|
|
10
|
-
'Evidence',
|
|
11
|
-
'Task Test Plan & Verification Evidence',
|
|
12
|
-
'Verification & Evidence',
|
|
13
|
-
]);
|
|
14
|
-
|
|
15
9
|
function inside(root, target) {
|
|
16
10
|
const relative = path.relative(path.resolve(root), path.resolve(target));
|
|
17
11
|
return relative === '' || (relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
|
@@ -40,34 +34,6 @@ function safeRead(root, relativePath) {
|
|
|
40
34
|
}
|
|
41
35
|
}
|
|
42
36
|
|
|
43
|
-
function canonicalTaskReceiptPath(taskPath) {
|
|
44
|
-
if (typeof taskPath !== 'string') return null;
|
|
45
|
-
const match = taskPath.match(/^tasks\/(task-[A-Za-z0-9][A-Za-z0-9._-]*\.md)$/);
|
|
46
|
-
return match ? `receipts/${match[1]}` : null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function evidenceBody(text, policy = {}) {
|
|
50
|
-
const lines = String(text || '').split('\n');
|
|
51
|
-
let start = -1;
|
|
52
|
-
let level = 0;
|
|
53
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
54
|
-
const match = lines[index].match(/^(#{2,3})\s+(.+?)\s*$/);
|
|
55
|
-
if (match && EVIDENCE_HEADINGS.has(match[2])) {
|
|
56
|
-
start = index + 1;
|
|
57
|
-
level = match[1].length;
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (start < 0) return null;
|
|
62
|
-
let end = lines.length;
|
|
63
|
-
for (let index = start; index < lines.length; index += 1) {
|
|
64
|
-
const heading = lines[index].match(/^(#{1,6})\s+/);
|
|
65
|
-
const tap = typeof policy.isTapMetadataHeading === 'function' && policy.isTapMetadataHeading(lines[index]);
|
|
66
|
-
if (heading && heading[1].length <= level && !tap) { end = index; break; }
|
|
67
|
-
}
|
|
68
|
-
return lines.slice(start, end).join('\n');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
37
|
function workflowReceiptBody(text, policy = {}) {
|
|
72
38
|
const lines = annotatedMarkdownLines(text);
|
|
73
39
|
const starts = [];
|
|
@@ -174,20 +140,6 @@ function workflowCommandFailures(taskText, body) {
|
|
|
174
140
|
: ['command_identity'];
|
|
175
141
|
}
|
|
176
142
|
|
|
177
|
-
function plannedField(taskText, name) {
|
|
178
|
-
const plan = String(taskText || '').split(/^##\s+Verification Plan\s*$/m)[1];
|
|
179
|
-
if (!plan) return null;
|
|
180
|
-
const value = fieldValues(plan.split(/^##\s+/m)[0], `- **${name}**`)[0];
|
|
181
|
-
return value ? value.replace(/^`|`$/g, '').trim() : null;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function identity(body) {
|
|
185
|
-
const names = ['Verification', 'Command', 'Commands', 'Exit', 'Result', 'Base', 'Head', 'base_sha', 'head_sha'];
|
|
186
|
-
const fields = names.flatMap((name) => fieldValues(body, name).map((value) => [name.toLowerCase(), value.trim()]));
|
|
187
|
-
const artifacts = String(body || '').split('\n').filter((line) => /^\s*Artifacts?\s*:|^\s*Artifact\s+produced\b/i.test(line)).map((line) => line.trim());
|
|
188
|
-
return crypto.createHash('sha256').update(JSON.stringify({ fields, artifacts })).digest('hex');
|
|
189
|
-
}
|
|
190
|
-
|
|
191
143
|
function tryGitBytes(root, args) {
|
|
192
144
|
const result = spawnSync('git', ['-C', root, ...args], { encoding: 'buffer', maxBuffer: 64 * 1024 * 1024 });
|
|
193
145
|
if (result.error || result.status !== 0) return null;
|
|
@@ -247,57 +199,6 @@ function canonicalFailures(body, task, runtimeContext, policy, { bindProvenance
|
|
|
247
199
|
return policy.validateCanonicalReceipt(body, options);
|
|
248
200
|
}
|
|
249
201
|
|
|
250
|
-
function separateMetadataFailures(body, taskPath, taskText) {
|
|
251
|
-
const failures = [];
|
|
252
|
-
const basename = path.posix.basename(taskPath);
|
|
253
|
-
if (fieldValues(body, 'Task').length !== 1 || fieldValues(body, 'Task')[0] !== basename) failures.push('task_identity');
|
|
254
|
-
if (fieldValues(body, 'Task path').length !== 1 || fieldValues(body, 'Task path')[0] !== taskPath) failures.push('task_identity');
|
|
255
|
-
if (!concrete(fieldValues(body, 'Expected')[0]) || !concrete(fieldValues(body, 'Observed')[0])) failures.push('expected_observed');
|
|
256
|
-
const plannedCommand = plannedField(taskText, 'Command');
|
|
257
|
-
const actualCommand = fieldValues(body, 'Command')[0] || fieldValues(body, 'Commands')[0];
|
|
258
|
-
if (plannedCommand && !/^N\/A\b/i.test(plannedCommand) && actualCommand !== plannedCommand) failures.push('command_identity');
|
|
259
|
-
for (const name of ['Negative path', 'Reachability']) {
|
|
260
|
-
const planned = plannedField(taskText, name);
|
|
261
|
-
if (planned && !/^(?:N\/A|none|not relevant)\b/i.test(planned) && !concrete(fieldValues(body, name)[0])) failures.push(name.toLowerCase().replace(' ', '_'));
|
|
262
|
-
}
|
|
263
|
-
return [...new Set(failures)];
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function readTaskProof(featureDir, taskPath, policy = {}) {
|
|
267
|
-
const receiptPath = canonicalTaskReceiptPath(taskPath);
|
|
268
|
-
if (typeof taskPath !== 'string' || !/^tasks\/[^/]+\.md$/.test(taskPath)) return { status: 'unsafe', taskPath, receiptPath: null };
|
|
269
|
-
const taskFile = safeRead(featureDir, taskPath);
|
|
270
|
-
if (taskFile.status !== 'ok') return { status: taskFile.status, taskPath, receiptPath };
|
|
271
|
-
const taskText = taskFile.bytes.toString('utf8');
|
|
272
|
-
const separate = receiptPath ? safeRead(featureDir, receiptPath) : { status: 'missing' };
|
|
273
|
-
const legacyBody = evidenceBody(taskText, policy);
|
|
274
|
-
if (separate.status === 'unsafe') return { status: 'unsafe', taskPath, receiptPath, taskFile };
|
|
275
|
-
if (separate.status === 'ok') {
|
|
276
|
-
const body = separate.bytes.toString('utf8');
|
|
277
|
-
return { status: 'ok', source: 'separate', body, receiptBytes: separate.bytes, receiptFile: separate, taskFile, taskText, taskPath, receiptPath, legacyBody };
|
|
278
|
-
}
|
|
279
|
-
if (legacyBody !== null) return { status: 'ok', source: 'legacy', body: legacyBody, receiptBytes: Buffer.from(legacyBody), taskFile, taskText, taskPath, receiptPath, legacyBody };
|
|
280
|
-
return { status: 'missing', taskPath, receiptPath, taskFile, taskText };
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function checkTaskReceipt(featureDir, taskPath, task, runtimeContext, policy) {
|
|
284
|
-
const proof = readTaskProof(featureDir, taskPath, policy);
|
|
285
|
-
const failures = [];
|
|
286
|
-
if (proof.status !== 'ok') return { ...proof, failures: [proof.status === 'unsafe' ? 'unsafe_path' : 'missing_receipt'] };
|
|
287
|
-
const status = proof.taskText.split('\n').find((line) => /^\s*(?:\*\*)?Status(?:\*\*)?\s*:/i.test(line));
|
|
288
|
-
if (!status || !/\bdone\b/i.test(status)) failures.push('task_status');
|
|
289
|
-
failures.push(...canonicalFailures(proof.body, task, runtimeContext, policy));
|
|
290
|
-
if (proof.source === 'separate') {
|
|
291
|
-
failures.push(...separateMetadataFailures(proof.body, taskPath, proof.taskText));
|
|
292
|
-
if (proof.legacyBody !== null
|
|
293
|
-
&& /^\s*Verification:\s*PASS\s*$/m.test(proof.legacyBody)
|
|
294
|
-
&& identity(proof.legacyBody) !== identity(proof.body)) failures.push('receipt_conflict');
|
|
295
|
-
}
|
|
296
|
-
const completedAt = task && task.completed_at;
|
|
297
|
-
if (typeof completedAt !== 'string' || !/^\d{4}-\d{2}-\d{2}T/.test(completedAt) || Number.isNaN(Date.parse(completedAt))) failures.push('completed_at');
|
|
298
|
-
return { ...proof, failures: [...new Set(failures)] };
|
|
299
|
-
}
|
|
300
|
-
|
|
301
202
|
function checkWorkflowTaskReceipt(featureDir, taskPath, runtimeContext, policy) {
|
|
302
203
|
const safeTaskPath = typeof taskPath === 'string' && /^task-[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(taskPath);
|
|
303
204
|
if (!safeTaskPath) return { status: 'unsafe', taskPath, failures: ['unsafe_path'] };
|
|
@@ -433,25 +334,10 @@ function checkWorkflowReceiptSet(candidates, projectRoot, runtimeSession, policy
|
|
|
433
334
|
return { failures };
|
|
434
335
|
}
|
|
435
336
|
|
|
436
|
-
function checkFeatureReceipt(featureDir, runtimeContext, policy) {
|
|
437
|
-
const receipt = safeRead(featureDir, 'feature-receipt.md');
|
|
438
|
-
if (receipt.status !== 'ok') return { status: receipt.status, failures: [receipt.status === 'unsafe' ? 'unsafe_path' : 'missing_receipt'] };
|
|
439
|
-
const body = receipt.bytes.toString('utf8');
|
|
440
|
-
const failures = canonicalFailures(body, {}, runtimeContext, policy);
|
|
441
|
-
if (fieldValues(body, 'Feature').length !== 1 || fieldValues(body, 'Feature')[0] !== path.basename(featureDir)) failures.push('feature_identity');
|
|
442
|
-
if (!concrete(fieldValues(body, 'Expected')[0]) || !concrete(fieldValues(body, 'Observed')[0])) failures.push('expected_observed');
|
|
443
|
-
return { status: 'ok', source: 'feature', body, receiptBytes: receipt.bytes, receiptFile: receipt, failures: [...new Set(failures)] };
|
|
444
|
-
}
|
|
445
|
-
|
|
446
337
|
module.exports = {
|
|
447
|
-
canonicalTaskReceiptPath,
|
|
448
|
-
checkFeatureReceipt,
|
|
449
|
-
checkTaskReceipt,
|
|
450
338
|
checkWorkflowReceiptSet,
|
|
451
339
|
checkWorkflowTaskReceipt,
|
|
452
340
|
receiptFixHint,
|
|
453
|
-
evidenceBody,
|
|
454
|
-
readTaskProof,
|
|
455
341
|
safeRead,
|
|
456
342
|
workflowDependencyProofState,
|
|
457
343
|
workflowReceiptBody,
|