@haposoft/cafekit 0.16.0-rc.6 → 0.16.0-rc.8
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 +21 -58
- package/bin/__tests__/change-firewall.semantic-firewall.test.js +4 -5
- package/bin/__tests__/codex-hooks.test.js +382 -0
- package/bin/__tests__/codex-native.test.js +579 -80
- package/bin/__tests__/develop-contract.test.js +155 -76
- package/bin/__tests__/installer-safety.test.js +19 -154
- package/bin/__tests__/package-inventory.test.js +494 -26
- package/bin/__tests__/release-preflight.semantic-firewall.test.js +2 -2
- package/bin/__tests__/validator-grounding.test.js +11 -11
- package/bin/install.js +2 -7
- package/bin/lib/context.js +0 -45
- package/bin/lib/copy-utils.js +1 -1
- package/bin/lib/i18n.js +0 -3
- package/bin/lib/manifest.js +1 -1
- package/bin/phases/claude-runtime.js +1 -3
- package/bin/phases/codex-runtime.js +4 -2
- package/bin/phases/copy-payload.js +3 -15
- package/bin/phases/post-install.js +5 -17
- package/bin/phases/root-config.js +2 -3
- package/bin/phases/select-platform.js +2 -5
- package/bin/phases/summary.js +0 -1
- package/package.json +2 -5
- package/src/claude/CLAUDE.md +19 -6
- package/src/claude/agents/project-manager.md +41 -9
- package/src/claude/agents/spec-maker.md +82 -155
- package/src/claude/gitignore +1 -1
- package/src/claude/hooks/__tests__/spec-gate.test.js +238 -0
- package/src/claude/hooks/__tests__/state.test.js +249 -3
- package/src/claude/hooks/lib/context.cjs +1 -1
- package/src/claude/hooks/lib/detect.cjs +1 -1
- package/src/claude/hooks/spec-gate.cjs +44 -9
- package/src/claude/hooks/spec-state.cjs +51 -13
- package/src/claude/hooks/task-scaffold-guard.cjs +1 -1
- package/src/claude/migration-manifest.json +17 -3
- package/src/claude/rules/manage-docs.md +43 -24
- package/src/claude/rules/state-sync.md +57 -62
- package/src/claude/rules/workflow.md +30 -13
- package/src/claude/scripts/change-firewall.cjs +2 -2
- package/src/claude/scripts/generate-skill-catalog.cjs +0 -1
- package/src/claude/scripts/spec-receipt.cjs +196 -1
- package/src/claude/scripts/spec-resolver.cjs +428 -0
- package/src/claude/skills/develop/SKILL.md +89 -125
- package/src/claude/skills/develop/references/parallel-waves.md +75 -162
- package/src/claude/skills/develop/references/quality-gate.md +61 -121
- package/src/claude/skills/develop/references/subagent-patterns.md +31 -38
- package/src/claude/skills/question/SKILL.md +1 -1
- package/src/claude/skills/specs/SKILL.md +152 -204
- package/src/claude/skills/specs/references/review.md +124 -243
- package/src/claude/skills/specs/references/templates.md +202 -0
- package/src/claude/skills/sync/SKILL.md +66 -90
- package/src/claude/skills/sync/references/sync-protocols.md +62 -83
- package/src/codex/AGENTS.md +20 -7
- package/src/codex/hooks/lib/spec-receipt.cjs +18 -0
- package/src/codex/hooks/lib/spec-utils.cjs +25 -0
- package/src/codex/hooks/spec-gate.cjs +46 -16
- package/src/codex/hooks/spec-state.cjs +54 -16
- package/src/codex/rules/state-sync.md +57 -61
- package/src/common/AGENTS.md +8 -1
- package/bin/__tests__/opencode-spec-gate.test.js +0 -799
- package/bin/lib/opencode-install.js +0 -899
- package/bin/phases/opencode-runtime.js +0 -38
- package/src/claude/skills/specs/references/archive-workflow.md +0 -74
- package/src/claude/skills/specs/references/ask-user-question-gates.md +0 -70
- package/src/claude/skills/specs/references/codebase-analysis.md +0 -102
- package/src/claude/skills/specs/references/cross-spec-dependency.md +0 -76
- package/src/claude/skills/specs/references/research-strategy.md +0 -107
- package/src/claude/skills/specs/references/scope-inquiry.md +0 -107
- package/src/claude/skills/specs/references/translation-mirror.md +0 -83
- package/src/claude/skills/specs/rules/design-discovery-full.md +0 -45
- package/src/claude/skills/specs/rules/design-discovery-light.md +0 -28
- package/src/claude/skills/specs/rules/design-principles.md +0 -138
- package/src/claude/skills/specs/rules/design-review.md +0 -55
- package/src/claude/skills/specs/rules/ears-format.md +0 -42
- package/src/claude/skills/specs/rules/phase-decision-matrix.md +0 -56
- package/src/claude/skills/specs/rules/task-scoring-rubric.md +0 -52
- package/src/claude/skills/specs/rules/tasks-generation.md +0 -189
- package/src/opencode/AGENTS.md +0 -41
- package/src/opencode/plugins/docs-sync.ts +0 -175
- package/src/opencode/plugins/inspect-block.ts +0 -164
- package/src/opencode/plugins/privacy-block.ts +0 -182
- package/src/opencode/plugins/rules.ts +0 -155
- package/src/opencode/plugins/session.ts +0 -179
- package/src/opencode/plugins/spec-gate.ts +0 -457
- package/src/opencode/plugins/spec-state.ts +0 -311
- package/src/opencode/plugins/state.ts +0 -253
- package/src/opencode/plugins/task-scaffold-guard.ts +0 -161
- package/src/opencode/plugins/usage.ts +0 -178
|
@@ -525,9 +525,8 @@ The transition records success, failure, and recovery states.
|
|
|
525
525
|
test('Codex installer transform preserves all owned spec assets with idempotent runtime parity', () => {
|
|
526
526
|
for (const relative of [
|
|
527
527
|
'src/claude/skills/specs/SKILL.md',
|
|
528
|
-
'src/claude/skills/specs/rules/tasks-generation.md',
|
|
529
|
-
'src/claude/skills/specs/rules/design-principles.md',
|
|
530
528
|
'src/claude/skills/specs/references/review.md',
|
|
529
|
+
'src/claude/skills/specs/references/templates.md',
|
|
531
530
|
'src/claude/skills/specs/templates/design.md',
|
|
532
531
|
'src/claude/skills/specs/templates/task.md',
|
|
533
532
|
'src/claude/scripts/spec-scaffold.cjs',
|
|
@@ -548,14 +547,15 @@ test('Codex installer transform preserves all owned spec assets with idempotent
|
|
|
548
547
|
|
|
549
548
|
const skill = fs.readFileSync(path.join(ROOT, 'src/claude/skills/specs/SKILL.md'), 'utf8');
|
|
550
549
|
const review = fs.readFileSync(path.join(ROOT, 'src/claude/skills/specs/references/review.md'), 'utf8');
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
assert.match(skill,
|
|
554
|
-
assert.
|
|
555
|
-
assert.
|
|
556
|
-
assert.match(
|
|
557
|
-
assert.match(
|
|
558
|
-
assert.match(
|
|
550
|
+
const templates = fs.readFileSync(path.join(ROOT, 'src/claude/skills/specs/references/templates.md'), 'utf8');
|
|
551
|
+
assert.match(skill, /specs\/<feature>\/[\s\S]{0,160}plan\.md[\s\S]{0,160}task-01-<slug>\.md/);
|
|
552
|
+
assert.match(skill, /C1 — Scope[\s\S]*C2 — Findings[\s\S]*C3 — Done/);
|
|
553
|
+
assert.doesNotMatch(skill, /--(?:status|validate|archive)\b/);
|
|
554
|
+
assert.match(review, /path:line/);
|
|
555
|
+
assert.match(review, /Cap the presented[\s\S]{0,40}list at 15/);
|
|
556
|
+
assert.match(review, /Round three requires runtime evidence/);
|
|
557
|
+
assert.match(templates, /\| ID \| EARS criterion \| Proof \|/);
|
|
558
|
+
assert.match(templates, /## Canonical inline Receipt[\s\S]*Verification: PASS[\s\S]*Exit: 0[\s\S]*Base:[\s\S]*Head:/);
|
|
559
559
|
|
|
560
560
|
const parityRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cafekit-codex-validator-parity-'));
|
|
561
561
|
try {
|
|
@@ -3201,7 +3201,7 @@ test('D11/R1.14: the legacy-bridge precondition artifact is reachable and change
|
|
|
3201
3201
|
// resolves its own production root the same way, via git from its own file
|
|
3202
3202
|
// location) -- ROOT here is packages/spec, one level below that root.
|
|
3203
3203
|
const MONOREPO_ROOT = path.resolve(ROOT, '..', '..');
|
|
3204
|
-
const bridgePath = path.join(MONOREPO_ROOT, 'specs/cafekit-semantic-eval-firewall/reports/bootstrap-legacy-bridge-review.json');
|
|
3204
|
+
const bridgePath = path.join(MONOREPO_ROOT, 'specs/archive/cafekit-semantic-eval-firewall/reports/bootstrap-legacy-bridge-review.json');
|
|
3205
3205
|
assert.ok(fs.existsSync(bridgePath), 'the legacy-bridge artifact must exist before any R0-01 change-firewall assertion runs');
|
|
3206
3206
|
const parsed = CHANGE_FIREWALL.assertLegacyBridgeArtifact();
|
|
3207
3207
|
assert.equal(parsed.schema_version, '1');
|
package/bin/install.js
CHANGED
|
@@ -33,7 +33,6 @@ const {
|
|
|
33
33
|
removeObsoleteAgents
|
|
34
34
|
} = require('./phases/claude-runtime');
|
|
35
35
|
const { mergeClaudeSettings } = require('./phases/claude-settings');
|
|
36
|
-
const { installOpenCodeRuntime } = require('./phases/opencode-runtime');
|
|
37
36
|
const { installCodexRuntime } = require('./phases/codex-runtime');
|
|
38
37
|
const { writePlatformVersionMetadata } = require('./phases/write-metadata');
|
|
39
38
|
const { checkVersions } = require('./lib/version-check');
|
|
@@ -70,10 +69,6 @@ function installPlatform(ctx, platformKey) {
|
|
|
70
69
|
copyRulesDirectory(ctx, platformKey);
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
if (platformKey === 'opencode') {
|
|
74
|
-
installOpenCodeRuntime(ctx, platformKey);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
72
|
if (platformKey === 'codex') {
|
|
78
73
|
installCodexRuntime(ctx, platformKey);
|
|
79
74
|
}
|
|
@@ -95,11 +90,11 @@ function printHelp() {
|
|
|
95
90
|
Usage: npx @haposoft/cafekit [options]
|
|
96
91
|
|
|
97
92
|
Installs CafeKit skills, agents, rules and runtime into the current project
|
|
98
|
-
for Claude Code
|
|
93
|
+
for Claude Code and/or Codex CLI. Re-runs are selective: managed files are updated,
|
|
99
94
|
your edits are preserved.
|
|
100
95
|
|
|
101
96
|
Options:
|
|
102
|
-
--platform <id[,id]> Select claude
|
|
97
|
+
--platform <id[,id]> Select claude or codex explicitly
|
|
103
98
|
--dry-run Preview changes; write nothing
|
|
104
99
|
--force-overwrite Overwrite user-modified managed files (backup kept)
|
|
105
100
|
-u, --upgrade, -f, --force Alias of --force-overwrite
|
package/bin/lib/context.js
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const path = require('path');
|
|
15
15
|
const packageJson = require('../../package.json');
|
|
16
|
-
const { getOpenCodeCopyOptions } = require('./opencode-install');
|
|
17
16
|
const { isInteractive, createUI } = require('./ui');
|
|
18
17
|
const { resolveLang, createTranslator } = require('./i18n');
|
|
19
18
|
const { normalizeSourcePaths } = require('./copy-utils');
|
|
@@ -57,12 +56,10 @@ function loadClaudeMigrationManifest() {
|
|
|
57
56
|
const DEPENDENCY_TEMPLATES = {
|
|
58
57
|
commands: {
|
|
59
58
|
claude: {},
|
|
60
|
-
opencode: {},
|
|
61
59
|
codex: {}
|
|
62
60
|
},
|
|
63
61
|
agents: {
|
|
64
62
|
claude: {},
|
|
65
|
-
opencode: {},
|
|
66
63
|
codex: {}
|
|
67
64
|
}
|
|
68
65
|
};
|
|
@@ -93,29 +90,6 @@ const PLATFORMS = {
|
|
|
93
90
|
commands: true
|
|
94
91
|
}
|
|
95
92
|
},
|
|
96
|
-
opencode: {
|
|
97
|
-
id: 'opencode',
|
|
98
|
-
name: 'OpenCode',
|
|
99
|
-
description: 'OpenCode terminal AI coding agent',
|
|
100
|
-
folder: '.opencode',
|
|
101
|
-
detectFiles: ['.opencode', 'opencode.json', 'opencode.jsonc'],
|
|
102
|
-
commandsDir: '.opencode/commands',
|
|
103
|
-
skillsDir: '.opencode/skills',
|
|
104
|
-
agentsDir: '.opencode/agents',
|
|
105
|
-
skillsRef: '.opencode/skills',
|
|
106
|
-
commandPrefix: '/',
|
|
107
|
-
sourceDir: 'claude',
|
|
108
|
-
sourceSubdir: 'commands', // Dead config (manifest commands.core is []); kept for shape parity
|
|
109
|
-
backupTargets: ['.opencode', 'AGENTS.md', 'opencode.json', 'opencode.jsonc'],
|
|
110
|
-
capabilities: {
|
|
111
|
-
skills: true,
|
|
112
|
-
agents: true,
|
|
113
|
-
references: true,
|
|
114
|
-
scripts: true,
|
|
115
|
-
rules: true,
|
|
116
|
-
commands: false
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
93
|
codex: {
|
|
120
94
|
id: 'codex',
|
|
121
95
|
name: 'Codex CLI',
|
|
@@ -192,26 +166,8 @@ function getRuntimeSupportTargetDir(platformKey, subdir) {
|
|
|
192
166
|
return path.join(PLATFORMS[platformKey].folder, subdir);
|
|
193
167
|
}
|
|
194
168
|
|
|
195
|
-
// Warn opencode-only installs when a legacy .claude/ folder remains from
|
|
196
|
-
// pre-0.9.0 installs (when OpenCode shared the .claude/ runtime). We do not
|
|
197
|
-
// delete anything; user must remove it explicitly to opt in.
|
|
198
|
-
function warnLegacyClaudeFolder(platforms) {
|
|
199
|
-
if (!platforms.includes('opencode')) return;
|
|
200
|
-
if (platforms.includes('claude')) return;
|
|
201
|
-
if (!fs.existsSync('.claude')) return;
|
|
202
|
-
|
|
203
|
-
console.log('');
|
|
204
|
-
console.log('⚠ Legacy .claude/ folder detected.');
|
|
205
|
-
console.log(' As of CafeKit 0.9.0, OpenCode installs are self-contained under .opencode/.');
|
|
206
|
-
console.log(' The .claude/ folder from older installs is no longer used by OpenCode.');
|
|
207
|
-
console.log(' After this install finishes you can remove it: rm -rf .claude');
|
|
208
|
-
console.log('');
|
|
209
|
-
}
|
|
210
169
|
|
|
211
170
|
function getCopyOptions(platformKey, baseOptions = {}) {
|
|
212
|
-
if (platformKey === 'opencode') {
|
|
213
|
-
return getOpenCodeCopyOptions(baseOptions);
|
|
214
|
-
}
|
|
215
171
|
if (platformKey === 'codex') {
|
|
216
172
|
// Lazy require avoids coupling the shared registry to a runtime adapter
|
|
217
173
|
// during module initialization.
|
|
@@ -358,7 +314,6 @@ module.exports = {
|
|
|
358
314
|
getPlatformKeys,
|
|
359
315
|
hasPlatformCapability,
|
|
360
316
|
getRuntimeSupportTargetDir,
|
|
361
|
-
warnLegacyClaudeFolder,
|
|
362
317
|
getCopyOptions,
|
|
363
318
|
parseInstallerArgs,
|
|
364
319
|
createResults,
|
package/bin/lib/copy-utils.js
CHANGED
|
@@ -13,7 +13,7 @@ function isTextAsset(filePath) {
|
|
|
13
13
|
|
|
14
14
|
// Generated artifacts never ship as runtime payload: the coverage db, the
|
|
15
15
|
// Python bytecode cache directory, and bytecode files. Skipping them here keeps
|
|
16
|
-
// both copyRecursive and copyManagedTree
|
|
16
|
+
// both copyRecursive and copyManagedTree
|
|
17
17
|
// built on copyRecursive) from ever copying build residue.
|
|
18
18
|
function isGeneratedArtifact(name) {
|
|
19
19
|
const base = String(name || '');
|
package/bin/lib/i18n.js
CHANGED
|
@@ -107,7 +107,6 @@ const MESSAGES = {
|
|
|
107
107
|
// Next steps
|
|
108
108
|
nextStepsTitle: 'Next steps',
|
|
109
109
|
nsClaude: 'Start coding: /hapo:specs <feature>',
|
|
110
|
-
nsOpencode: 'Start coding: ask the agent to begin a new feature or brainstorm',
|
|
111
110
|
nsCodex: 'Start with `$hapo-specs <feature>`; review and trust project hooks with `/hooks`',
|
|
112
111
|
nsKeys: 'Some skills need API keys: {skills}\n Copy <skill>/.env.example → .env and fill in the values',
|
|
113
112
|
nsForce: 'To force-refresh managed files: npx @haposoft/cafekit --force-overwrite',
|
|
@@ -228,7 +227,6 @@ const MESSAGES = {
|
|
|
228
227
|
|
|
229
228
|
nextStepsTitle: '次のステップ',
|
|
230
229
|
nsClaude: 'コーディング開始: /hapo:specs <機能名>',
|
|
231
|
-
nsOpencode: 'コーディング開始: エージェントに新機能の開始またはブレストを依頼',
|
|
232
230
|
nsCodex: '`$hapo-specs <機能名>` で開始し、`/hooks` でプロジェクトフックを確認・信頼',
|
|
233
231
|
nsKeys: '一部のスキルに API キーが必要です: {skills}\n <skill>/.env.example を .env にコピーし、値を入力してください',
|
|
234
232
|
nsForce: '管理ファイルを強制更新: npx @haposoft/cafekit --force-overwrite',
|
|
@@ -348,7 +346,6 @@ const MESSAGES = {
|
|
|
348
346
|
|
|
349
347
|
nextStepsTitle: 'Bước tiếp theo',
|
|
350
348
|
nsClaude: 'Bắt đầu code: /hapo:specs <mô-tả-tính-năng>',
|
|
351
|
-
nsOpencode: 'Bắt đầu code: yêu cầu agent khởi động tính năng mới hoặc brainstorm',
|
|
352
349
|
nsCodex: 'Bắt đầu bằng `$hapo-specs <tính-năng>`; kiểm tra và trust project hooks bằng `/hooks`',
|
|
353
350
|
nsKeys: 'Một số skill cần API key: {skills}\n Sao chép <skill>/.env.example → .env rồi điền giá trị',
|
|
354
351
|
nsForce: 'Làm mới file được quản lý: npx @haposoft/cafekit --force-overwrite',
|
package/bin/lib/manifest.js
CHANGED
|
@@ -169,7 +169,7 @@ function createTracker(platformFolder, version, options = {}) {
|
|
|
169
169
|
* Classify a managed file against the recorded baseline + the incoming payload.
|
|
170
170
|
*
|
|
171
171
|
* @param {string} absPath destination path on disk
|
|
172
|
-
* @param {string} platformFolder root of the platform install (.claude
|
|
172
|
+
* @param {string} platformFolder root of the platform install (e.g. .claude)
|
|
173
173
|
* @param {object} manifest result of read(platformFolder)
|
|
174
174
|
* @param {string} payloadHash sha256 of the content about to be written
|
|
175
175
|
* @returns {{state: string, diskHash: string|null, recordedHash: string|null, changed: boolean}}
|
|
@@ -18,7 +18,6 @@ const {
|
|
|
18
18
|
const { sha256 } = require('../lib/manifest');
|
|
19
19
|
const { writeManagedFile, copyManagedTree } = require('../lib/managed-writer');
|
|
20
20
|
const { report, treeAction } = require('./report');
|
|
21
|
-
const { normalizeOpenCodeBody } = require('../lib/opencode-install');
|
|
22
21
|
const {
|
|
23
22
|
upsertManagedCoreBlock,
|
|
24
23
|
managedRange,
|
|
@@ -120,7 +119,7 @@ function copyClaudeAgentsMdFile(ctx, platformKey) {
|
|
|
120
119
|
ensureSharedAgentsMdCore(ctx);
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
/** Copy ROUTING.md (SKILLS_DIR substituted
|
|
122
|
+
/** Copy ROUTING.md (SKILLS_DIR substituted). */
|
|
124
123
|
function copyRoutingFile(ctx, platformKey) {
|
|
125
124
|
const platform = PLATFORMS[platformKey];
|
|
126
125
|
const src = path.join(SRC, platform.sourceDir, 'ROUTING.md');
|
|
@@ -129,7 +128,6 @@ function copyRoutingFile(ctx, platformKey) {
|
|
|
129
128
|
|
|
130
129
|
const transform = (content) => {
|
|
131
130
|
let c = content.replace(/\{\{SKILLS_DIR\}\}/g, platform.skillsRef);
|
|
132
|
-
if (platformKey === 'opencode') c = normalizeOpenCodeBody(c);
|
|
133
131
|
return c;
|
|
134
132
|
};
|
|
135
133
|
const { action } = writeManagedFile({
|
|
@@ -7,7 +7,6 @@ const { writeManagedFile, copyManagedTree } = require('../lib/managed-writer');
|
|
|
7
7
|
const { report, treeAction } = require('./report');
|
|
8
8
|
const { copyRulesDirectory } = require('./claude-runtime');
|
|
9
9
|
const {
|
|
10
|
-
normalizeCodexBody,
|
|
11
10
|
managedRange,
|
|
12
11
|
upsertManagedCodexBlock
|
|
13
12
|
} = require('../lib/codex-install');
|
|
@@ -138,7 +137,10 @@ function installManagedAgentsMd(ctx) {
|
|
|
138
137
|
ctx.results.errors++;
|
|
139
138
|
return;
|
|
140
139
|
}
|
|
141
|
-
|
|
140
|
+
// This template is already Codex-native. Running it through the generic
|
|
141
|
+
// Claude-to-Codex converter corrupts intentional cross-runtime wording such
|
|
142
|
+
// as the fail-safe instruction for Claude Code to ignore this block.
|
|
143
|
+
const block = fs.readFileSync(runtimeSource, 'utf8');
|
|
142
144
|
const next = upsertManagedCodexBlock(existing, block);
|
|
143
145
|
const action = !exists ? 'created' : next === existing ? 'unchanged' : 'updated';
|
|
144
146
|
|
|
@@ -17,10 +17,6 @@ const {
|
|
|
17
17
|
} = require('../lib/context');
|
|
18
18
|
const { writeManagedFile, copyManagedTree } = require('../lib/managed-writer');
|
|
19
19
|
const { report, treeAction } = require('./report');
|
|
20
|
-
const {
|
|
21
|
-
convertOpenCodeAgentContent,
|
|
22
|
-
convertOpenCodeCommandContent
|
|
23
|
-
} = require('../lib/opencode-install');
|
|
24
20
|
const {
|
|
25
21
|
codexAgentName,
|
|
26
22
|
convertCodexAgentContent
|
|
@@ -29,8 +25,7 @@ const {
|
|
|
29
25
|
const SRC = path.join(__dirname, '../../src');
|
|
30
26
|
|
|
31
27
|
/**
|
|
32
|
-
* Spec command files installed for a platform. Claude ships spec-* commands
|
|
33
|
-
* OpenCode generates its own command wrappers elsewhere.
|
|
28
|
+
* Spec command files installed for a platform. Claude ships spec-* commands.
|
|
34
29
|
*/
|
|
35
30
|
function getPlatformSpecFiles(platformKey, ctx) {
|
|
36
31
|
if (platformKey === 'claude') {
|
|
@@ -76,7 +71,6 @@ function copyPlatformFiles(ctx, platformKey) {
|
|
|
76
71
|
const tracker = ctx.trackers[platformKey];
|
|
77
72
|
const platformFolder = platform.folder;
|
|
78
73
|
|
|
79
|
-
// For OpenCode, text bodies are path-normalized (.claude → .opencode, etc.).
|
|
80
74
|
const bodyTransform = getCopyOptions(platformKey, {}).transform;
|
|
81
75
|
|
|
82
76
|
const skillsSourceDir = path.join(SRC, 'claude/skills');
|
|
@@ -162,9 +156,7 @@ function copyPlatformFiles(ctx, platformKey) {
|
|
|
162
156
|
'tester.md', 'code-reviewer.md', 'fullstack-developer.md', 'debugger.md'
|
|
163
157
|
];
|
|
164
158
|
let agentTransform;
|
|
165
|
-
if (platformKey === '
|
|
166
|
-
agentTransform = (content, src) => convertOpenCodeAgentContent(content, path.basename(src));
|
|
167
|
-
} else if (platformKey === 'codex') {
|
|
159
|
+
if (platformKey === 'codex') {
|
|
168
160
|
agentTransform = (content, src) => convertCodexAgentContent(content, path.basename(src));
|
|
169
161
|
}
|
|
170
162
|
|
|
@@ -222,11 +214,7 @@ function copyPlatformFiles(ctx, platformKey) {
|
|
|
222
214
|
return;
|
|
223
215
|
}
|
|
224
216
|
const cmdTransform = (content, s) => {
|
|
225
|
-
|
|
226
|
-
if (platformKey === 'opencode') {
|
|
227
|
-
c = convertOpenCodeCommandContent(c, path.basename(s));
|
|
228
|
-
}
|
|
229
|
-
return c;
|
|
217
|
+
return content.replace(/\{\{SKILLS_DIR\}\}/g, platform.skillsRef);
|
|
230
218
|
};
|
|
231
219
|
const { action } = writeManagedFile({
|
|
232
220
|
src, dest, platformFolder, ctx, tracker, transform: cmdTransform
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Phase: post-install runtime configuration.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Addressing config. Interactive prompts use ctx.ui (clack);
|
|
5
5
|
* in non-interactive/dry-run they are skipped via fallbacks so spawned/CI runs
|
|
6
6
|
* never hang.
|
|
7
7
|
*
|
|
@@ -15,14 +15,12 @@ const fs = require('fs');
|
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const { PLATFORMS } = require('../lib/context');
|
|
17
17
|
const { LANGUAGE_LABELS } = require('../lib/i18n');
|
|
18
|
-
const { setupOpenCodeModel, transformManagedOpenCodeContent } = require('../lib/opencode-install');
|
|
19
18
|
const { transformManagedCodexContent } = require('../lib/codex-install');
|
|
20
19
|
const { transformManagedClaudeContent } = require('./claude-runtime');
|
|
21
20
|
const { transformManagedCoreContent } = require('../lib/instruction-blocks');
|
|
22
21
|
const ASSISTANT_NAMES = {
|
|
23
22
|
claude: 'Claude Code',
|
|
24
|
-
codex: 'Codex CLI'
|
|
25
|
-
opencode: 'OpenCode'
|
|
23
|
+
codex: 'Codex CLI'
|
|
26
24
|
};
|
|
27
25
|
const LANGUAGE_LABEL_BY_CODE = {
|
|
28
26
|
vi: 'Vietnamese',
|
|
@@ -50,10 +48,6 @@ function instructionTargets(ctx) {
|
|
|
50
48
|
file: path.join(process.cwd(), 'AGENTS.md'),
|
|
51
49
|
transform: transformManagedCodexContent
|
|
52
50
|
},
|
|
53
|
-
opencode: {
|
|
54
|
-
file: path.join(process.cwd(), 'AGENTS.md'),
|
|
55
|
-
transform: transformManagedOpenCodeContent
|
|
56
|
-
}
|
|
57
51
|
};
|
|
58
52
|
return Object.keys(targets)
|
|
59
53
|
.filter((key) => ctx.platforms.includes(key))
|
|
@@ -161,7 +155,7 @@ function patchRuntimeLocale(ctx) {
|
|
|
161
155
|
|
|
162
156
|
/** Human assistant name for the active platform(s). */
|
|
163
157
|
function assistantName(platformKey) {
|
|
164
|
-
return ASSISTANT_NAMES[platformKey] ||
|
|
158
|
+
return ASSISTANT_NAMES[platformKey] || platformKey;
|
|
165
159
|
}
|
|
166
160
|
|
|
167
161
|
function configureAddressing(ctx, userAddress) {
|
|
@@ -188,7 +182,7 @@ ${name} always addresses the user as "${userAddress}" throughout the conversatio
|
|
|
188
182
|
}
|
|
189
183
|
|
|
190
184
|
async function setupAddressing(ctx) {
|
|
191
|
-
if (!ctx.platforms.some((key) => key === 'claude' || key === 'codex'
|
|
185
|
+
if (!ctx.platforms.some((key) => key === 'claude' || key === 'codex')) return;
|
|
192
186
|
|
|
193
187
|
let existingName = null;
|
|
194
188
|
for (const target of instructionTargets(ctx)) {
|
|
@@ -237,16 +231,10 @@ async function setupAddressing(ctx) {
|
|
|
237
231
|
/** Run the post-install configuration sequence. */
|
|
238
232
|
async function runPostInstall(ctx) {
|
|
239
233
|
if (ctx.dryRun) {
|
|
240
|
-
ctx.ui.info('[dry-run] Skipping
|
|
234
|
+
ctx.ui.info('[dry-run] Skipping addressing setup');
|
|
241
235
|
return ctx;
|
|
242
236
|
}
|
|
243
237
|
|
|
244
|
-
// OpenCode model uses its own readline; only run it when it won't block:
|
|
245
|
-
// interactive, or an env override is present (which it reads without prompting).
|
|
246
|
-
const hasModelEnv = Boolean(process.env.OPENCODE_MODEL || process.env.OPENCODE_DEFAULT_MODEL);
|
|
247
|
-
if (ctx.platforms.includes('opencode') && (ctx.interactive || hasModelEnv)) {
|
|
248
|
-
await setupOpenCodeModel(ctx.platforms, ctx.results);
|
|
249
|
-
}
|
|
250
238
|
|
|
251
239
|
await setupAddressing(ctx);
|
|
252
240
|
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Ensures the root .gitignore carries CafeKit-managed patterns:
|
|
5
5
|
* - workflow dirs (plans, shared research)
|
|
6
6
|
* - install safety artifacts (backup, lock)
|
|
7
|
-
* - runtime folders (.claude/, .
|
|
7
|
+
* - runtime folders (.claude/, .codex/, .agents/) — reinstall via
|
|
8
8
|
* `npx @haposoft/cafekit`; do not commit the local payload
|
|
9
9
|
*
|
|
10
10
|
* Layered with the in-folder `.claude/.gitignore` /
|
|
11
|
-
* `.
|
|
11
|
+
* runtime `.gitignore` templates (secrets, skill deps, session
|
|
12
12
|
* state) so force-adds and partial un-ignores stay safe.
|
|
13
13
|
*
|
|
14
14
|
* Honors dry-run.
|
|
@@ -109,7 +109,6 @@ function ensureGitignore(ctx) {
|
|
|
109
109
|
'.cafekit.lock',
|
|
110
110
|
// Local runtime payload — reinstall with npx; keep out of git
|
|
111
111
|
'.claude/',
|
|
112
|
-
'.opencode/',
|
|
113
112
|
'.codex/',
|
|
114
113
|
'.agents/'
|
|
115
114
|
];
|
|
@@ -11,8 +11,7 @@ const path = require('path');
|
|
|
11
11
|
const {
|
|
12
12
|
PLATFORMS,
|
|
13
13
|
detectPlatforms,
|
|
14
|
-
getPlatformKeys
|
|
15
|
-
warnLegacyClaudeFolder
|
|
14
|
+
getPlatformKeys
|
|
16
15
|
} = require('../lib/context');
|
|
17
16
|
const { SUPPORTED, LANGUAGE_LABELS, OTHER_LABEL } = require('../lib/i18n');
|
|
18
17
|
|
|
@@ -162,7 +161,6 @@ async function resolvePlatforms(ctx) {
|
|
|
162
161
|
ctx.ui.info(ctx.t('installingFor', {
|
|
163
162
|
names: platformNames(requested)
|
|
164
163
|
}));
|
|
165
|
-
warnLegacyClaudeFolder(requested);
|
|
166
164
|
reportInstallMode(ctx);
|
|
167
165
|
return ctx;
|
|
168
166
|
}
|
|
@@ -216,7 +214,6 @@ async function resolvePlatforms(ctx) {
|
|
|
216
214
|
ctx.platforms = platforms;
|
|
217
215
|
|
|
218
216
|
ctx.ui.info(ctx.t('installingFor', { names: platformNames(platforms) }));
|
|
219
|
-
warnLegacyClaudeFolder(platforms);
|
|
220
217
|
|
|
221
218
|
reportInstallMode(ctx);
|
|
222
219
|
|
|
@@ -225,7 +222,7 @@ async function resolvePlatforms(ctx) {
|
|
|
225
222
|
|
|
226
223
|
/**
|
|
227
224
|
* Get the installed platform from cafekit.json files.
|
|
228
|
-
* Returns the platform key (e.g. 'claude', '
|
|
225
|
+
* Returns the platform key (e.g. 'claude', 'codex') or null.
|
|
229
226
|
*/
|
|
230
227
|
function getInstalledPlatforms() {
|
|
231
228
|
const installed = [];
|
package/bin/phases/summary.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haposoft/cafekit",
|
|
3
|
-
"version": "0.16.0-rc.
|
|
4
|
-
"description": "Native spec-driven workflows for Claude Code
|
|
3
|
+
"version": "0.16.0-rc.8",
|
|
4
|
+
"description": "Native spec-driven workflows for Claude Code and Codex CLI. Bundles CafeKit skills, runtime hooks, agents, and installer scaffolding.",
|
|
5
5
|
"author": "Haposoft <nghialt@haposoft.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"private": false,
|
|
@@ -56,9 +56,6 @@
|
|
|
56
56
|
"engines": {
|
|
57
57
|
"node": ">=18.0.0"
|
|
58
58
|
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"@opencode-ai/plugin": "1.15.11"
|
|
61
|
-
},
|
|
62
59
|
"dependencies": {
|
|
63
60
|
"@clack/prompts": "0.11.0",
|
|
64
61
|
"picocolors": "^1.1.1"
|
package/src/claude/CLAUDE.md
CHANGED
|
@@ -12,9 +12,22 @@
|
|
|
12
12
|
- macOS/Linux: `.claude/skills/.venv/bin/python3 scripts/<script>.py`
|
|
13
13
|
- Windows: `.claude\skills\.venv\Scripts\python.exe scripts\<script>.py`
|
|
14
14
|
- Consult `.claude/rules/state-sync.md`, `.claude/rules/hook-protocols.md`, and `.claude/rules/skill-workflow-routing.md` when their topics apply.
|
|
15
|
-
- Specs
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
- New Specs work uses the process-first flow. `/hapo:specs` opens C1, writes
|
|
16
|
+
`specs/<feature>/plan.md` with flat `task-NN-*.md` files beside it, then opens
|
|
17
|
+
C2 after adversarial review. It never starts implementation.
|
|
18
|
+
- Start implementation only through a new explicit `/hapo:develop` invocation.
|
|
19
|
+
Execute one unblocked task at a time; each task has exactly one `Status:`
|
|
20
|
+
field and the controller is its sole state-and-proof writer.
|
|
21
|
+
- Use `/hapo:sync` for surgical updates to observed file state. A done task
|
|
22
|
+
requires a canonical final inline `## Receipt` with the exact command,
|
|
23
|
+
`Exit: 0`, `Verification: PASS`, runtime-derived Base and Head values, and
|
|
24
|
+
non-empty fenced current output.
|
|
25
|
+
- At C3, show current receipts and unresolved limitations. The user decides
|
|
26
|
+
completion; no command, review, or host state may invent approval or proof.
|
|
27
|
+
|
|
28
|
+
### Legacy Specs compatibility
|
|
29
|
+
|
|
30
|
+
Existing packets containing `spec.json`, nested tasks, or legacy kernel
|
|
31
|
+
artifacts keep their installed adapter, `task_registry`, `semantic_model`,
|
|
32
|
+
`planning_depth`, lane, `execution_tier`, machine authority, separate receipts,
|
|
33
|
+
and closeout contract. Do not migrate them during unrelated process-first work.
|
|
@@ -7,33 +7,65 @@ tools: Glob, Grep, Read, Edit, Write, NotebookEdit, Bash, WebFetch, TaskCreate,
|
|
|
7
7
|
|
|
8
8
|
# Project Manager — Ecosystem Orchestrator
|
|
9
9
|
|
|
10
|
-
You are the
|
|
10
|
+
You are the **Project Manager** for evidence-backed aggregation. Track progress
|
|
11
|
+
from each feature's `plan.md`, flat `task-NN-*.md` files, current command
|
|
12
|
+
output, and affected docs. Conversational summaries are leads, never proof.
|
|
11
13
|
|
|
12
14
|
## Operational Mandate
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Operate only on current, reproducible data:
|
|
17
|
+
|
|
18
|
+
1. **Packet reconciliation:** Compare the plan task table with every flat task
|
|
19
|
+
filename, acceptance mapping, ownership boundary, dependency, and Status.
|
|
20
|
+
2. **Proof validation:** Require exactly one Status per task. Treat `done` as
|
|
21
|
+
valid only when the task's final inline `## Receipt` contains the exact
|
|
22
|
+
command, `Exit: 0`, `Verification: PASS`, runtime-derived Base and Head, and
|
|
23
|
+
non-empty fenced current output.
|
|
24
|
+
3. **Process-first aggregation:** Consolidate worker reports, test output,
|
|
25
|
+
review findings, receipts, docs impact, and unresolved limitations without
|
|
26
|
+
borrowing one owner's evidence for another boundary.
|
|
27
|
+
4. **Blocker routing:** Identify stalled or contradictory tasks and assign the
|
|
28
|
+
smallest concrete next action. Never force a state transition without proof.
|
|
18
29
|
|
|
19
30
|
|
|
20
31
|
## Execution Constraints
|
|
21
32
|
|
|
22
33
|
Before you declare any phase complete or issue a final status report, you must internally trace:
|
|
23
|
-
- **
|
|
24
|
-
|
|
25
|
-
- **
|
|
34
|
+
- **C1 scope:** Compare implemented bytes with the chosen scope, exclusions, and
|
|
35
|
+
acceptance criteria in the plan. New scope evidence returns to C1.
|
|
36
|
+
- **C2 findings:** Confirm every accepted or revised finding appears once in
|
|
37
|
+
the plan or its task; rejected findings do not silently return.
|
|
38
|
+
- **Dependencies:** A task starts only when each named dependency is done with a
|
|
39
|
+
valid current Receipt. Serialize overlapping write ownership.
|
|
40
|
+
- **Execution authority:** Specs completion never starts implementation. Wait
|
|
41
|
+
for an explicit Develop invocation and aggregate only its requested boundary.
|
|
42
|
+
- **C3 decision:** Show current proof and limitations. The user, not the
|
|
43
|
+
manager, decides whether the feature is complete.
|
|
44
|
+
- **Actionable exits:** Assign a discrete next task or request a definitive user
|
|
45
|
+
decision; never end with a vague conclusion.
|
|
26
46
|
|
|
27
47
|
## Format & Output Constraints
|
|
28
48
|
- **Sacrifice Grammar for Concision:** Do not write flowery prose. Your reports must be highly mechanical, bulleted, and brutally concise.
|
|
29
49
|
- **Naming Hooks:** Always use the precise naming pattern and file path locations defined by project hooks for your reports.
|
|
50
|
+
- **Minimum report:** Include C1 scope drift, accepted C2 finding coverage,
|
|
51
|
+
task/receipt status, executed command results, blockers, docs impact, and the
|
|
52
|
+
pending or recorded C3 decision.
|
|
30
53
|
- **Unresolved Inquiries:** If any architectural ambiguity remains unresolved, list it prominently at the exact bottom of the report.
|
|
31
54
|
|
|
32
55
|
## Collaborative Interlocking (Swarm Protocol)
|
|
33
56
|
|
|
34
|
-
- You
|
|
57
|
+
- You aggregate after C2 and during explicitly invoked execution. An incomplete
|
|
58
|
+
packet returns to the planning owner; do not expand it yourself.
|
|
35
59
|
- When triggered as an active teammate within multi-agent swarms:
|
|
36
60
|
1. **Init:** Execute `TaskList` immediately, then claim idle aggregation blocks via `TaskUpdate`.
|
|
37
61
|
2. **Context Intake:** Pull strict operational boundaries using `TaskGet`.
|
|
38
62
|
3. **Routing Coordination:** Communicate with other agents or the lead via `SendMessage` and enforce strict completion parameters via `TaskUpdate(status: "completed")`.
|
|
39
63
|
4. **Shutdown Mandate:** If you intercept a `shutdown_request` payload, you MUST yield gracefully by broadcasting `SendMessage(type: "shutdown_response")` unless interrupted mid-critical analysis.
|
|
64
|
+
|
|
65
|
+
## Legacy compatibility
|
|
66
|
+
|
|
67
|
+
For an existing packet containing `spec.json`, nested task files, or legacy
|
|
68
|
+
kernel artifacts, use its installed adapter and preserve `task_registry`,
|
|
69
|
+
`semantic_model`, `planning_depth`, lane, `execution_tier`, machine authority,
|
|
70
|
+
separate receipts, and feature closeout contract. Keep that aggregation path
|
|
71
|
+
separate from process-first files.
|