@haposoft/cafekit 0.16.0-rc.2 → 0.16.0-rc.4
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/bin/__tests__/codex-hooks.test.js +794 -21
- package/bin/__tests__/codex-native.test.js +228 -7
- package/bin/__tests__/develop-contract.test.js +1838 -112
- package/bin/__tests__/installer-safety.test.js +82 -29
- package/bin/__tests__/opencode-spec-gate.test.js +799 -0
- package/bin/__tests__/package-inventory.test.js +841 -10
- package/bin/__tests__/specs-v2-execution-closeout.test.js +421 -0
- package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +601 -0
- package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +952 -0
- package/bin/__tests__/test-runtime-dependency-closure.cjs +182 -0
- package/bin/__tests__/validator-grounding.test.js +2469 -71
- package/bin/lib/managed-writer.js +12 -3
- package/bin/phases/codex-runtime.js +17 -1
- package/package.json +1 -1
- package/src/claude/CLAUDE.md +6 -0
- package/src/claude/agents/code-auditor.md +20 -0
- package/src/claude/agents/spec-maker.md +153 -202
- package/src/claude/hooks/__tests__/completion-authority.test.js +953 -0
- package/src/claude/hooks/__tests__/privacy-block.test.js +172 -0
- package/src/claude/hooks/__tests__/semantic-review-authority.test.js +257 -0
- package/src/claude/hooks/__tests__/spec-gate.test.js +604 -56
- package/src/claude/hooks/completion-authority-check.cjs +56 -0
- package/src/claude/hooks/completion-authority-state.cjs +527 -0
- package/src/claude/hooks/completion-authority.cjs +154 -0
- package/src/claude/hooks/docs-sync.cjs +5 -2
- package/src/claude/hooks/lib/privacy-command-analysis.cjs +393 -0
- package/src/claude/hooks/lib/runtime-path-safety.cjs +119 -0
- package/src/claude/hooks/privacy-block.cjs +77 -30
- package/src/claude/hooks/semantic-review-authority.cjs +152 -0
- package/src/claude/hooks/session.cjs +33 -19
- package/src/claude/hooks/spec-gate.cjs +181 -139
- package/src/claude/hooks/spec-state.cjs +112 -47
- package/src/claude/migration-manifest.json +15 -2
- package/src/claude/rules/state-sync.md +52 -21
- package/src/claude/rules/workflow.md +17 -9
- package/src/claude/scripts/provenance.cjs +315 -0
- package/src/claude/scripts/spec-final-state.cjs +244 -0
- package/src/claude/scripts/spec-ground.cjs +535 -173
- package/src/claude/scripts/spec-readiness.cjs +118 -0
- package/src/claude/scripts/spec-receipt.cjs +162 -0
- package/src/claude/scripts/spec-resolver.cjs +501 -0
- package/src/claude/scripts/spec-scaffold.cjs +1945 -55
- package/src/claude/scripts/spec-semantic-model.cjs +396 -0
- package/src/claude/scripts/validate-spec-output.cjs +3204 -262
- package/src/claude/scripts/workflow-policy.cjs +1888 -203
- package/src/claude/settings/settings.json +12 -0
- package/src/claude/skills/code-review/SKILL.md +94 -66
- package/src/claude/skills/code-review/references/spec-compliance-review.md +10 -2
- package/src/claude/skills/code-review/references/verification-gate.md +13 -0
- package/src/claude/skills/develop/SKILL.md +138 -283
- package/src/claude/skills/develop/references/parallel-waves.md +9 -6
- package/src/claude/skills/develop/references/quality-gate.md +123 -148
- package/src/claude/skills/develop/references/subagent-patterns.md +42 -37
- package/src/claude/skills/specs/SKILL.md +192 -397
- package/src/claude/skills/specs/references/ask-user-question-gates.md +27 -18
- package/src/claude/skills/specs/references/cross-spec-dependency.md +8 -4
- package/src/claude/skills/specs/references/research-strategy.md +4 -1
- package/src/claude/skills/specs/references/review.md +200 -260
- package/src/claude/skills/specs/references/scope-inquiry.md +18 -5
- package/src/claude/skills/specs/rules/design-discovery-full.md +33 -81
- package/src/claude/skills/specs/rules/design-discovery-light.md +21 -42
- package/src/claude/skills/specs/rules/design-principles.md +136 -180
- package/src/claude/skills/specs/rules/design-review.md +42 -97
- package/src/claude/skills/specs/rules/ears-format.md +42 -50
- package/src/claude/skills/specs/rules/phase-decision-matrix.md +42 -41
- package/src/claude/skills/specs/rules/task-scoring-rubric.md +46 -46
- package/src/claude/skills/specs/rules/tasks-generation.md +189 -271
- package/src/claude/skills/specs/templates/design.md +49 -263
- package/src/claude/skills/specs/templates/requirements.md +26 -36
- package/src/claude/skills/specs/templates/research.md +9 -98
- package/src/claude/skills/specs/templates/spec-state.json +26 -67
- package/src/claude/skills/specs/templates/task.md +30 -82
- package/src/claude/skills/sync/SKILL.md +45 -15
- package/src/claude/skills/sync/references/sync-protocols.md +34 -16
- package/src/claude/skills/test/SKILL.md +151 -167
- package/src/codex/AGENTS.md +6 -0
- package/src/codex/hooks/completion-authority-check.cjs +63 -0
- package/src/codex/hooks/completion-authority-state.cjs +527 -0
- package/src/codex/hooks/completion-authority.cjs +106 -0
- package/src/codex/hooks/lib/hook-context.cjs +58 -4
- package/src/codex/hooks/lib/privacy-command-analysis.cjs +3 -0
- package/src/codex/hooks/lib/privacy-state.cjs +38 -16
- package/src/codex/hooks/lib/runtime-path-safety.cjs +3 -0
- package/src/codex/hooks/lib/spec-receipt.cjs +86 -115
- package/src/codex/hooks/lib/spec-utils.cjs +104 -27
- package/src/codex/hooks/privacy-approval.cjs +1 -1
- package/src/codex/hooks/privacy-block.cjs +67 -11
- package/src/codex/hooks/semantic-review-authority.cjs +130 -0
- package/src/codex/hooks/session.cjs +2 -0
- package/src/codex/hooks/spec-gate.cjs +151 -24
- package/src/codex/hooks/spec-state.cjs +65 -12
- package/src/codex/hooks/state.cjs +2 -0
- package/src/codex/hooks.json +16 -1
- package/src/codex/rules/state-sync.md +47 -27
- package/src/common/AGENTS.md +1 -1
- package/src/opencode/AGENTS.md +4 -2
- package/src/opencode/plugins/spec-gate.ts +296 -122
- package/src/opencode/plugins/spec-state.ts +183 -116
|
@@ -23,6 +23,7 @@ const { upsertManagedCoreBlock } = require('../lib/instruction-blocks');
|
|
|
23
23
|
const { upsertManagedCodexBlock, normalizeCodexBody } = require('../lib/codex-install');
|
|
24
24
|
const { copyRecursive } = require('../lib/copy-utils');
|
|
25
25
|
const { createTracker, sha256 } = require('../lib/manifest');
|
|
26
|
+
const { copyManagedTree } = require('../lib/managed-writer');
|
|
26
27
|
|
|
27
28
|
const START = '<!-- CAFEKIT CLAUDE START -->';
|
|
28
29
|
const END = '<!-- CAFEKIT CLAUDE END -->';
|
|
@@ -672,6 +673,44 @@ test('managed targets and snapshots reject project symlink traversal', () => {
|
|
|
672
673
|
});
|
|
673
674
|
});
|
|
674
675
|
|
|
676
|
+
test('managed tree copy rejects source and destination symlink traversal before writes', () => {
|
|
677
|
+
inTempProject((root) => {
|
|
678
|
+
const source = path.join(root, 'source');
|
|
679
|
+
const outsideSource = path.join(root, 'outside-source.txt');
|
|
680
|
+
const destination = path.join('.codex', 'payload');
|
|
681
|
+
fs.mkdirSync(source);
|
|
682
|
+
fs.writeFileSync(outsideSource, 'outside');
|
|
683
|
+
fs.symlinkSync(outsideSource, path.join(source, 'linked.txt'));
|
|
684
|
+
const ctx = {
|
|
685
|
+
dryRun: false,
|
|
686
|
+
options: { forceOverwrite: false },
|
|
687
|
+
ownership: {},
|
|
688
|
+
results: { preservedFiles: [] },
|
|
689
|
+
};
|
|
690
|
+
const copy = () => copyManagedTree({
|
|
691
|
+
src: source,
|
|
692
|
+
dest: destination,
|
|
693
|
+
platformFolder: '.codex',
|
|
694
|
+
ctx,
|
|
695
|
+
tracker: null,
|
|
696
|
+
});
|
|
697
|
+
assert.throws(copy, /source tree cannot contain symlinks/i);
|
|
698
|
+
assert.equal(fs.existsSync(destination), false);
|
|
699
|
+
|
|
700
|
+
fs.rmSync(path.join(source, 'linked.txt'));
|
|
701
|
+
fs.writeFileSync(path.join(source, 'safe.txt'), 'safe');
|
|
702
|
+
const outsideDestination = fs.mkdtempSync(path.join(os.tmpdir(), 'cafekit-managed-outside-'));
|
|
703
|
+
try {
|
|
704
|
+
fs.symlinkSync(outsideDestination, path.join(root, '.codex'));
|
|
705
|
+
assert.throws(copy, /Refusing to follow symlinked managed path/);
|
|
706
|
+
assert.deepEqual(fs.readdirSync(outsideDestination), []);
|
|
707
|
+
} finally {
|
|
708
|
+
fs.rmSync(path.join(root, '.codex'), { force: true });
|
|
709
|
+
fs.rmSync(outsideDestination, { recursive: true, force: true });
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
});
|
|
713
|
+
|
|
675
714
|
test('managed Claude Addressing survives force refresh when template drops it', () => {
|
|
676
715
|
inTempProject(() => {
|
|
677
716
|
const before = '# User preface\n\n';
|
|
@@ -761,50 +800,64 @@ test('copyRecursive skips generated artifacts while copying normal files', () =>
|
|
|
761
800
|
});
|
|
762
801
|
});
|
|
763
802
|
|
|
764
|
-
test('OpenCode
|
|
803
|
+
test('OpenCode gate uses a real before-hook block and documents the host boundary', () => {
|
|
765
804
|
const opencodeAgents = fs.readFileSync(path.join(__dirname, '../../src/opencode/AGENTS.md'), 'utf8');
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
805
|
+
const assertOpenCodeBoundary = (content) => {
|
|
806
|
+
assert.match(content, /tool\.execute\.before/);
|
|
807
|
+
assert.match(content, /hard-block supported completion\/state tools/);
|
|
808
|
+
assert.match(content, /`task`, `taskupdate`, and `todowrite`/);
|
|
809
|
+
assert.match(content, /CAFEKIT_SPEC_GATE_BLOCKED/);
|
|
810
|
+
assert.match(content, /`session\.idle`\/Stop/);
|
|
811
|
+
assert.match(content, /final assistant-turn cancellation boundary/);
|
|
812
|
+
assert.match(content, /observational only/);
|
|
813
|
+
assert.match(content, /full-turn parity with Claude\/Codex/);
|
|
814
|
+
assert.doesNotMatch(content, /tool\.execute\.after/);
|
|
815
|
+
assert.doesNotMatch(content, /best-effort/);
|
|
816
|
+
assert.doesNotMatch(content, /tier-2/);
|
|
817
|
+
assert.doesNotMatch(content, /\badvisory\b/i);
|
|
818
|
+
};
|
|
819
|
+
assertOpenCodeBoundary(opencodeAgents);
|
|
820
|
+
|
|
777
821
|
const pluginPath = path.join(__dirname, '../../src/opencode/plugins/spec-gate.ts');
|
|
778
|
-
assert.equal(fs.existsSync(pluginPath), true, 'OpenCode spec-gate plugin must exist
|
|
822
|
+
assert.equal(fs.existsSync(pluginPath), true, 'OpenCode spec-gate plugin must exist');
|
|
779
823
|
const plugin = fs.readFileSync(pluginPath, 'utf8');
|
|
780
|
-
assert.match(plugin, /advisory/i);
|
|
781
824
|
assert.match(plugin, /completion_gate/);
|
|
782
|
-
assert.match(plugin, /
|
|
783
|
-
assert.match(plugin, /
|
|
825
|
+
assert.match(plugin, /tool\.execute\.before/);
|
|
826
|
+
assert.match(plugin, /CAFEKIT_SPEC_GATE_BLOCKED/);
|
|
827
|
+
assert.match(plugin, /throw createBlockError/);
|
|
828
|
+
assert.match(plugin, /session\.idle/);
|
|
829
|
+
assert.match(plugin, /final assistant message[\s\S]*outside this adapter's boundary/);
|
|
830
|
+
assert.doesNotMatch(plugin, /advisory/i);
|
|
831
|
+
assert.doesNotMatch(plugin, /fail-open/i);
|
|
784
832
|
// JSDoc-safe wording: must not contain block-comment-closing pattern specs/*/spec.json
|
|
785
833
|
assert.doesNotMatch(plugin, /specs\/\*\/spec\.json/);
|
|
786
|
-
|
|
787
|
-
// traversal check must be sibling-prefix safe (resolve + relative, not simple startsWith)
|
|
834
|
+
// Traversal check must be sibling-prefix safe (resolve + relative, not simple startsWith).
|
|
788
835
|
assert.match(plugin, /relative\s*\(\s*resolvedFeatureDir/);
|
|
789
836
|
assert.match(plugin, /isAbsolute/);
|
|
790
837
|
assert.doesNotMatch(plugin, /if \(!abs\.startsWith\(featureDir\)\)/);
|
|
791
|
-
//
|
|
792
|
-
assert.match(plugin, /
|
|
793
|
-
assert.match(plugin, /
|
|
794
|
-
assert.match(plugin, /
|
|
795
|
-
|
|
796
|
-
assert.
|
|
797
|
-
|
|
798
|
-
assert.match(plugin, /head_sha\\s\*:\[ \\t\]\*\\S/);
|
|
799
|
-
// shipped docs must not claim OpenCode parity for hard completion gate
|
|
838
|
+
// Single executable authorities: OpenCode delegates both validation and resolution.
|
|
839
|
+
assert.match(plugin, /workflow-policy\.cjs/);
|
|
840
|
+
assert.match(plugin, /spec-resolver\.cjs/);
|
|
841
|
+
assert.match(plugin, /getSharedValidate|validateCanonicalReceipt/);
|
|
842
|
+
assert.doesNotMatch(plugin, /const hasBase\s*&&\s*hasHead/);
|
|
843
|
+
assert.doesNotMatch(plugin, /PLACEHOLDER_TOKENS/);
|
|
844
|
+
|
|
800
845
|
const installerDocs = fs.readFileSync(path.join(__dirname, '../../../../docs/installer-architecture.md'), 'utf8');
|
|
801
846
|
assert.doesNotMatch(installerDocs, /OpenCode.*hard.*completion gate/i);
|
|
802
|
-
|
|
847
|
+
|
|
848
|
+
// Combined install must copy the plugin and both shared authorities.
|
|
803
849
|
inTempProject((root) => {
|
|
804
850
|
const result = spawnSync(process.execPath, [INSTALLER, '--platform', 'opencode', '--yes'], { cwd: root, encoding: 'utf8', env: { ...process.env, PATH: '/usr/bin:/bin' } });
|
|
805
851
|
assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
|
|
806
852
|
assert.equal(fs.existsSync(path.join(root, '.opencode/plugins/spec-gate.ts')), true);
|
|
853
|
+
assert.equal(fs.existsSync(path.join(root, '.opencode/scripts/workflow-policy.cjs')), true);
|
|
854
|
+
assert.equal(fs.existsSync(path.join(root, '.opencode/scripts/spec-resolver.cjs')), true);
|
|
855
|
+
const installedAgents = fs.readFileSync(path.join(root, 'AGENTS.md'), 'utf8');
|
|
856
|
+
assertOpenCodeBoundary(managedBody(installedAgents, OPENCODE_START, OPENCODE_END));
|
|
807
857
|
const installed = fs.readFileSync(path.join(root, '.opencode/plugins/spec-gate.ts'), 'utf8');
|
|
808
|
-
assert.match(installed, /
|
|
858
|
+
assert.match(installed, /tool\.execute\.before/);
|
|
859
|
+
assert.match(installed, /CAFEKIT_SPEC_GATE_BLOCKED/);
|
|
860
|
+
assert.match(installed, /workflow-policy\.cjs/);
|
|
861
|
+
assert.match(installed, /spec-resolver\.cjs/);
|
|
809
862
|
});
|
|
810
863
|
});
|