@kaddo/cli 3.27.1 → 3.27.3
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 +2 -0
- package/dist/index.js +173 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -519,6 +519,8 @@ create --from roadmap → owners → guard → explain`.
|
|
|
519
519
|
| v3.26 | Open-questions readiness gate: `kaddo questions`/`readiness`, blocking/important/deferred classification; MCP open-questions + roadmap-readiness resources + tool; roadmap/work-item/implementation/bootstrap agents check it |
|
|
520
520
|
| v3.27 | Codex adapter: `kaddo adapters install codex` (alias `kaddo export codex`) generates a compact `AGENTS.md` projection (`--dry-run`/`--force`) |
|
|
521
521
|
| v3.27.1 | Codex adapter command fallbacks: AGENTS.md tells Codex to try `corepack pnpm exec` / `pnpm exec` / `npx` kaddo when the global binary isn't on PATH |
|
|
522
|
+
| v3.27.2 | Codex adapter safe merge: `kaddo adapters install codex --inject` adds/updates only a delimited Kaddo block in an existing AGENTS.md, preserving team content |
|
|
523
|
+
| v3.27.3 | Codex adapter reference stabilization: package-manager-aware command fallbacks (lockfile detection) + Adapter Contract & Custom Adapters docs (reference for future adapters) |
|
|
522
524
|
|
|
523
525
|
**Optional modules (installed with `kaddo add`):**
|
|
524
526
|
|
package/dist/index.js
CHANGED
|
@@ -12337,6 +12337,7 @@ function buildCodexAdapterContext(dir) {
|
|
|
12337
12337
|
projectName: config?.project.name,
|
|
12338
12338
|
projectType: config?.project.state,
|
|
12339
12339
|
language: config ? config.project.language : void 0,
|
|
12340
|
+
packageManager: detectPackageManager2(dir),
|
|
12340
12341
|
hasAgents: agents.length > 0,
|
|
12341
12342
|
agents,
|
|
12342
12343
|
hasSkills: skills.length > 0,
|
|
@@ -12346,6 +12347,48 @@ function buildCodexAdapterContext(dir) {
|
|
|
12346
12347
|
generatedPaths: GENERATED_PATHS
|
|
12347
12348
|
};
|
|
12348
12349
|
}
|
|
12350
|
+
function detectPackageManager2(dir) {
|
|
12351
|
+
if (exists(join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
12352
|
+
if (exists(join(dir, "yarn.lock"))) return "yarn";
|
|
12353
|
+
if (exists(join(dir, "bun.lockb")) || exists(join(dir, "bun.lock"))) return "bun";
|
|
12354
|
+
if (exists(join(dir, "package-lock.json"))) return "npm";
|
|
12355
|
+
return void 0;
|
|
12356
|
+
}
|
|
12357
|
+
function commandFallbacks(pm) {
|
|
12358
|
+
switch (pm) {
|
|
12359
|
+
case "pnpm":
|
|
12360
|
+
return ["corepack pnpm exec kaddo <command>", "pnpm exec kaddo <command>", "npx kaddo <command>"];
|
|
12361
|
+
case "yarn":
|
|
12362
|
+
return ["yarn kaddo <command>", "yarn dlx kaddo <command>", "npx kaddo <command>"];
|
|
12363
|
+
case "bun":
|
|
12364
|
+
return ["bunx kaddo <command>", "npx kaddo <command>"];
|
|
12365
|
+
case "npm":
|
|
12366
|
+
return ["npm exec kaddo <command>", "npx kaddo <command>"];
|
|
12367
|
+
default:
|
|
12368
|
+
return ["corepack pnpm exec kaddo <command>", "pnpm exec kaddo <command>", "npm exec kaddo <command>", "npx kaddo <command>"];
|
|
12369
|
+
}
|
|
12370
|
+
}
|
|
12371
|
+
function commandFallbackSection(pm, heading) {
|
|
12372
|
+
const L = [];
|
|
12373
|
+
const pmNote = pm ? ` (detected package manager: \`${pm}\`)` : " (no package manager detected \u2014 generic options)";
|
|
12374
|
+
L.push(`${heading}Command fallback`, "");
|
|
12375
|
+
L.push(`Prefer the global \`kaddo\` command when available:`, "");
|
|
12376
|
+
L.push("```bash");
|
|
12377
|
+
L.push("kaddo <command>");
|
|
12378
|
+
L.push("```");
|
|
12379
|
+
L.push("");
|
|
12380
|
+
L.push(`If \`kaddo\` is not available in \`PATH\`, try the local project runner${pmNote} before`);
|
|
12381
|
+
L.push("reporting that Kaddo is unavailable:", "");
|
|
12382
|
+
L.push("```bash");
|
|
12383
|
+
for (const f of commandFallbacks(pm)) L.push(f);
|
|
12384
|
+
L.push("```");
|
|
12385
|
+
L.push("");
|
|
12386
|
+
L.push("Do not fail immediately just because the global `kaddo` binary is missing. When you use a");
|
|
12387
|
+
L.push('fallback, mention it briefly (e.g. "the global `kaddo` was not available, so I used the local');
|
|
12388
|
+
L.push('runner").');
|
|
12389
|
+
L.push("");
|
|
12390
|
+
return L;
|
|
12391
|
+
}
|
|
12349
12392
|
function detectMcpHint(dir) {
|
|
12350
12393
|
for (const f of [".mcp.json", "mcp.json", ".cursor/mcp.json"]) {
|
|
12351
12394
|
if (exists(join(dir, f))) return true;
|
|
@@ -12441,32 +12484,7 @@ function renderAgentsMd(ctx) {
|
|
|
12441
12484
|
}
|
|
12442
12485
|
L.push("");
|
|
12443
12486
|
}
|
|
12444
|
-
|
|
12445
|
-
L.push("Prefer the direct command when available:", "");
|
|
12446
|
-
L.push("```bash");
|
|
12447
|
-
L.push("kaddo <command>");
|
|
12448
|
-
L.push("```");
|
|
12449
|
-
L.push("");
|
|
12450
|
-
L.push("If the global `kaddo` command is not available in `PATH`, try the local project runner");
|
|
12451
|
-
L.push("before reporting that Kaddo is unavailable:", "");
|
|
12452
|
-
L.push("```bash");
|
|
12453
|
-
L.push("corepack pnpm exec kaddo <command>");
|
|
12454
|
-
L.push("```");
|
|
12455
|
-
L.push("");
|
|
12456
|
-
L.push("If that is not available, try:", "");
|
|
12457
|
-
L.push("```bash");
|
|
12458
|
-
L.push("pnpm exec kaddo <command>");
|
|
12459
|
-
L.push("```");
|
|
12460
|
-
L.push("");
|
|
12461
|
-
L.push("As a last resort (may resolve/download the package):", "");
|
|
12462
|
-
L.push("```bash");
|
|
12463
|
-
L.push("npx kaddo <command>");
|
|
12464
|
-
L.push("```");
|
|
12465
|
-
L.push("");
|
|
12466
|
-
L.push("Do not assume Kaddo is unavailable until these local fallbacks have been attempted. When you");
|
|
12467
|
-
L.push('use a fallback, mention it briefly (e.g. "the global `kaddo` was not available, so I used');
|
|
12468
|
-
L.push('`corepack pnpm exec kaddo`").');
|
|
12469
|
-
L.push("");
|
|
12487
|
+
for (const line of commandFallbackSection(ctx.packageManager, "## ")) L.push(line);
|
|
12470
12488
|
L.push("## Useful Kaddo commands", "");
|
|
12471
12489
|
L.push("```bash");
|
|
12472
12490
|
for (const c of ["kaddo context", "kaddo understand", "kaddo explain", "kaddo graph export", "kaddo questions", "kaddo guard", "kaddo impact", "kaddo savings", "kaddo drift"]) {
|
|
@@ -12493,6 +12511,85 @@ function renderAgentsMd(ctx) {
|
|
|
12493
12511
|
L.push("");
|
|
12494
12512
|
return L.join("\n");
|
|
12495
12513
|
}
|
|
12514
|
+
var KADDO_BEGIN_MARKER = "<!-- BEGIN KADDO CODEX ADAPTER -->";
|
|
12515
|
+
var KADDO_END_MARKER = "<!-- END KADDO CODEX ADAPTER -->";
|
|
12516
|
+
var GENERATED_HEADER = "Generated by `kaddo adapters install codex`";
|
|
12517
|
+
function detectAgentsState(content) {
|
|
12518
|
+
if (content === null) return "missing";
|
|
12519
|
+
const hasBegin = content.includes(KADDO_BEGIN_MARKER);
|
|
12520
|
+
const hasEnd = content.includes(KADDO_END_MARKER);
|
|
12521
|
+
if (hasBegin !== hasEnd) return "invalid_kaddo_block";
|
|
12522
|
+
if (hasBegin && hasEnd) return "existing_with_kaddo_block";
|
|
12523
|
+
if (content.includes(GENERATED_HEADER)) return "generated_by_kaddo";
|
|
12524
|
+
return "existing_external";
|
|
12525
|
+
}
|
|
12526
|
+
function renderKaddoBlock(ctx) {
|
|
12527
|
+
const L = [];
|
|
12528
|
+
L.push(KADDO_BEGIN_MARKER, "");
|
|
12529
|
+
L.push("## Kaddo guidance", "");
|
|
12530
|
+
if (ctx.projectName) L.push(`Project: **${ctx.projectName}**${ctx.projectType ? ` (${ctx.projectType})` : ""}.`, "");
|
|
12531
|
+
L.push("This repository uses **Kaddo** for Knowledge Driven Development. Kaddo keeps business,");
|
|
12532
|
+
L.push("product, technical and delivery knowledge close to the code. Read the relevant Kaddo");
|
|
12533
|
+
L.push("knowledge before changing code.");
|
|
12534
|
+
L.push("");
|
|
12535
|
+
L.push("### Kaddo knowledge map", "");
|
|
12536
|
+
L.push("Primary knowledge:");
|
|
12537
|
+
for (const p2 of ctx.knowledgePaths.length > 0 ? ctx.knowledgePaths : KNOWLEDGE_PATHS) L.push(`- \`${p2}\``);
|
|
12538
|
+
L.push("");
|
|
12539
|
+
L.push("Generated context (do not edit by hand):");
|
|
12540
|
+
for (const p2 of ctx.generatedPaths) L.push(`- \`${p2}\``);
|
|
12541
|
+
L.push("");
|
|
12542
|
+
L.push("### Kaddo operating rules", "");
|
|
12543
|
+
L.push("- Do not generate a roadmap without checking open-questions readiness.");
|
|
12544
|
+
L.push("- Do not implement without reading the active Work Item.");
|
|
12545
|
+
L.push("- Do not implement outside the scope of the active Work Item unless the user confirms.");
|
|
12546
|
+
L.push("- Do not modify `.kaddo/` manually; it is generated output.");
|
|
12547
|
+
L.push("- Do not commit without user confirmation.");
|
|
12548
|
+
L.push("");
|
|
12549
|
+
for (const line of commandFallbackSection(ctx.packageManager, "### ")) L.push(line);
|
|
12550
|
+
L.push("### Before roadmap work", "");
|
|
12551
|
+
L.push("Check open-questions readiness first. If blocking open questions exist, ask the user to");
|
|
12552
|
+
L.push("resolve, assume or defer them before generating the roadmap.");
|
|
12553
|
+
L.push("");
|
|
12554
|
+
L.push("### Before implementation", "");
|
|
12555
|
+
L.push("Read the target Work Item in `knowledge/delivery/work-items/`, `.kaddo/context-pack.md`,");
|
|
12556
|
+
L.push("`.kaddo/understand.md`, and related knowledge and skills.");
|
|
12557
|
+
L.push("");
|
|
12558
|
+
L.push("### After implementation", "");
|
|
12559
|
+
L.push("Suggest running `kaddo guard`, `kaddo impact`, `kaddo savings` and `kaddo drift`. If guard");
|
|
12560
|
+
L.push("reports drift, explain it and ask before updating knowledge.");
|
|
12561
|
+
L.push("");
|
|
12562
|
+
if (ctx.hasAgents) {
|
|
12563
|
+
L.push(`### Kaddo agents`, "");
|
|
12564
|
+
L.push(`Installed under \`knowledge/agents/\`: ${ctx.agents.map((a) => `\`${a}\``).join(", ")}.`);
|
|
12565
|
+
L.push("");
|
|
12566
|
+
}
|
|
12567
|
+
if (ctx.hasSkills) {
|
|
12568
|
+
L.push(`### Kaddo skills`, "");
|
|
12569
|
+
L.push(`Installed under \`knowledge/skills/\`: ${ctx.skills.map((s) => `\`${s}\``).join(", ")}. Read only what's relevant.`);
|
|
12570
|
+
L.push("");
|
|
12571
|
+
}
|
|
12572
|
+
L.push(KADDO_END_MARKER);
|
|
12573
|
+
return L.join("\n");
|
|
12574
|
+
}
|
|
12575
|
+
function injectKaddoBlock(existing, ctx) {
|
|
12576
|
+
const block = renderKaddoBlock(ctx);
|
|
12577
|
+
const begin = existing.indexOf(KADDO_BEGIN_MARKER);
|
|
12578
|
+
const end = existing.indexOf(KADDO_END_MARKER);
|
|
12579
|
+
if (begin === -1 !== (end === -1)) {
|
|
12580
|
+
throw new Error("Invalid Kaddo adapter block: found one marker without its pair.");
|
|
12581
|
+
}
|
|
12582
|
+
if (begin !== -1 && end !== -1) {
|
|
12583
|
+
if (end < begin) throw new Error("Invalid Kaddo adapter block: END marker before BEGIN marker.");
|
|
12584
|
+
const before = existing.slice(0, begin);
|
|
12585
|
+
const after = existing.slice(end + KADDO_END_MARKER.length);
|
|
12586
|
+
return { content: `${before}${block}${after}`, status: "updated" };
|
|
12587
|
+
}
|
|
12588
|
+
const sep = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
12589
|
+
return { content: `${existing.replace(/\s*$/, "")}
|
|
12590
|
+
${sep}${block}
|
|
12591
|
+
`, status: "injected" };
|
|
12592
|
+
}
|
|
12496
12593
|
|
|
12497
12594
|
// src/commands/adapters.ts
|
|
12498
12595
|
function runAdaptersInstall(adapter, opts = {}) {
|
|
@@ -12502,20 +12599,62 @@ function runAdaptersInstall(adapter, opts = {}) {
|
|
|
12502
12599
|
console.error(`Unknown adapter: "${adapter}". Available: codex.`);
|
|
12503
12600
|
process.exit(1);
|
|
12504
12601
|
}
|
|
12505
|
-
const
|
|
12602
|
+
const ctx = buildCodexAdapterContext(dir);
|
|
12603
|
+
const rel = "AGENTS.md";
|
|
12604
|
+
const full = join(dir, rel);
|
|
12605
|
+
const existed = exists(full);
|
|
12606
|
+
const existing = existed ? readFile(full) : null;
|
|
12607
|
+
if (opts.inject) {
|
|
12608
|
+
const state = detectAgentsState(existing);
|
|
12609
|
+
if (state === "invalid_kaddo_block") {
|
|
12610
|
+
console.error("Invalid Kaddo adapter block detected in AGENTS.md.");
|
|
12611
|
+
console.error("Found one marker without its pair. Fix the file manually or use --force to overwrite.");
|
|
12612
|
+
console.error("Nothing changed.");
|
|
12613
|
+
process.exit(1);
|
|
12614
|
+
}
|
|
12615
|
+
if (existing === null) {
|
|
12616
|
+
const content2 = renderAgentsMd(ctx);
|
|
12617
|
+
if (opts.dryRun) {
|
|
12618
|
+
console.log("# AGENTS.md preview", "");
|
|
12619
|
+
console.log(content2);
|
|
12620
|
+
return;
|
|
12621
|
+
}
|
|
12622
|
+
intro2("kaddo adapters install codex --inject");
|
|
12623
|
+
writeFile(full, content2);
|
|
12624
|
+
log2.success("Created AGENTS.md for Codex.");
|
|
12625
|
+
printCommandFooter("adapters install codex");
|
|
12626
|
+
outro2("AGENTS.md ready.");
|
|
12627
|
+
return;
|
|
12628
|
+
}
|
|
12629
|
+
const merged = injectKaddoBlock(existing, ctx);
|
|
12630
|
+
if (opts.dryRun) {
|
|
12631
|
+
console.log("# AGENTS.md preview (inject)", "");
|
|
12632
|
+
console.log(merged.content);
|
|
12633
|
+
return;
|
|
12634
|
+
}
|
|
12635
|
+
intro2("kaddo adapters install codex --inject");
|
|
12636
|
+
writeFile(full, merged.content);
|
|
12637
|
+
if (merged.status === "updated") {
|
|
12638
|
+
log2.success("Updated existing Kaddo guidance block in AGENTS.md.");
|
|
12639
|
+
} else {
|
|
12640
|
+
log2.success("Injected Kaddo guidance block into AGENTS.md.");
|
|
12641
|
+
}
|
|
12642
|
+
log2.info("Content outside the Kaddo markers was preserved.");
|
|
12643
|
+
printCommandFooter("adapters install codex");
|
|
12644
|
+
outro2("AGENTS.md ready.");
|
|
12645
|
+
return;
|
|
12646
|
+
}
|
|
12647
|
+
const content = renderAgentsMd(ctx);
|
|
12506
12648
|
if (opts.dryRun) {
|
|
12507
12649
|
console.log("# AGENTS.md preview", "");
|
|
12508
12650
|
console.log(content);
|
|
12509
12651
|
return;
|
|
12510
12652
|
}
|
|
12511
12653
|
intro2("kaddo adapters install codex");
|
|
12512
|
-
const rel = "AGENTS.md";
|
|
12513
|
-
const full = join(dir, rel);
|
|
12514
|
-
const existed = exists(full);
|
|
12515
12654
|
if (existed && !opts.force) {
|
|
12516
12655
|
log2.warn("AGENTS.md already exists.");
|
|
12517
|
-
log2.info("Use `
|
|
12518
|
-
log2.info("
|
|
12656
|
+
log2.info("Use `--inject` to add or update only the Kaddo block,");
|
|
12657
|
+
log2.info("`--force` to overwrite, or `--dry-run` to preview.");
|
|
12519
12658
|
outro2("Nothing changed.");
|
|
12520
12659
|
return;
|
|
12521
12660
|
}
|
|
@@ -12580,10 +12719,10 @@ var questionsAction = (opts) => runQuestions(opts);
|
|
|
12580
12719
|
program.command("questions").description("Open-questions readiness gate: blocking/important/deferred decisions before the roadmap").option("--json", "Output JSON instead of a summary").option("--output <path>", "Write the report to a file (e.g. .kaddo/reports/questions-report.md)").action(questionsAction);
|
|
12581
12720
|
program.command("readiness").description("Alias for `kaddo questions`").option("--json", "Output JSON instead of a summary").option("--output <path>", "Write the report to a file").action(questionsAction);
|
|
12582
12721
|
var adaptersCmd = program.command("adapters").description("Generate adapters that project Kaddo knowledge for external coding agents");
|
|
12583
|
-
adaptersCmd.command("install <adapter>").description("Generate an adapter file (codex \u2192 AGENTS.md) from Kaddo knowledge").option("--force", "Overwrite an existing output file").option("--dry-run", "Print the content without writing files").action((adapter, opts) => {
|
|
12722
|
+
adaptersCmd.command("install <adapter>").description("Generate an adapter file (codex \u2192 AGENTS.md) from Kaddo knowledge").option("--force", "Overwrite an existing output file").option("--inject", "Add or update only the Kaddo block in an existing file, preserving the rest").option("--dry-run", "Print the content without writing files").action((adapter, opts) => {
|
|
12584
12723
|
runAdaptersInstall(adapter, opts);
|
|
12585
12724
|
});
|
|
12586
|
-
program.command("export <adapter>").description("Alias for `kaddo adapters install <adapter>` (codex \u2192 AGENTS.md)").option("--force", "Overwrite an existing output file").option("--dry-run", "Print the content without writing files").action((adapter, opts) => {
|
|
12725
|
+
program.command("export <adapter>").description("Alias for `kaddo adapters install <adapter>` (codex \u2192 AGENTS.md)").option("--force", "Overwrite an existing output file").option("--inject", "Add or update only the Kaddo block in an existing file, preserving the rest").option("--dry-run", "Print the content without writing files").action((adapter, opts) => {
|
|
12587
12726
|
runAdaptersInstall(adapter, opts);
|
|
12588
12727
|
});
|
|
12589
12728
|
program.command("guard").description("Check if modified code has related artifacts that were not updated").option("--staged", "Check only staged files").option("--no-interactive", "Disable interactive ignore prompts").option("--ci", "CI mode: output JSON, no prompts, non-blocking").option("--json", "Output JSON (alias for --ci)").option("--workspace", "Also check local mapped module repos from .kaddo/modules.yml (opt-in)").option("--include-archived", "Include archived Work Items in ownership matching (excluded by default)").option("--record", "Record this run to .kaddo/history/ for drift trend reporting").action(async (opts) => {
|