@kaddo/cli 3.25.1 → 3.27.0

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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/index.js +520 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -516,6 +516,8 @@ create --from roadmap → owners → guard → explain`.
516
516
  | v3.24 | Estimated Savings Model: `kaddo savings` (+ `savings init`, `.kaddo/savings.yml`); evidence-based time/value estimates, confidence; MCP resource + tool |
517
517
  | v3.25 | Guard history & drift trend: `kaddo guard --record`, `kaddo drift`; feeds impact Guard Activity + savings Drift Prevention; MCP drift/guard-history resources + tool |
518
518
  | v3.25.1 | Savings guard-history messaging fix: distinguishes "no history" from "history with 0 resolved warnings" (drift prevention available at 0 h) |
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
+ | v3.27 | Codex adapter: `kaddo adapters install codex` (alias `kaddo export codex`) generates a compact `AGENTS.md` projection (`--dry-run`/`--force`) |
519
521
 
520
522
  **Optional modules (installed with `kaddo add`):**
521
523
 
package/dist/index.js CHANGED
@@ -696,6 +696,14 @@ var COMMAND_HELP = {
696
696
  drift: {
697
697
  question: "Are code and knowledge drifting apart over time?",
698
698
  next: "Review open warnings; `kaddo guard --record` before commits"
699
+ },
700
+ questions: {
701
+ question: "Are there open questions to decide before the roadmap?",
702
+ next: "Resolve, assume or defer blocking questions, then generate the roadmap"
703
+ },
704
+ "adapters install codex": {
705
+ question: "How does Codex work with this Kaddo project?",
706
+ next: "Open AGENTS.md, or regenerate it after knowledge changes"
699
707
  }
700
708
  };
701
709
  function commandFooterLines(name) {
@@ -2401,6 +2409,21 @@ open question):
2401
2409
  - \`knowledge/knowledge.md\`
2402
2410
  - business priorities
2403
2411
 
2412
+ ## Readiness Gate (check first)
2413
+
2414
+ Before generating the roadmap, check **roadmap readiness** for open questions that affect scope,
2415
+ architecture or the MVP. Read \`kaddo://roadmap-readiness\` (MCP) or run \`kaddo questions\`.
2416
+
2417
+ If readiness is \`needs_decisions\` (there are **blocking** open questions), do **not** generate the
2418
+ roadmap yet. Instead, list the blocking questions, propose reasonable assumptions for each, and ask
2419
+ the user to confirm, e.g.:
2420
+
2421
+ > Before generating the roadmap I found blocking open questions that affect the MVP scope.
2422
+ > I can proceed with these assumptions: \u2026 Confirm and continue?
2423
+
2424
+ Only generate the roadmap once the user confirms the assumptions (or resolves/defers the
2425
+ questions). Record confirmed assumptions explicitly in the roadmap.
2426
+
2404
2427
  ## Expected Output
2405
2428
 
2406
2429
  A single Markdown artifact intended to be saved as \`knowledge/delivery/roadmap.md\`.
@@ -2709,6 +2732,13 @@ Work Items into clear, traceable units of work.
2709
2732
  You do not write code. You sharpen the problem, validate the Knowledge Level and make the
2710
2733
  Work Item actionable for a human.
2711
2734
 
2735
+ ## Readiness Gate (check first)
2736
+
2737
+ For high-impact Work Items, check \`kaddo://roadmap-readiness\` (or \`kaddo questions\`) for
2738
+ **blocking** open questions related to this Work Item's scope. If any are unresolved, surface them
2739
+ and propose assumptions for the user to confirm before refining \u2014 don't bake in invisible
2740
+ assumptions.
2741
+
2712
2742
  ## When to Use
2713
2743
 
2714
2744
  Use this agent after a roadmap exists (\`knowledge/delivery/roadmap.md\`) or when an existing Work
@@ -3210,6 +3240,13 @@ You are the Kaddo Bootstrap Agent. You guide the transition from business defini
3210
3240
  initial architecture direction, quality attributes, a roadmap and first Work Items for a
3211
3241
  new project. You propose; the human decides.
3212
3242
 
3243
+ ## Readiness Gate
3244
+
3245
+ Bootstrap surfaces \`## Open Questions\` in the knowledge files. Before moving to the roadmap,
3246
+ explicitly recommend reviewing them (\`kaddo questions\` / \`kaddo://roadmap-readiness\`) and turning
3247
+ **blocking** ones into resolved decisions or confirmed assumptions \u2014 so the roadmap isn't built on
3248
+ invisible assumptions.
3249
+
3213
3250
  ## When to Use
3214
3251
 
3215
3252
  Use this agent after \`kaddo bootstrap\` and after the business artifacts are drafted.
@@ -3321,6 +3358,13 @@ may suggest a Git branch, and only by respecting the project's Git strategy.
3321
3358
  You never run Git yourself. The Kaddo CLI never runs Git either. Every git action is the
3322
3359
  human's, and commits/pushes/merges happen only with explicit human confirmation.
3323
3360
 
3361
+ ## Readiness Gate (check first)
3362
+
3363
+ Before implementing a high-impact Work Item, check \`kaddo://roadmap-readiness\` (or
3364
+ \`kaddo questions\`) for **blocking** open questions about stack, architecture, persistence,
3365
+ authentication or the Work Item's scope. If any are unresolved, pause and ask the user to confirm
3366
+ assumptions or resolve them before writing code.
3367
+
3324
3368
  ## When to Use
3325
3369
 
3326
3370
  Use this agent after the work-item-agent has produced a clear, traceable Work Item under
@@ -8162,6 +8206,224 @@ function renderDeliveryLifecycle(wi) {
8162
8206
  ];
8163
8207
  }
8164
8208
 
8209
+ // src/core/open-questions.ts
8210
+ var SOURCES = [
8211
+ "knowledge/business/business.md",
8212
+ "knowledge/product/product.md",
8213
+ "knowledge/tech/codebase.md",
8214
+ "knowledge/delivery/roadmap.md"
8215
+ ];
8216
+ var BLOCKING = [
8217
+ "mvp",
8218
+ "stack",
8219
+ "arquitect",
8220
+ "architecture",
8221
+ "api",
8222
+ "web app",
8223
+ "webapp",
8224
+ "cli",
8225
+ "backend",
8226
+ "auth",
8227
+ "autenticaci",
8228
+ "persist",
8229
+ "base de datos",
8230
+ "database",
8231
+ "roadmap",
8232
+ "alcance",
8233
+ "scope",
8234
+ "primera versi\xF3n",
8235
+ "primera version",
8236
+ "first version",
8237
+ "fastify",
8238
+ "nestjs",
8239
+ "framework"
8240
+ ];
8241
+ var DEFERRED = [
8242
+ "integraci",
8243
+ "integration",
8244
+ "analytics",
8245
+ "notificaci",
8246
+ "notification",
8247
+ "google calendar",
8248
+ "eventbrite",
8249
+ "meetup",
8250
+ "dashboard",
8251
+ "multi-tenant",
8252
+ "multitenant",
8253
+ "mobile",
8254
+ "m\xF3vil",
8255
+ "pago",
8256
+ "payment",
8257
+ "ticketing",
8258
+ "multiple tracks",
8259
+ "m\xFAltiples tracks",
8260
+ "webhook"
8261
+ ];
8262
+ var IMPORTANT = [
8263
+ "validaci",
8264
+ "validation",
8265
+ "paginaci",
8266
+ "pagination",
8267
+ "soft delete",
8268
+ "sponsor",
8269
+ "agenda",
8270
+ "ubicaci",
8271
+ "location",
8272
+ "rol",
8273
+ "role",
8274
+ "permis",
8275
+ "permission"
8276
+ ];
8277
+ function matchesAny(text3, keywords) {
8278
+ return keywords.some((k) => text3.includes(k));
8279
+ }
8280
+ function classifyQuestion(question) {
8281
+ const t = question.toLowerCase();
8282
+ if (matchesAny(t, BLOCKING)) {
8283
+ return { classification: "blocking", reason: "Affects scope, architecture or the first Work Items." };
8284
+ }
8285
+ if (matchesAny(t, DEFERRED) && !matchesAny(t, IMPORTANT)) {
8286
+ return { classification: "deferred", reason: "Can be moved to a later phase." };
8287
+ }
8288
+ if (matchesAny(t, IMPORTANT)) {
8289
+ return { classification: "important", reason: "Relevant, but a temporary assumption can unblock progress." };
8290
+ }
8291
+ return { classification: "important", reason: "Relevant, but a temporary assumption can unblock progress." };
8292
+ }
8293
+ function extractFromMarkdown(md) {
8294
+ const lines = md.split(/\r?\n/);
8295
+ const start = lines.findIndex((l) => /^#{1,6}\s+open questions\s*$/i.test(l.trim()) || /^#{1,6}\s+preguntas abiertas\s*$/i.test(l.trim()));
8296
+ if (start < 0) return [];
8297
+ const out = [];
8298
+ for (let i = start + 1; i < lines.length; i++) {
8299
+ const line = lines[i];
8300
+ if (/^#{1,6}\s+/.test(line)) break;
8301
+ const m = line.match(/^\s*(?:[-*]|\d+\.)\s+(.+?)\s*$/);
8302
+ if (m) {
8303
+ const q = m[1].trim();
8304
+ if (q && !/^_.*_$/.test(q)) out.push(q);
8305
+ }
8306
+ }
8307
+ return out;
8308
+ }
8309
+ function suggestedAssumption(question) {
8310
+ const t = question.toLowerCase();
8311
+ if (matchesAny(t, ["api", "web app", "webapp", "cli", "backend"])) {
8312
+ return "Start as a backend API to keep the initial scope small.";
8313
+ }
8314
+ if (matchesAny(t, ["auth", "autenticaci"])) {
8315
+ return "No authentication in the MVP.";
8316
+ }
8317
+ if (matchesAny(t, ["fastify", "nestjs", "framework", "stack"])) {
8318
+ return "Choose the lighter stack option to minimize MVP scope.";
8319
+ }
8320
+ if (matchesAny(t, ["persist", "base de datos", "database"])) {
8321
+ return "Use a simple local datastore (e.g. SQLite) for the MVP.";
8322
+ }
8323
+ return "Proceed with the smallest reasonable MVP interpretation and revisit later.";
8324
+ }
8325
+ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
8326
+ const project = loadConfig(dir)?.project.name ?? "unknown";
8327
+ const questions = [];
8328
+ let seq = 0;
8329
+ for (const source of SOURCES) {
8330
+ const p2 = join(dir, source);
8331
+ if (!exists(p2)) continue;
8332
+ let md;
8333
+ try {
8334
+ md = readFile(p2);
8335
+ } catch {
8336
+ continue;
8337
+ }
8338
+ for (const q of extractFromMarkdown(md)) {
8339
+ seq += 1;
8340
+ const { classification, reason } = classifyQuestion(q);
8341
+ questions.push({
8342
+ id: `OQ-${String(seq).padStart(3, "0")}`,
8343
+ source,
8344
+ section: "Open Questions",
8345
+ question: q,
8346
+ classification,
8347
+ reason,
8348
+ ...classification === "blocking" ? { suggested_assumption: suggestedAssumption(q) } : {}
8349
+ });
8350
+ }
8351
+ }
8352
+ const blocking = questions.filter((q) => q.classification === "blocking");
8353
+ const important = questions.filter((q) => q.classification === "important");
8354
+ const deferred = questions.filter((q) => q.classification === "deferred");
8355
+ let readiness;
8356
+ if (questions.length === 0) readiness = "unknown";
8357
+ else if (blocking.length > 0) readiness = "needs_decisions";
8358
+ else readiness = "ready";
8359
+ const suggested_assumptions = blocking.map((q) => q.suggested_assumption).filter(Boolean);
8360
+ const recommended_next_step = readiness === "needs_decisions" ? "Confirm suggested assumptions with the user (resolve, assume or defer blocking questions) before generating the roadmap." : readiness === "ready" ? "No blocking questions \u2014 you can proceed to the roadmap (review important questions when convenient)." : "No open questions found. Run `kaddo bootstrap` to capture early questions, or proceed.";
8361
+ return {
8362
+ generated_at: now.toISOString(),
8363
+ project,
8364
+ summary: {
8365
+ open_questions: questions.length,
8366
+ roadmap_readiness: readiness,
8367
+ blocking: blocking.length,
8368
+ important: important.length,
8369
+ deferred: deferred.length
8370
+ },
8371
+ questions,
8372
+ blocking_questions: blocking,
8373
+ important_questions: important,
8374
+ deferred_questions: deferred,
8375
+ suggested_assumptions,
8376
+ recommended_next_step
8377
+ };
8378
+ }
8379
+ function renderOpenQuestionsMarkdown(r) {
8380
+ const L = [];
8381
+ L.push("# Kaddo Open Questions Readiness Report", "");
8382
+ L.push(`Generated at: ${r.generated_at}`);
8383
+ L.push(`Project: ${r.project}`);
8384
+ L.push("");
8385
+ L.push("## Summary", "");
8386
+ L.push(`- Open questions found: ${r.summary.open_questions}`);
8387
+ L.push(`- Roadmap readiness: ${r.summary.roadmap_readiness}`);
8388
+ L.push(`- Blocking: ${r.summary.blocking}`);
8389
+ L.push(`- Important: ${r.summary.important}`);
8390
+ L.push(`- Deferred: ${r.summary.deferred}`);
8391
+ L.push("");
8392
+ if (r.summary.open_questions === 0) {
8393
+ L.push("No `## Open Questions` sections found in business / product / codebase / roadmap.", "");
8394
+ L.push("## Recommended Next Step", "", r.recommended_next_step, "");
8395
+ return L.join("\n");
8396
+ }
8397
+ L.push("## Blocking Questions", "");
8398
+ if (r.blocking_questions.length === 0) L.push("_None._", "");
8399
+ for (const q of r.blocking_questions) {
8400
+ L.push(`### ${q.id}`, "");
8401
+ L.push(`- Source: \`${q.source}\``);
8402
+ L.push(`- Question: ${q.question}`);
8403
+ L.push(`- Reason: ${q.reason}`);
8404
+ if (q.suggested_assumption) L.push(`- Suggested assumption: ${q.suggested_assumption}`);
8405
+ L.push("");
8406
+ }
8407
+ L.push("## Important Questions", "");
8408
+ if (r.important_questions.length === 0) L.push("_None._");
8409
+ for (const q of r.important_questions) L.push(`- ${q.question}`);
8410
+ L.push("");
8411
+ L.push("## Deferred Questions", "");
8412
+ if (r.deferred_questions.length === 0) L.push("_None._");
8413
+ for (const q of r.deferred_questions) L.push(`- ${q.question}`);
8414
+ L.push("");
8415
+ if (r.suggested_assumptions.length > 0) {
8416
+ L.push("## Suggested Assumptions", "");
8417
+ for (const a of r.suggested_assumptions) L.push(`- ${a}`);
8418
+ L.push("");
8419
+ }
8420
+ L.push("## Recommended Next Step", "", r.recommended_next_step, "");
8421
+ return L.join("\n");
8422
+ }
8423
+ function serializeOpenQuestionsJson(r) {
8424
+ return JSON.stringify(r, null, 2) + "\n";
8425
+ }
8426
+
8165
8427
  // src/commands/understand.ts
8166
8428
  function runUnderstand() {
8167
8429
  const dir = cwd();
@@ -8234,6 +8496,12 @@ function runUnderstand() {
8234
8496
  console.log(" \u2192 Review graph hints before continuing with implementation.");
8235
8497
  console.log(" Suggested agent: graph-agent (see .kaddo/graph-hints.md)");
8236
8498
  }
8499
+ const oq = buildOpenQuestionsReport(dir);
8500
+ if (oq.summary.blocking > 0) {
8501
+ console.log("");
8502
+ console.log(`Open questions: ${oq.summary.blocking} blocking decision(s) before the roadmap (roadmap readiness: ${oq.summary.roadmap_readiness}).`);
8503
+ console.log(" \u2192 Run `kaddo questions` to review them, then resolve, assume or defer before `kaddo create --from roadmap`.");
8504
+ }
8237
8505
  const active = activeWorkItems(dir);
8238
8506
  if (active.length > 0) {
8239
8507
  console.log("");
@@ -8291,35 +8559,35 @@ var DEP_PATTERNS = [
8291
8559
  function normalizePath2(p2) {
8292
8560
  return p2.split(path5.sep).join("/");
8293
8561
  }
8294
- function matchesAny(file, patterns) {
8562
+ function matchesAny2(file, patterns) {
8295
8563
  const normalized = normalizePath2(file);
8296
8564
  return patterns.some((p2) => p2.test(normalized));
8297
8565
  }
8298
8566
  function detectSignals(touchedFiles) {
8299
8567
  const signals = [];
8300
8568
  for (const file of touchedFiles) {
8301
- if (matchesAny(file, MIGRATION_PATTERNS)) {
8569
+ if (matchesAny2(file, MIGRATION_PATTERNS)) {
8302
8570
  signals.push({
8303
8571
  name: "DB migration",
8304
8572
  file,
8305
8573
  implication: "Data schema change \u2014 typically K4 or Migration type",
8306
8574
  suggestedLevel: "K4"
8307
8575
  });
8308
- } else if (matchesAny(file, CONTRACT_PATTERNS)) {
8576
+ } else if (matchesAny2(file, CONTRACT_PATTERNS)) {
8309
8577
  signals.push({
8310
8578
  name: "API/event contract",
8311
8579
  file,
8312
8580
  implication: "Contract change affects consumers \u2014 typically K3/K4",
8313
8581
  suggestedLevel: "K3"
8314
8582
  });
8315
- } else if (matchesAny(file, INFRA_PATTERNS)) {
8583
+ } else if (matchesAny2(file, INFRA_PATTERNS)) {
8316
8584
  signals.push({
8317
8585
  name: "Infrastructure",
8318
8586
  file,
8319
8587
  implication: "Infrastructure change \u2014 typically K3/K4",
8320
8588
  suggestedLevel: "K3"
8321
8589
  });
8322
- } else if (matchesAny(file, DEP_PATTERNS)) {
8590
+ } else if (matchesAny2(file, DEP_PATTERNS)) {
8323
8591
  signals.push({
8324
8592
  name: "Dependency",
8325
8593
  file,
@@ -11995,6 +12263,243 @@ function runDrift(opts = {}) {
11995
12263
  console.log(content);
11996
12264
  }
11997
12265
 
12266
+ // src/commands/questions.ts
12267
+ function runQuestions(opts = {}) {
12268
+ const dir = cwd();
12269
+ requireConfig(dir);
12270
+ const report = buildOpenQuestionsReport(dir);
12271
+ if (opts.output) {
12272
+ intro2("kaddo questions");
12273
+ writeFile(join(dir, opts.output), opts.json ? serializeOpenQuestionsJson(report) : renderOpenQuestionsMarkdown(report));
12274
+ log2.success(`Wrote ${opts.output.replace(/\\/g, "/")}`);
12275
+ printCommandFooter("questions");
12276
+ outro2("Questions report written.");
12277
+ return;
12278
+ }
12279
+ if (opts.json) {
12280
+ console.log(serializeOpenQuestionsJson(report));
12281
+ return;
12282
+ }
12283
+ console.log("");
12284
+ console.log(`Open questions detected: ${report.summary.open_questions}`);
12285
+ console.log(`Roadmap readiness: ${report.summary.roadmap_readiness === "needs_decisions" ? "needs decisions" : report.summary.roadmap_readiness}`);
12286
+ const list2 = (title, qs) => {
12287
+ if (qs.length === 0) return;
12288
+ console.log("");
12289
+ console.log(`${title}:`);
12290
+ for (const q of qs.slice(0, 8)) console.log(`- ${q.question}`);
12291
+ if (qs.length > 8) console.log(` \u2026and ${qs.length - 8} more`);
12292
+ };
12293
+ list2("Blocking", report.blocking_questions);
12294
+ list2("Important", report.important_questions);
12295
+ list2("Deferred", report.deferred_questions);
12296
+ console.log("");
12297
+ console.log("Suggested next:");
12298
+ console.log(report.recommended_next_step);
12299
+ printCommandFooter("questions");
12300
+ }
12301
+
12302
+ // src/core/codex-adapter.ts
12303
+ var KNOWLEDGE_PATHS = [
12304
+ "knowledge/business/",
12305
+ "knowledge/product/",
12306
+ "knowledge/tech/",
12307
+ "knowledge/delivery/",
12308
+ "knowledge/agents/",
12309
+ "knowledge/skills/"
12310
+ ];
12311
+ var GENERATED_PATHS = [
12312
+ ".kaddo/context-pack.md",
12313
+ ".kaddo/understand.md",
12314
+ ".kaddo/explain.md",
12315
+ ".kaddo/graph.json",
12316
+ ".kaddo/reports/"
12317
+ ];
12318
+ function discoverAgents(dir) {
12319
+ const base = join(dir, "knowledge", "agents");
12320
+ if (!exists(base) || !isDir(base)) return [];
12321
+ const out = /* @__PURE__ */ new Set();
12322
+ const walk = (d) => {
12323
+ for (const e of readDir(d)) {
12324
+ const full = join(d, e);
12325
+ if (isDir(full)) walk(full);
12326
+ else if (e.endsWith("-agent.md")) out.add(e.replace(/\.md$/, ""));
12327
+ }
12328
+ };
12329
+ walk(base);
12330
+ return [...out].sort();
12331
+ }
12332
+ function buildCodexAdapterContext(dir) {
12333
+ const config = loadConfig(dir);
12334
+ const agents = discoverAgents(dir);
12335
+ const skills = discoverInstalledSkills(dir).map((s) => s.id);
12336
+ return {
12337
+ projectName: config?.project.name,
12338
+ projectType: config?.project.state,
12339
+ language: config ? config.project.language : void 0,
12340
+ hasAgents: agents.length > 0,
12341
+ agents,
12342
+ hasSkills: skills.length > 0,
12343
+ skills,
12344
+ hasMcpHint: detectMcpHint(dir),
12345
+ knowledgePaths: KNOWLEDGE_PATHS.filter((p2) => exists(join(dir, p2))),
12346
+ generatedPaths: GENERATED_PATHS
12347
+ };
12348
+ }
12349
+ function detectMcpHint(dir) {
12350
+ for (const f of [".mcp.json", "mcp.json", ".cursor/mcp.json"]) {
12351
+ if (exists(join(dir, f))) return true;
12352
+ }
12353
+ return false;
12354
+ }
12355
+ var ROLE_HINTS = {
12356
+ "roadmap-agent": "use before creating or refining the roadmap.",
12357
+ "work-item-agent": "use before refining Work Items.",
12358
+ "implementation-agent": "use before implementing Work Items.",
12359
+ "bootstrap-agent": "use when refining initial knowledge.",
12360
+ "ownership-agent": "use to propose precise `code:` ownership globs.",
12361
+ "graph-agent": "use to turn graph hints into front matter.",
12362
+ "capsule-agent": "use to refine a Knowledge Capsule for sharing."
12363
+ };
12364
+ function renderAgentsMd(ctx) {
12365
+ const L = [];
12366
+ L.push("<!-- Generated by `kaddo adapters install codex`. Kaddo is the source of truth \u2014");
12367
+ L.push(" regenerate this file instead of editing it by hand. Do not treat it as primary. -->");
12368
+ L.push("# AGENTS.md", "");
12369
+ L.push("## Project guidance", "");
12370
+ if (ctx.projectName) L.push(`Project: **${ctx.projectName}**${ctx.projectType ? ` (${ctx.projectType})` : ""}.`, "");
12371
+ L.push("This repository uses **Kaddo** for Knowledge Driven Development. Kaddo keeps business,");
12372
+ L.push("product, technical and delivery knowledge close to the code.");
12373
+ L.push("");
12374
+ L.push("Before making changes, read the relevant Kaddo knowledge files instead of relying only on");
12375
+ L.push("source code.");
12376
+ L.push("");
12377
+ L.push("## Kaddo knowledge map", "");
12378
+ L.push("Primary knowledge lives in:", "");
12379
+ for (const p2 of ctx.knowledgePaths.length > 0 ? ctx.knowledgePaths : KNOWLEDGE_PATHS) L.push(`- \`${p2}\``);
12380
+ L.push("");
12381
+ L.push("Derived context (generated \u2014 do not edit by hand) lives in:", "");
12382
+ for (const p2 of ctx.generatedPaths) L.push(`- \`${p2}\``);
12383
+ L.push("");
12384
+ L.push("## Operating rules", "");
12385
+ L.push("- Do not generate a roadmap without checking open-questions readiness.");
12386
+ L.push("- Do not implement without reading the active Work Item.");
12387
+ L.push("- Do not assume missing product or business decisions \u2014 prefer explicit assumptions.");
12388
+ L.push("- Keep knowledge updated when implementation changes scope.");
12389
+ L.push("- Do not modify `.kaddo/` manually; it is generated output.");
12390
+ L.push("- Do not commit without user confirmation.");
12391
+ L.push("");
12392
+ L.push("## Before roadmap work", "");
12393
+ L.push("Read `knowledge/business/business.md`, `knowledge/product/product.md`,");
12394
+ L.push("`knowledge/tech/codebase.md`, and `.kaddo/reports/questions-report.md` if available.");
12395
+ L.push("");
12396
+ L.push("Check open-questions readiness first. **If blocking open questions exist, ask the user to");
12397
+ L.push("resolve, assume or defer them before generating the roadmap** \u2014 never build the roadmap on");
12398
+ L.push("invisible assumptions.");
12399
+ L.push("");
12400
+ L.push("## Before implementation", "");
12401
+ L.push("Read the target Work Item in `knowledge/delivery/work-items/`, `.kaddo/context-pack.md`,");
12402
+ L.push("`.kaddo/understand.md`, and the related knowledge and skills files.");
12403
+ L.push("");
12404
+ L.push("Do not implement outside the scope of the active Work Item unless the user confirms.");
12405
+ L.push("");
12406
+ L.push("## After implementation", "");
12407
+ L.push("Suggest running, as validation (not mandatory):", "");
12408
+ L.push("```bash");
12409
+ L.push("kaddo guard");
12410
+ L.push("kaddo impact");
12411
+ L.push("kaddo savings");
12412
+ L.push("kaddo drift");
12413
+ L.push("```");
12414
+ L.push("");
12415
+ L.push("Before finishing a change, suggest `kaddo guard`. If warnings appear, explain the possible");
12416
+ L.push("knowledge drift and ask the user whether to update the related knowledge \u2014 never update it");
12417
+ L.push("automatically.");
12418
+ L.push("");
12419
+ if (ctx.hasAgents) {
12420
+ L.push("## Available Kaddo agents", "");
12421
+ L.push("Installed under `knowledge/agents/`. Use them as role-specific guidance when relevant:", "");
12422
+ for (const a of ctx.agents) {
12423
+ const hint = ROLE_HINTS[a];
12424
+ L.push(`- \`${a}\`${hint ? `: ${hint}` : ""}`);
12425
+ }
12426
+ L.push("");
12427
+ }
12428
+ if (ctx.hasSkills) {
12429
+ L.push("## Available Kaddo skills", "");
12430
+ L.push("Reusable skills under `knowledge/skills/`. Read only the skills relevant to the current");
12431
+ L.push("task \u2014 do not load every skill by default.", "");
12432
+ for (const s of ctx.skills) L.push(`- \`${s}\``);
12433
+ L.push("");
12434
+ }
12435
+ if (ctx.hasMcpHint) {
12436
+ L.push("## MCP", "");
12437
+ L.push("A Kaddo MCP server appears to be configured. Prefer MCP resources over manually scanning");
12438
+ L.push("generated files:", "");
12439
+ for (const r of ["kaddo://context-pack", "kaddo://understand", "kaddo://explain", "kaddo://open-questions", "kaddo://roadmap-readiness", "kaddo://impact-report", "kaddo://savings-report", "kaddo://drift-report"]) {
12440
+ L.push(`- \`${r}\``);
12441
+ }
12442
+ L.push("");
12443
+ }
12444
+ L.push("## Useful Kaddo commands", "");
12445
+ L.push("```bash");
12446
+ for (const c of ["kaddo context", "kaddo understand", "kaddo explain", "kaddo graph export", "kaddo questions", "kaddo guard", "kaddo impact", "kaddo savings", "kaddo drift"]) {
12447
+ L.push(c);
12448
+ }
12449
+ L.push("```");
12450
+ L.push("");
12451
+ L.push("## Agent behavior", "");
12452
+ const steps = [
12453
+ "Identify the current task or Work Item.",
12454
+ "Read the related Kaddo knowledge.",
12455
+ "Check readiness gates (open questions).",
12456
+ "Implement only the requested scope.",
12457
+ "Validate with tests or checks.",
12458
+ "Suggest knowledge updates if implementation changed the original understanding.",
12459
+ "Ask before committing."
12460
+ ];
12461
+ steps.forEach((s, i) => L.push(`${i + 1}. ${s}`));
12462
+ L.push("");
12463
+ L.push("## Safety limits", "");
12464
+ L.push("Do not: rewrite the Kaddo methodology, delete knowledge files, manually edit generated");
12465
+ L.push("`.kaddo/` artifacts, bypass readiness gates, generate a roadmap from source code alone, or");
12466
+ L.push("implement broad changes without an active Work Item.");
12467
+ L.push("");
12468
+ return L.join("\n");
12469
+ }
12470
+
12471
+ // src/commands/adapters.ts
12472
+ function runAdaptersInstall(adapter, opts = {}) {
12473
+ const dir = cwd();
12474
+ requireConfig(dir);
12475
+ if (adapter !== "codex") {
12476
+ console.error(`Unknown adapter: "${adapter}". Available: codex.`);
12477
+ process.exit(1);
12478
+ }
12479
+ const content = renderAgentsMd(buildCodexAdapterContext(dir));
12480
+ if (opts.dryRun) {
12481
+ console.log("# AGENTS.md preview", "");
12482
+ console.log(content);
12483
+ return;
12484
+ }
12485
+ intro2("kaddo adapters install codex");
12486
+ const rel = "AGENTS.md";
12487
+ const full = join(dir, rel);
12488
+ const existed = exists(full);
12489
+ if (existed && !opts.force) {
12490
+ log2.warn("AGENTS.md already exists.");
12491
+ log2.info("Use `kaddo adapters install codex --force` to overwrite,");
12492
+ log2.info("or `kaddo adapters install codex --dry-run` to preview.");
12493
+ outro2("Nothing changed.");
12494
+ return;
12495
+ }
12496
+ writeFile(full, content);
12497
+ log2.success(`${existed ? "Overwrote" : "Created"} AGENTS.md for Codex.`);
12498
+ log2.info("Source: Kaddo project knowledge. Regenerate it instead of editing by hand.");
12499
+ printCommandFooter("adapters install codex");
12500
+ outro2("AGENTS.md ready.");
12501
+ }
12502
+
11998
12503
  // src/index.ts
11999
12504
  var require2 = createRequire(import.meta.url);
12000
12505
  var { version } = require2("../package.json");
@@ -12045,6 +12550,16 @@ reportCmd.command("drift").description("Drift Trend Report from recorded guard h
12045
12550
  program.command("drift").description("Drift Trend Report from recorded `kaddo guard --record` history").option("--json", "Output JSON instead of Markdown").option("--output <path>", "Write the report to a file").action((opts) => {
12046
12551
  runDrift(opts);
12047
12552
  });
12553
+ var questionsAction = (opts) => runQuestions(opts);
12554
+ 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);
12555
+ 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);
12556
+ var adaptersCmd = program.command("adapters").description("Generate adapters that project Kaddo knowledge for external coding agents");
12557
+ 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) => {
12558
+ runAdaptersInstall(adapter, opts);
12559
+ });
12560
+ 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) => {
12561
+ runAdaptersInstall(adapter, opts);
12562
+ });
12048
12563
  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) => {
12049
12564
  await runGuard(opts);
12050
12565
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.25.1",
3
+ "version": "3.27.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {