@dzhechkov/keysarium 1.7.15 → 1.7.19
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/.dz-manifest.json +214 -54
- package/README.md +29 -6
- package/README.ru.md +17 -0
- package/package.json +3 -3
- package/sbom.json +455 -55
- package/src/cli.js +32 -2
- package/src/commands/doctor.js +25 -1
- package/src/commands/init.js +56 -12
- package/src/commands/update.js +30 -3
- package/src/utils.js +7 -0
- package/templates/.agents/skills/casarium/SKILL.md +29 -0
- package/templates/.claude/agents/code-goal-planner.md +447 -0
- package/templates/.claude/commands/casarium.md +3 -1
- package/templates/.claude/commands/cjm-prototype.md +2 -2
- package/templates/.claude/commands/research.md +4 -1
- package/templates/.claude/rules/checkpoint-protocol.md +2 -1
- package/templates/.claude/rules/research-quality.md +11 -6
- package/templates/.claude/shards/phase-2-research.shard.md +12 -8
- package/templates/.claude/shards/phase-25-cjm.shard.md +5 -3
- package/templates/.claude/skills/feature-adr/SKILL.md +17 -15
- package/templates/.claude/skills/feature-adr/modules/03-adr.md +1 -1
- package/templates/.claude/skills/feature-adr/modules/03.5-ideation-swarm.md +1 -1
- package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +2 -2
- package/templates/.claude/skills/feature-adr/modules/08-qe.md +1 -1
- package/templates/.claude/skills/feature-adr/modules/09-fleet-qe.md +12 -12
- package/templates/.claude/skills/feature-adr/references/agentic-qe/LICENSE.agentic-qe +21 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/README.md +20 -16
- package/templates/.claude/skills/feature-adr/references/agentic-qe/UPSTREAM-MANIFEST.json +246 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-brutal-honesty-review/README.md +218 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/{brutal-honesty-review.md → qe-ref-brutal-honesty-review/REFERENCE.md} +14 -1
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-brutal-honesty-review/resources/assessment-rubrics.md +295 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-brutal-honesty-review/resources/review-template.md +102 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-brutal-honesty-review/schemas/output.json +291 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-brutal-honesty-review/scripts/assess-code.sh +179 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-brutal-honesty-review/scripts/assess-tests.sh +223 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-brutal-honesty-review/scripts/validate-config.json +34 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-enterprise-integration-testing/REFERENCE.md +758 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-enterprise-integration-testing/evals/enterprise-integration-testing.yaml +158 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-enterprise-integration-testing/schemas/output.json +74 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-enterprise-integration-testing/scripts/validate-config.json +25 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/REFERENCE.md +226 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/evals/qcsd-ideation-swarm.yaml +138 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/schemas/output.json +568 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/scripts/validate-config.json +25 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/01-flag-detection.md +57 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/02-core-agents.md +29 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/03-batch1-results.md +15 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/04-conditional-agents.md +23 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/05-decision-synthesis.md +29 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/06-report-generation.md +18 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/07-learning-persistence.md +29 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qcsd-ideation-swarm/steps/08-final-output.md +18 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/{qe-coverage-analysis.md → qe-ref-qe-coverage-analysis/REFERENCE.md} +42 -3
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qe-coverage-analysis/evals/qe-coverage-analysis.yaml +494 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qe-coverage-analysis/schemas/output.json +286 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qe-coverage-analysis/scripts/validate-config.json +42 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/{qe-requirements-validation.md → qe-ref-qe-requirements-validation/REFERENCE.md} +13 -3
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qe-requirements-validation/evals/qe-requirements-validation.yaml +598 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qe-requirements-validation/schemas/output.json +587 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-qe-requirements-validation/scripts/validate-config.json +37 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/{regression-testing.md → qe-ref-regression-testing/REFERENCE.md} +30 -49
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-regression-testing/evals/regression-testing.yaml +504 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-regression-testing/schemas/output.json +311 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-regression-testing/scripts/validate-config.json +50 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/{risk-based-testing.md → qe-ref-risk-based-testing/REFERENCE.md} +23 -52
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-risk-based-testing/evals/risk-based-testing.yaml +141 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-risk-based-testing/schemas/output.json +480 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-risk-based-testing/scripts/validate-config.json +25 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/{shift-left-testing.md → qe-ref-shift-left-testing/REFERENCE.md} +33 -88
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-shift-left-testing/evals/shift-left-testing.yaml +145 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-shift-left-testing/schemas/output.json +459 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-ref-shift-left-testing/scripts/validate-config.json +25 -0
- package/templates/CLAUDE.md +3 -1
- package/templates/docs/feature-adr/04-admin-guide.md +1 -1
- package/templates/docs/improvement-directions.md +3 -3
- package/templates/docs/keysarium/02-admin-guide.md +2 -2
- package/templates/docs/keysarium/03-user-guide.md +3 -3
- package/templates/docs/keysarium/05-architecture.md +9 -8
- package/templates/docs/keysarium/06-user-flows.md +4 -4
- package/templates/lib/platform-templates/copilot.md +1 -1
- package/templates/lib/platform-templates/opencode.md +1 -1
- package/templates/.claude/skills/feature-adr/references/agentic-qe/enterprise-integration-testing.md +0 -111
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-ideation-swarm.md +0 -126
package/src/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ function showBanner() {
|
|
|
10
10
|
console.log('');
|
|
11
11
|
console.log(cyan('╔══════════════════════════════════════════════════════╗'));
|
|
12
12
|
console.log(cyan('║') + bold(' \uD83D\uDD2C DZ-KEYSARIUM — AI Research Toolkit ') + cyan('║'));
|
|
13
|
-
console.log(cyan('║') + '
|
|
13
|
+
console.log(cyan('║') + ' Full 7-phase research pipeline ' + cyan('║'));
|
|
14
14
|
console.log(cyan('╚══════════════════════════════════════════════════════╝'));
|
|
15
15
|
console.log('');
|
|
16
16
|
}
|
|
@@ -40,6 +40,8 @@ function showHelp() {
|
|
|
40
40
|
console.log(' ' + yellow('--minimal') + ' Install only .claude/ directory (skills, commands, rules)');
|
|
41
41
|
console.log(' ' + yellow('--force') + ' Overwrite existing files without prompting');
|
|
42
42
|
console.log(' ' + yellow('--with-docs') + ' Include docs/ directory');
|
|
43
|
+
console.log(' ' + yellow('--target') + ' Install for claude (default) or codex');
|
|
44
|
+
console.log(' ' + yellow('--project') + ' Project directory (default: current directory)');
|
|
43
45
|
console.log(' ' + yellow('--dry-run') + ' Show what would be done without making changes');
|
|
44
46
|
console.log(' ' + yellow('--help, -h') + ' Show this help message');
|
|
45
47
|
console.log(' ' + yellow('--version, -v') + ' Show version number');
|
|
@@ -47,6 +49,7 @@ function showHelp() {
|
|
|
47
49
|
console.log(bold('Examples:'));
|
|
48
50
|
console.log(dim(' $ ') + 'npx @dzhechkov/keysarium init');
|
|
49
51
|
console.log(dim(' $ ') + 'npx @dzhechkov/keysarium init --minimal --force');
|
|
52
|
+
console.log(dim(' $ ') + 'npx @dzhechkov/keysarium init --target codex --project ./my-case');
|
|
50
53
|
console.log(dim(' $ ') + 'npx @dzhechkov/keysarium update --dry-run');
|
|
51
54
|
console.log(dim(' $ ') + 'npx @dzhechkov/keysarium doctor');
|
|
52
55
|
console.log('');
|
|
@@ -64,11 +67,14 @@ function parseArgs(argv) {
|
|
|
64
67
|
withDocs: false,
|
|
65
68
|
dryRun: false,
|
|
66
69
|
targetDir: process.cwd(),
|
|
70
|
+
target: 'claude',
|
|
71
|
+
targetSpecified: false,
|
|
67
72
|
};
|
|
68
73
|
|
|
69
74
|
let command = null;
|
|
70
75
|
|
|
71
|
-
for (
|
|
76
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
77
|
+
const arg = args[index];
|
|
72
78
|
switch (arg) {
|
|
73
79
|
case '--minimal':
|
|
74
80
|
flags.minimal = true;
|
|
@@ -82,6 +88,25 @@ function parseArgs(argv) {
|
|
|
82
88
|
case '--dry-run':
|
|
83
89
|
flags.dryRun = true;
|
|
84
90
|
break;
|
|
91
|
+
case '--target': {
|
|
92
|
+
const value = args[++index];
|
|
93
|
+
if (value !== 'claude' && value !== 'codex') {
|
|
94
|
+
error('--target must be claude or codex');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
flags.target = value;
|
|
98
|
+
flags.targetSpecified = true;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case '--project': {
|
|
102
|
+
const value = args[++index];
|
|
103
|
+
if (!value || value.startsWith('-')) {
|
|
104
|
+
error('--project requires a directory path');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
flags.targetDir = path.resolve(value);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
85
110
|
case '--help':
|
|
86
111
|
case '-h':
|
|
87
112
|
command = 'help';
|
|
@@ -132,6 +157,11 @@ function main() {
|
|
|
132
157
|
|
|
133
158
|
// Route to command handlers
|
|
134
159
|
const resolvedCommand = command || 'init';
|
|
160
|
+
if (flags.targetSpecified && resolvedCommand !== 'init') {
|
|
161
|
+
error('--target is supported only by init; update and doctor use the installation manifest');
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
135
165
|
|
|
136
166
|
switch (resolvedCommand) {
|
|
137
167
|
case 'init':
|
package/src/commands/doctor.js
CHANGED
|
@@ -293,6 +293,28 @@ function checkSettingsValid(targetDir) {
|
|
|
293
293
|
});
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
+
function checkCodexEntrypoint(targetDir) {
|
|
297
|
+
return check('Codex entrypoint', () => {
|
|
298
|
+
const entry = path.join(targetDir, '.agents', 'skills', 'casarium', 'SKILL.md');
|
|
299
|
+
const command = path.join(targetDir, '.claude', 'commands', 'casarium.md');
|
|
300
|
+
const shards = path.join(targetDir, '.claude', 'shards');
|
|
301
|
+
const missing = [entry, command, shards].filter((item) => !fileExists(item));
|
|
302
|
+
if (missing.length > 0) {
|
|
303
|
+
return { passed: false, detail: `Missing ${missing.map((item) => path.relative(targetDir, item)).join(', ')}`,
|
|
304
|
+
fix: 'Run keysarium update to restore the installed Codex entrypoint.' };
|
|
305
|
+
}
|
|
306
|
+
const body = fs.readFileSync(entry, 'utf8');
|
|
307
|
+
const frontmatter = body.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
308
|
+
if (!frontmatter || !/^name:\s*casarium\s*$/m.test(frontmatter[1])
|
|
309
|
+
|| !/^description:\s*\S.+$/m.test(frontmatter[1])
|
|
310
|
+
|| !body.includes('.claude/commands/casarium.md')) {
|
|
311
|
+
return { passed: false, detail: 'SKILL.md lacks Codex discovery metadata or the canonical command reference',
|
|
312
|
+
fix: 'Run keysarium update to restore the Codex entrypoint.' };
|
|
313
|
+
}
|
|
314
|
+
return { passed: true, detail: 'Project skill and canonical pipeline references present' };
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
296
318
|
/**
|
|
297
319
|
* Check 8: researches/ directory exists.
|
|
298
320
|
*/
|
|
@@ -372,7 +394,9 @@ async function run(options) {
|
|
|
372
394
|
checkRulesPresent(targetDir),
|
|
373
395
|
checkShardsPresent(targetDir),
|
|
374
396
|
checkAgentsPresent(targetDir),
|
|
375
|
-
|
|
397
|
+
manifest.components?.includes('codex_entry')
|
|
398
|
+
? checkCodexEntrypoint(targetDir)
|
|
399
|
+
: checkSettingsValid(targetDir),
|
|
376
400
|
checkResearchDir(targetDir),
|
|
377
401
|
];
|
|
378
402
|
|
package/src/commands/init.js
CHANGED
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
copyDirRecursive, copyDirTracked, fileExists, readJSON,
|
|
9
9
|
ensureDir, getRelativePaths,
|
|
10
10
|
createManifest, writeManifest, getTemplatesDir,
|
|
11
|
+
hashFile,
|
|
11
12
|
COMPONENTS, MANIFEST_FILE,
|
|
12
13
|
} = require('../utils');
|
|
13
14
|
|
|
@@ -22,8 +23,10 @@ const {
|
|
|
22
23
|
* --with-docs: add docs group
|
|
23
24
|
*/
|
|
24
25
|
function resolveComponents(options) {
|
|
25
|
-
const { minimal, withDocs } = options;
|
|
26
|
-
const coreKeys = ['skills', 'commands', 'rules', 'shards', 'agents', '
|
|
26
|
+
const { minimal, withDocs, target } = options;
|
|
27
|
+
const coreKeys = ['skills', 'commands', 'rules', 'shards', 'agents', 'claude_md', 'harvest'];
|
|
28
|
+
if (target === 'codex') coreKeys.push('codex_entry');
|
|
29
|
+
else coreKeys.push('hooks');
|
|
27
30
|
const keys = [...coreKeys];
|
|
28
31
|
|
|
29
32
|
if (!minimal) {
|
|
@@ -81,9 +84,10 @@ function installComponent(comp, templatesDir, targetDir, force) {
|
|
|
81
84
|
* @param {boolean} options.withDocs — Include docs/ directory
|
|
82
85
|
* @param {boolean} options.dryRun — Preview without writing anything
|
|
83
86
|
* @param {string} options.targetDir — Destination project root
|
|
87
|
+
* @param {string} options.target — claude (default) or codex
|
|
84
88
|
*/
|
|
85
89
|
async function run(options) {
|
|
86
|
-
const { force, dryRun, targetDir } = options;
|
|
90
|
+
const { force, dryRun, targetDir, target = 'claude' } = options;
|
|
87
91
|
const manifestPath = path.join(targetDir, MANIFEST_FILE);
|
|
88
92
|
|
|
89
93
|
// ── a) Check for existing installation ──────────────────────────────────
|
|
@@ -93,9 +97,25 @@ async function run(options) {
|
|
|
93
97
|
info(`Run ${cyan('npx @dzhechkov/keysarium update')} to update, or use ${yellow('--force')} to overwrite.`);
|
|
94
98
|
process.exit(1);
|
|
95
99
|
}
|
|
100
|
+
const existing = readJSON(manifestPath);
|
|
101
|
+
if (!existing || !Array.isArray(existing.components)) {
|
|
102
|
+
logError('Existing .keysarium.json is invalid; refusing to overwrite its ownership record.');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const existingTarget = existing.components.includes('codex_entry') ? 'codex' : 'claude';
|
|
106
|
+
if (existingTarget !== target) {
|
|
107
|
+
logError(`Cannot switch an installed ${existingTarget} toolkit to ${target} with --force. Remove it first, then init for the new target.`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
96
110
|
warn('Existing installation found — overwriting (--force).');
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
const codexEntryPath = path.join(targetDir, '.agents', 'skills', 'casarium', 'SKILL.md');
|
|
114
|
+
if (target === 'codex' && fileExists(codexEntryPath) && !force) {
|
|
115
|
+
logError('A project skill named casarium already exists. Use --force only if it may be replaced.');
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
99
119
|
// ── b) Determine components ─────────────────────────────────────────────
|
|
100
120
|
const componentKeys = resolveComponents(options);
|
|
101
121
|
const templatesDir = getTemplatesDir();
|
|
@@ -103,6 +123,7 @@ async function run(options) {
|
|
|
103
123
|
// ── c) Show plan ────────────────────────────────────────────────────────
|
|
104
124
|
console.log('');
|
|
105
125
|
info(bold('Installation plan:'));
|
|
126
|
+
info(`Target: ${target}; project: ${targetDir}`);
|
|
106
127
|
console.log('');
|
|
107
128
|
|
|
108
129
|
for (const key of componentKeys) {
|
|
@@ -145,6 +166,15 @@ async function run(options) {
|
|
|
145
166
|
const version = pkg ? pkg.version : '0.0.0';
|
|
146
167
|
|
|
147
168
|
const manifest = createManifest(version, componentKeys, installedFiles.sort());
|
|
169
|
+
// Only claim a baseline for the planner when the installed bytes equal the template.
|
|
170
|
+
// A pre-existing user file preserved by init must not be adopted as our version.
|
|
171
|
+
const plannerRel = path.join('.claude', 'agents', 'code-goal-planner.md');
|
|
172
|
+
const installedPlanner = path.join(targetDir, plannerRel);
|
|
173
|
+
const templatePlanner = path.join(templatesDir, plannerRel);
|
|
174
|
+
if (fileExists(installedPlanner) && fileExists(templatePlanner)
|
|
175
|
+
&& hashFile(installedPlanner) === hashFile(templatePlanner)) {
|
|
176
|
+
manifest.templateHashes = { [plannerRel]: hashFile(templatePlanner) };
|
|
177
|
+
}
|
|
148
178
|
writeManifest(targetDir, manifest);
|
|
149
179
|
info('Created .keysarium.json manifest');
|
|
150
180
|
|
|
@@ -161,16 +191,30 @@ async function run(options) {
|
|
|
161
191
|
|
|
162
192
|
console.log('');
|
|
163
193
|
console.log(bold('Next steps:'));
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
194
|
+
if (target === 'codex') {
|
|
195
|
+
console.log(` 1. Open ${cyan('Codex')} in ${targetDir}`);
|
|
196
|
+
console.log(` 2. Invoke ${cyan('$casarium [your case description]')}`);
|
|
197
|
+
console.log(` 3. Confirm each phase checkpoint and select a CJM variant`);
|
|
198
|
+
console.log('');
|
|
199
|
+
console.log(bold('Codex integration status:'));
|
|
200
|
+
console.log(' Bundled workflow skills: installed under .claude/skills/ as phase references');
|
|
201
|
+
console.log(' Full pipeline entrypoint: installed at .agents/skills/casarium/SKILL.md');
|
|
202
|
+
console.log(' Codex hooks and MCP integrations: not installed');
|
|
203
|
+
console.log(' Claude settings/hooks: not installed for this target');
|
|
204
|
+
} else {
|
|
205
|
+
console.log(` 1. Open ${cyan('Claude Code')} in this directory`);
|
|
206
|
+
console.log(` 2. Run ${cyan('/casarium [your case description]')}`);
|
|
207
|
+
console.log(` 3. Follow the 7-phase pipeline`);
|
|
208
|
+
}
|
|
173
209
|
console.log('');
|
|
210
|
+
if (target === 'claude') {
|
|
211
|
+
console.log(bold('Available commands:'));
|
|
212
|
+
console.log(` ${cyan('/casarium')} ${dim('\u2014 Full pipeline')}`);
|
|
213
|
+
console.log(` ${cyan('/new-research')} ${dim('\u2014 New research')}`);
|
|
214
|
+
console.log(` ${cyan('/parallel-research')} ${dim('\u2014 Multiple cases in parallel')}`);
|
|
215
|
+
console.log(` ${cyan('/harvest')} ${dim('\u2014 Extract knowledge')}`);
|
|
216
|
+
console.log('');
|
|
217
|
+
}
|
|
174
218
|
|
|
175
219
|
process.exit(0);
|
|
176
220
|
}
|
package/src/commands/update.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
info, success, warn, error: logError, step,
|
|
8
8
|
copyDirRecursive, fileExists, readJSON,
|
|
9
9
|
ensureDir, getRelativePaths, diffFiles,
|
|
10
|
+
hashFile,
|
|
10
11
|
readManifest, writeManifest, getTemplatesDir,
|
|
11
12
|
COMPONENTS, MANIFEST_FILE,
|
|
12
13
|
} = require('../utils');
|
|
@@ -20,11 +21,11 @@ const {
|
|
|
20
21
|
*
|
|
21
22
|
* @param {object} options
|
|
22
23
|
* @param {boolean} options.dryRun — Preview without writing anything
|
|
23
|
-
* @param {boolean} options.force —
|
|
24
|
+
* @param {boolean} options.force — Back up and replace a locally edited planner agent
|
|
24
25
|
* @param {string} options.targetDir — Destination project root
|
|
25
26
|
*/
|
|
26
27
|
async function run(options) {
|
|
27
|
-
const { dryRun, targetDir } = options;
|
|
28
|
+
const { dryRun, force, targetDir } = options;
|
|
28
29
|
const manifestPath = path.join(targetDir, MANIFEST_FILE);
|
|
29
30
|
|
|
30
31
|
// ── a) Read existing manifest ───────────────────────────────────────────
|
|
@@ -60,7 +61,11 @@ async function run(options) {
|
|
|
60
61
|
let totalAdded = 0;
|
|
61
62
|
let totalModified = 0;
|
|
62
63
|
let totalUnchanged = 0;
|
|
64
|
+
let preservedPlanner = false;
|
|
63
65
|
const filesToCopy = []; // { src, dest, status, relPath }
|
|
66
|
+
const plannerRel = path.join('.claude', 'agents', 'code-goal-planner.md');
|
|
67
|
+
// The unmodified wrapper shipped before the full agent was introduced.
|
|
68
|
+
const legacyPlannerHash = 'fd6faca31bacfa3c70c0ff2a8ba152957d952b8590b4df0934ffd19af5078592';
|
|
64
69
|
|
|
65
70
|
for (const key of installedKeys) {
|
|
66
71
|
const comp = COMPONENTS[key];
|
|
@@ -107,11 +112,24 @@ async function run(options) {
|
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
for (const rel of diff.modified) {
|
|
115
|
+
const relPath = path.join(comp.src, rel);
|
|
116
|
+
let backup = false;
|
|
117
|
+
if (relPath === plannerRel) {
|
|
118
|
+
const currentHash = hashFile(path.join(destBase, rel));
|
|
119
|
+
const baseline = manifest.templateHashes?.[plannerRel];
|
|
120
|
+
const clean = currentHash === baseline || (!baseline && currentHash === legacyPlannerHash);
|
|
121
|
+
if (!clean && !force) {
|
|
122
|
+
preservedPlanner = true;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
backup = !clean;
|
|
126
|
+
}
|
|
110
127
|
filesToCopy.push({
|
|
111
128
|
src: path.join(srcBase, rel),
|
|
112
129
|
dest: path.join(destBase, rel),
|
|
113
130
|
status: 'modified',
|
|
114
|
-
relPath
|
|
131
|
+
relPath,
|
|
132
|
+
backup,
|
|
115
133
|
});
|
|
116
134
|
totalModified++;
|
|
117
135
|
}
|
|
@@ -125,6 +143,7 @@ async function run(options) {
|
|
|
125
143
|
console.log(` ${green('+')} ${totalAdded} file(s) to add`);
|
|
126
144
|
console.log(` ${yellow('~')} ${totalModified} file(s) to update`);
|
|
127
145
|
console.log(` ${dim('=')} ${totalUnchanged} file(s) unchanged`);
|
|
146
|
+
if (preservedPlanner) warn(`Local edit preserved: ${plannerRel}. Use --force to back up and replace it.`);
|
|
128
147
|
console.log('');
|
|
129
148
|
|
|
130
149
|
if (totalAdded === 0 && totalModified === 0) {
|
|
@@ -137,6 +156,7 @@ async function run(options) {
|
|
|
137
156
|
for (const f of filesToCopy) {
|
|
138
157
|
const marker = f.status === 'added' ? green('+ ADD') : yellow('~ MOD');
|
|
139
158
|
console.log(` ${marker} ${f.relPath}`);
|
|
159
|
+
if (f.backup) console.log(` backup: ${f.relPath}.bak`);
|
|
140
160
|
}
|
|
141
161
|
console.log('');
|
|
142
162
|
warn('Dry run — no files were written.');
|
|
@@ -150,6 +170,7 @@ async function run(options) {
|
|
|
150
170
|
step(i + 1, filesToCopy.length, `${label} ${f.relPath}`);
|
|
151
171
|
|
|
152
172
|
ensureDir(path.dirname(f.dest));
|
|
173
|
+
if (f.backup) fs.copyFileSync(f.dest, `${f.dest}.bak`);
|
|
153
174
|
fs.copyFileSync(f.src, f.dest);
|
|
154
175
|
}
|
|
155
176
|
|
|
@@ -176,6 +197,12 @@ async function run(options) {
|
|
|
176
197
|
manifest.version = newVersion;
|
|
177
198
|
manifest.updatedAt = new Date().toISOString();
|
|
178
199
|
manifest.files = allFiles.sort();
|
|
200
|
+
const installedPlanner = path.join(targetDir, plannerRel);
|
|
201
|
+
const templatePlanner = path.join(templatesDir, plannerRel);
|
|
202
|
+
if (fileExists(installedPlanner) && fileExists(templatePlanner)
|
|
203
|
+
&& hashFile(installedPlanner) === hashFile(templatePlanner)) {
|
|
204
|
+
manifest.templateHashes = { ...manifest.templateHashes, [plannerRel]: hashFile(templatePlanner) };
|
|
205
|
+
}
|
|
179
206
|
|
|
180
207
|
writeManifest(targetDir, manifest);
|
|
181
208
|
info('Updated .keysarium.json manifest');
|
package/src/utils.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const { createHash } = require('node:crypto');
|
|
5
6
|
|
|
6
7
|
// ===========================================================================
|
|
7
8
|
// Colors — ANSI escape codes (zero dependencies)
|
|
@@ -36,6 +37,10 @@ function step(n, total, msg) {
|
|
|
36
37
|
console.log(cyan(`[${n}/${total}]`) + ' ' + msg);
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
function hashFile(file) {
|
|
41
|
+
return createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
// ===========================================================================
|
|
40
45
|
// File operations — all synchronous, Node.js built-ins only
|
|
41
46
|
// ===========================================================================
|
|
@@ -311,6 +316,7 @@ const COMPONENT_SPECS = {
|
|
|
311
316
|
docs: { src: 'docs', name: 'Documentation', unit: 'guides', countMode: 'files', group: 'docs' },
|
|
312
317
|
claude_md: { src: 'CLAUDE.md', name: 'Master instructions', group: 'core', isFile: true },
|
|
313
318
|
harvest: { src: 'TOOLKIT_HARVEST.md', name: 'Knowledge harvest tracker', group: 'core', isFile: true },
|
|
319
|
+
codex_entry: { src: '.agents/skills/casarium', name: 'Codex pipeline entrypoint', unit: 'entrypoint', countMode: 'files', group: 'codex' },
|
|
314
320
|
};
|
|
315
321
|
|
|
316
322
|
/**
|
|
@@ -370,6 +376,7 @@ module.exports = {
|
|
|
370
376
|
warn,
|
|
371
377
|
error,
|
|
372
378
|
step,
|
|
379
|
+
hashFile,
|
|
373
380
|
|
|
374
381
|
// File operations
|
|
375
382
|
copyDirRecursive,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: casarium
|
|
3
|
+
description: Run the installed Keysarium seven-phase case research pipeline in Codex, with phase artifacts and user checkpoints. Use when the user invokes $casarium or asks to work through a Keysarium case.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Casarium in Codex
|
|
7
|
+
|
|
8
|
+
This project contains the complete Keysarium workflow. Start by reading
|
|
9
|
+
`.claude/commands/casarium.md`; it is the source of truth for phase order, outputs and
|
|
10
|
+
checkpoints. Treat its `$ARGUMENTS` as the user's request after `$casarium`. If the case is
|
|
11
|
+
missing, ask for it.
|
|
12
|
+
|
|
13
|
+
For each phase, read only its `.claude/shards/phase-*.shard.md` and the skill files it names
|
|
14
|
+
under `.claude/skills/`. Read `.claude/rules/checkpoint-protocol.md` and
|
|
15
|
+
`.claude/rules/research-quality.md` when reaching their gates. Create phase artifacts under
|
|
16
|
+
`researches/<case-name>/` as the phase runs. Show the checkpoint and wait for the user's
|
|
17
|
+
confirmation before advancing. Phase 2.5 requires an explicit CJM choice; preserve that
|
|
18
|
+
choice in later phases. A failed research gate cannot emit a success promise.
|
|
19
|
+
|
|
20
|
+
The `.claude/` files are workflow references in Codex. Claude slash commands, Agent tool
|
|
21
|
+
calls, hook settings and model names inside them are not Codex commands or installed Codex
|
|
22
|
+
integrations. Use available Codex tools for the work and state any unavailable capability;
|
|
23
|
+
do not claim that a named Claude agent or hook ran. Parallel work is optional when the host
|
|
24
|
+
supports it. The research mode requirements still apply to every worker.
|
|
25
|
+
|
|
26
|
+
If the case asks for AI Factory mapping, read
|
|
27
|
+
`.claude/shards/phase-ai-factory.shard.md` and its referenced skill before Phase 0. Otherwise
|
|
28
|
+
leave that branch inactive. The project-local `$casarium` skill is the Codex entrypoint;
|
|
29
|
+
`/casarium` remains the Claude Code entrypoint.
|