@kaddo/cli 3.31.0 → 3.33.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 +248 -56
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -527,6 +527,8 @@ create --from roadmap → owners → guard → explain`.
527
527
  | v3.29 | OpenCode adapter: `kaddo adapters install opencode` (alias `kaddo export opencode`) generates an `AGENTS.md` projection reusing the shared adapter common core (`--dry-run`/`--force`/`--inject` + inject guard) |
528
528
  | v3.30 | Antigravity adapter: `kaddo adapters install antigravity` (alias `kaddo export antigravity`) generates an `AGENTS.md` projection reusing the shared adapter common core (`--dry-run`/`--force`/`--inject` + inject guard) |
529
529
  | v3.31 | Kiro adapter: `kaddo adapters install kiro` (alias `kaddo export kiro`) generates an `AGENTS.md` projection reusing the shared adapter common core (`--dry-run`/`--force`/`--inject` + inject guard) |
530
+ | v3.32 | Adapter discovery & status: `kaddo adapters list` (alias `ls`) and `kaddo adapters status` (alias `check`) — read-only catalog + per-adapter install state (missing/team-owned/injected/legacy-injected/full-generated/broken-markers), shared-`AGENTS.md` origin detection, `--json` |
531
+ | v3.33 | Open questions resolution tracking: mark questions `[open]`/`[resolved]`/`[assumed]`/`[deferred]` (EN+ES); only `open` blocks readiness, so assumed/resolved/deferred decisions stop false blocks. `kaddo questions` shows status counts + `resolution_status` in JSON |
530
532
 
531
533
  **Optional modules (installed with `kaddo add`):**
532
534
 
package/dist/index.js CHANGED
@@ -2414,9 +2414,13 @@ open question):
2414
2414
  Before generating the roadmap, check **roadmap readiness** for open questions that affect scope,
2415
2415
  architecture or the MVP. Read \`kaddo://roadmap-readiness\` (MCP) or run \`kaddo questions\`.
2416
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.:
2417
+ Only questions with \`resolution_status = open\` block readiness. Questions marked \`[resolved]\`,
2418
+ \`[assumed]\` or \`[deferred]\` (EN) / \`[resuelta]\` \`[asumida]\` \`[diferida]\` (ES) do **not** block \u2014
2419
+ surface assumed ones as assumptions and deferred ones as out-of-scope, then continue.
2420
+
2421
+ If readiness is \`needs_decisions\` (there are **blocking open** questions), do **not** generate the
2422
+ roadmap yet. Instead, list the blocking open questions, propose reasonable assumptions for each, and
2423
+ ask the user to confirm, e.g.:
2420
2424
 
2421
2425
  > Before generating the roadmap I found blocking open questions that affect the MVP scope.
2422
2426
  > I can proceed with these assumptions: \u2026 Confirm and continue?
@@ -2735,9 +2739,11 @@ Work Item actionable for a human.
2735
2739
  ## Readiness Gate (check first)
2736
2740
 
2737
2741
  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.
2742
+ **blocking open** questions (\`resolution_status = open\`) related to this Work Item's scope. If any are
2743
+ open, surface them and propose assumptions for the user to confirm before refining \u2014 don't bake in
2744
+ invisible assumptions. Convert each open question into an explicit decision (\`[resolved]\`), an
2745
+ explicit assumption (\`[assumed]\`), or move it out of scope (\`[deferred]\`). Questions already marked
2746
+ resolved/assumed/deferred do not block.
2741
2747
 
2742
2748
  ## When to Use
2743
2749
 
@@ -3244,8 +3250,10 @@ new project. You propose; the human decides.
3244
3250
 
3245
3251
  Bootstrap surfaces \`## Open Questions\` in the knowledge files. Before moving to the roadmap,
3246
3252
  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.
3253
+ **blocking open** ones into resolved decisions or confirmed assumptions \u2014 so the roadmap isn't built
3254
+ on invisible assumptions. When you find unresolved questions, suggest marking each with a resolution
3255
+ token so Kaddo can track them: \`[open]\`, \`[resolved]\`, \`[assumed]\` or \`[deferred]\` (ES: \`[abierta]\`,
3256
+ \`[resuelta]\`, \`[asumida]\`, \`[diferida]\`). Only \`open\` questions block readiness.
3249
3257
 
3250
3258
  ## When to Use
3251
3259
 
@@ -3361,9 +3369,11 @@ human's, and commits/pushes/merges happen only with explicit human confirmation.
3361
3369
  ## Readiness Gate (check first)
3362
3370
 
3363
3371
  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.
3372
+ \`kaddo questions\`) for **blocking open** questions (\`resolution_status = open\`) about stack,
3373
+ architecture, persistence, authentication or the Work Item's scope. Block only on questions still
3374
+ \`open\`; if a related question is already \`[assumed]\`, \`[resolved]\` or \`[deferred]\`, proceed and
3375
+ mention the relevant assumptions instead of pausing. If any blocking question is still open, pause and
3376
+ ask the user to confirm assumptions or resolve them before writing code.
3367
3377
 
3368
3378
  ## When to Use
3369
3379
 
@@ -8207,6 +8217,24 @@ function renderDeliveryLifecycle(wi) {
8207
8217
  }
8208
8218
 
8209
8219
  // src/core/open-questions.ts
8220
+ var RESOLUTION_TOKENS = {
8221
+ open: "open",
8222
+ resolved: "resolved",
8223
+ assumed: "assumed",
8224
+ deferred: "deferred",
8225
+ abierta: "open",
8226
+ resuelta: "resolved",
8227
+ asumida: "assumed",
8228
+ diferida: "deferred"
8229
+ };
8230
+ function parseResolution(line) {
8231
+ const m = line.match(/^\[([a-zA-Záéí]+)\]\s*(.*)$/);
8232
+ if (m) {
8233
+ const status = RESOLUTION_TOKENS[m[1].toLowerCase()];
8234
+ if (status) return { text: m[2].trim(), resolution_status: status };
8235
+ }
8236
+ return { text: line.trim(), resolution_status: "open" };
8237
+ }
8210
8238
  var SOURCES = [
8211
8239
  "knowledge/business/business.md",
8212
8240
  "knowledge/product/product.md",
@@ -8298,10 +8326,17 @@ function extractFromMarkdown(md) {
8298
8326
  for (let i = start + 1; i < lines.length; i++) {
8299
8327
  const line = lines[i];
8300
8328
  if (/^#{1,6}\s+/.test(line)) break;
8329
+ const meta = line.match(/^\s+(?:[-*])\s+(\w+)\s*:\s*(.+?)\s*$/);
8330
+ if (meta && out.length > 0) {
8331
+ if (meta[1].toLowerCase() === "note") out[out.length - 1].resolution_note = meta[2].trim();
8332
+ continue;
8333
+ }
8301
8334
  const m = line.match(/^\s*(?:[-*]|\d+\.)\s+(.+?)\s*$/);
8302
8335
  if (m) {
8303
- const q = m[1].trim();
8304
- if (q && !/^_.*_$/.test(q)) out.push(q);
8336
+ const raw = m[1].trim();
8337
+ if (!raw || /^_.*_$/.test(raw)) continue;
8338
+ const { text: text3, resolution_status } = parseResolution(raw);
8339
+ if (text3) out.push({ text: text3, resolution_status });
8305
8340
  }
8306
8341
  }
8307
8342
  return out;
@@ -8335,29 +8370,37 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
8335
8370
  } catch {
8336
8371
  continue;
8337
8372
  }
8338
- for (const q of extractFromMarkdown(md)) {
8373
+ for (const eq of extractFromMarkdown(md)) {
8339
8374
  seq += 1;
8340
- const { classification, reason } = classifyQuestion(q);
8375
+ const { classification, reason } = classifyQuestion(eq.text);
8341
8376
  questions.push({
8342
8377
  id: `OQ-${String(seq).padStart(3, "0")}`,
8343
8378
  source,
8344
8379
  section: "Open Questions",
8345
- question: q,
8380
+ question: eq.text,
8346
8381
  classification,
8382
+ resolution_status: eq.resolution_status,
8347
8383
  reason,
8348
- ...classification === "blocking" ? { suggested_assumption: suggestedAssumption(q) } : {}
8384
+ ...eq.resolution_note ? { resolution_note: eq.resolution_note } : {},
8385
+ ...classification === "blocking" && eq.resolution_status === "open" ? { suggested_assumption: suggestedAssumption(eq.text) } : {}
8349
8386
  });
8350
8387
  }
8351
8388
  }
8352
8389
  const blocking = questions.filter((q) => q.classification === "blocking");
8353
8390
  const important = questions.filter((q) => q.classification === "important");
8354
8391
  const deferred = questions.filter((q) => q.classification === "deferred");
8392
+ const blockingOpen = blocking.filter((q) => q.resolution_status === "open");
8393
+ const importantOpen = important.filter((q) => q.resolution_status === "open");
8394
+ const byStatus = (s) => questions.filter((q) => q.resolution_status === s);
8395
+ const resolved = byStatus("resolved");
8396
+ const assumed = byStatus("assumed");
8397
+ const deferredStatus = byStatus("deferred");
8355
8398
  let readiness;
8356
8399
  if (questions.length === 0) readiness = "unknown";
8357
- else if (blocking.length > 0) readiness = "needs_decisions";
8400
+ else if (blockingOpen.length > 0) readiness = "needs_decisions";
8358
8401
  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.";
8402
+ const suggested_assumptions = blockingOpen.map((q) => q.suggested_assumption).filter(Boolean);
8403
+ const recommended_next_step = readiness === "needs_decisions" ? "Confirm suggested assumptions with the user (resolve, assume or defer blocking open questions) before generating the roadmap." : readiness === "ready" ? "No blocking open questions \u2014 you can proceed to the roadmap. Surfaced assumptions/deferred items are informational." : "No open questions found. Run `kaddo bootstrap` to capture early questions, or proceed.";
8361
8404
  return {
8362
8405
  generated_at: now.toISOString(),
8363
8406
  project,
@@ -8366,12 +8409,23 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
8366
8409
  roadmap_readiness: readiness,
8367
8410
  blocking: blocking.length,
8368
8411
  important: important.length,
8369
- deferred: deferred.length
8412
+ deferred: deferred.length,
8413
+ blocking_open: blockingOpen.length,
8414
+ important_open: importantOpen.length,
8415
+ resolution: {
8416
+ open: byStatus("open").length,
8417
+ resolved: resolved.length,
8418
+ assumed: assumed.length,
8419
+ deferred: deferredStatus.length
8420
+ }
8370
8421
  },
8371
8422
  questions,
8372
8423
  blocking_questions: blocking,
8373
8424
  important_questions: important,
8374
8425
  deferred_questions: deferred,
8426
+ resolved_questions: resolved,
8427
+ assumed_questions: assumed,
8428
+ deferred_status_questions: deferredStatus,
8375
8429
  suggested_assumptions,
8376
8430
  recommended_next_step
8377
8431
  };
@@ -8385,18 +8439,18 @@ function renderOpenQuestionsMarkdown(r) {
8385
8439
  L.push("## Summary", "");
8386
8440
  L.push(`- Open questions found: ${r.summary.open_questions}`);
8387
8441
  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}`);
8442
+ L.push(`- By resolution \u2014 open: ${r.summary.resolution.open}, resolved: ${r.summary.resolution.resolved}, assumed: ${r.summary.resolution.assumed}, deferred: ${r.summary.resolution.deferred}`);
8443
+ L.push(`- Blocking open: ${r.summary.blocking_open}, important open: ${r.summary.important_open}`);
8391
8444
  L.push("");
8392
8445
  if (r.summary.open_questions === 0) {
8393
8446
  L.push("No `## Open Questions` sections found in business / product / codebase / roadmap.", "");
8394
8447
  L.push("## Recommended Next Step", "", r.recommended_next_step, "");
8395
8448
  return L.join("\n");
8396
8449
  }
8397
- L.push("## Blocking Questions", "");
8398
- if (r.blocking_questions.length === 0) L.push("_None._", "");
8399
- for (const q of r.blocking_questions) {
8450
+ const blockingOpen = r.blocking_questions.filter((q) => q.resolution_status === "open");
8451
+ L.push("## Blocking Open Questions", "");
8452
+ if (blockingOpen.length === 0) L.push("_None \u2014 nothing blocks readiness._", "");
8453
+ for (const q of blockingOpen) {
8400
8454
  L.push(`### ${q.id}`, "");
8401
8455
  L.push(`- Source: \`${q.source}\``);
8402
8456
  L.push(`- Question: ${q.question}`);
@@ -8404,13 +8458,18 @@ function renderOpenQuestionsMarkdown(r) {
8404
8458
  if (q.suggested_assumption) L.push(`- Suggested assumption: ${q.suggested_assumption}`);
8405
8459
  L.push("");
8406
8460
  }
8461
+ const renderStatusList = (title, items) => {
8462
+ L.push(`## ${title}`, "");
8463
+ if (items.length === 0) L.push("_None._");
8464
+ for (const q of items) L.push(`- ${q.question}${q.resolution_note ? ` \u2014 _${q.resolution_note}_` : ""}`);
8465
+ L.push("");
8466
+ };
8467
+ renderStatusList("Resolved", r.resolved_questions);
8468
+ renderStatusList("Assumed (decisions to revisit)", r.assumed_questions);
8469
+ renderStatusList("Deferred (out of current scope)", r.deferred_status_questions);
8407
8470
  L.push("## Important Questions", "");
8408
8471
  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}`);
8472
+ for (const q of r.important_questions) L.push(`- [${q.resolution_status}] ${q.question}`);
8414
8473
  L.push("");
8415
8474
  if (r.suggested_assumptions.length > 0) {
8416
8475
  L.push("## Suggested Assumptions", "");
@@ -8497,9 +8556,9 @@ function runUnderstand() {
8497
8556
  console.log(" Suggested agent: graph-agent (see .kaddo/graph-hints.md)");
8498
8557
  }
8499
8558
  const oq = buildOpenQuestionsReport(dir);
8500
- if (oq.summary.blocking > 0) {
8559
+ if (oq.summary.blocking_open > 0) {
8501
8560
  console.log("");
8502
- console.log(`Open questions: ${oq.summary.blocking} blocking decision(s) before the roadmap (roadmap readiness: ${oq.summary.roadmap_readiness}).`);
8561
+ console.log(`Open questions: ${oq.summary.blocking_open} blocking open decision(s) before the roadmap (roadmap readiness: ${oq.summary.roadmap_readiness}).`);
8503
8562
  console.log(" \u2192 Run `kaddo questions` to review them, then resolve, assume or defer before `kaddo create --from roadmap`.");
8504
8563
  }
8505
8564
  const active = activeWorkItems(dir);
@@ -12280,19 +12339,22 @@ function runQuestions(opts = {}) {
12280
12339
  console.log(serializeOpenQuestionsJson(report));
12281
12340
  return;
12282
12341
  }
12342
+ const s = report.summary;
12283
12343
  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}`);
12344
+ console.log(`Open questions detected: ${s.open_questions}`);
12345
+ console.log(`By resolution \u2014 open: ${s.resolution.open}, resolved: ${s.resolution.resolved}, assumed: ${s.resolution.assumed}, deferred: ${s.resolution.deferred}`);
12346
+ console.log(`Roadmap readiness: ${s.roadmap_readiness === "needs_decisions" ? "needs decisions" : s.roadmap_readiness} (blocking open: ${s.blocking_open}, important open: ${s.important_open})`);
12286
12347
  const list2 = (title, qs) => {
12287
12348
  if (qs.length === 0) return;
12288
12349
  console.log("");
12289
12350
  console.log(`${title}:`);
12290
- for (const q of qs.slice(0, 8)) console.log(`- ${q.question}`);
12351
+ for (const q of qs.slice(0, 8)) console.log(`- ${q.question}${q.resolution_note ? ` \u2014 ${q.resolution_note}` : ""}`);
12291
12352
  if (qs.length > 8) console.log(` \u2026and ${qs.length - 8} more`);
12292
12353
  };
12293
- list2("Blocking", report.blocking_questions);
12294
- list2("Important", report.important_questions);
12295
- list2("Deferred", report.deferred_questions);
12354
+ list2("Blocking (open)", report.blocking_questions.filter((q) => q.resolution_status === "open"));
12355
+ list2("Resolved", report.resolved_questions);
12356
+ list2("Assumed", report.assumed_questions);
12357
+ list2("Deferred", report.deferred_status_questions);
12296
12358
  console.log("");
12297
12359
  console.log("Suggested next:");
12298
12360
  console.log(report.recommended_next_step);
@@ -12444,9 +12506,9 @@ function renderAdapterMarkdown(ctx, target) {
12444
12506
  L.push("Read `knowledge/business/business.md`, `knowledge/product/product.md`,");
12445
12507
  L.push("`knowledge/tech/codebase.md`, and `.kaddo/reports/questions-report.md` if available.");
12446
12508
  L.push("");
12447
- L.push("Check open-questions readiness first. **If blocking open questions exist, ask the user to");
12448
- L.push("resolve, assume or defer them before generating the roadmap** \u2014 never build the roadmap on");
12449
- L.push("invisible assumptions.");
12509
+ L.push("Check open-questions readiness first. **If blocking questions with resolution_status = open");
12510
+ L.push("exist, ask the user to resolve, assume or defer them before generating the roadmap.** Assumed,");
12511
+ L.push("resolved or deferred questions should be surfaced for context, but should not block execution.");
12450
12512
  L.push("");
12451
12513
  L.push("## Before implementation", "");
12452
12514
  L.push("Read the target Work Item in `knowledge/delivery/work-items/`, `.kaddo/context-pack.md`,");
@@ -12568,8 +12630,9 @@ function renderKaddoBlock(ctx) {
12568
12630
  L.push("");
12569
12631
  for (const line of commandFallbackSection(ctx.packageManager, "### ")) L.push(line);
12570
12632
  L.push("### Before roadmap work", "");
12571
- L.push("Check open-questions readiness first. If blocking open questions exist, ask the user to");
12572
- L.push("resolve, assume or defer them before generating the roadmap.");
12633
+ L.push("Check open-questions readiness first. If blocking questions with resolution_status = open");
12634
+ L.push("exist, ask the user to resolve, assume or defer them. Assumed/resolved/deferred questions");
12635
+ L.push("should be surfaced, but should not block execution.");
12573
12636
  L.push("");
12574
12637
  L.push("### Before implementation", "");
12575
12638
  L.push("Read the target Work Item in `knowledge/delivery/work-items/`, `.kaddo/context-pack.md`,");
@@ -12610,21 +12673,92 @@ function injectKaddoBlock(existing, ctx) {
12610
12673
  ${sep}${block}
12611
12674
  `, status: "injected" };
12612
12675
  }
12676
+ var ADAPTERS = [
12677
+ { id: "codex", label: "Codex", file: "AGENTS.md", supportsInject: true },
12678
+ { id: "claude", label: "Claude Code", file: "CLAUDE.md", supportsInject: true },
12679
+ { id: "opencode", label: "OpenCode", file: "AGENTS.md", supportsInject: true },
12680
+ { id: "antigravity", label: "Antigravity", file: "AGENTS.md", supportsInject: true },
12681
+ { id: "kiro", label: "Kiro", file: "AGENTS.md", supportsInject: true }
12682
+ ];
12683
+ function findAdapter(id) {
12684
+ return ADAPTERS.find((a) => a.id === id);
12685
+ }
12686
+ function parseOriginAdapter(content) {
12687
+ const m = content.match(/Generated by `kaddo adapters install (\w+)`/);
12688
+ const id = m?.[1];
12689
+ return id && findAdapter(id) ? id : null;
12690
+ }
12691
+ function classifyAdapterState(content) {
12692
+ const base = detectAgentsState(content);
12693
+ switch (base) {
12694
+ case "missing":
12695
+ return "missing";
12696
+ case "invalid_kaddo_block":
12697
+ return "broken-markers";
12698
+ case "generated_by_kaddo":
12699
+ return "full-generated";
12700
+ case "existing_with_kaddo_block":
12701
+ return content.includes(LEGACY_BEGIN_MARKER) ? "legacy-injected" : "injected";
12702
+ default:
12703
+ return "team-owned";
12704
+ }
12705
+ }
12706
+ function recommendedAction(a, state) {
12707
+ const cmd = `kaddo adapters install ${a.id}`;
12708
+ switch (state) {
12709
+ case "missing":
12710
+ return cmd;
12711
+ case "team-owned":
12712
+ return `${cmd} --inject`;
12713
+ case "injected":
12714
+ return "No action needed (run --inject to update the Kaddo block).";
12715
+ case "legacy-injected":
12716
+ return `${cmd} --inject (migrates legacy markers to neutral)`;
12717
+ case "full-generated":
12718
+ return `No action needed. Use \`${cmd} --force\` only to regenerate for ${a.label}.`;
12719
+ case "broken-markers":
12720
+ return "Fix the incomplete Kaddo adapter markers before running --inject.";
12721
+ }
12722
+ }
12723
+ function buildAdapterStatuses(dir) {
12724
+ const cache = /* @__PURE__ */ new Map();
12725
+ const read = (file) => {
12726
+ if (!cache.has(file)) {
12727
+ const full = join(dir, file);
12728
+ cache.set(file, exists(full) ? readFile(full) : null);
12729
+ }
12730
+ return cache.get(file);
12731
+ };
12732
+ return ADAPTERS.map((a) => {
12733
+ const content = read(a.file);
12734
+ const state = classifyAdapterState(content);
12735
+ const originAdapter = content ? parseOriginAdapter(content) : null;
12736
+ return { ...a, state, originAdapter, recommendedAction: recommendedAction(a, state) };
12737
+ });
12738
+ }
12739
+ function buildSharedFileStatuses(statuses) {
12740
+ const byFile = /* @__PURE__ */ new Map();
12741
+ for (const s of statuses) {
12742
+ const arr = byFile.get(s.file) ?? [];
12743
+ arr.push(s);
12744
+ byFile.set(s.file, arr);
12745
+ }
12746
+ return [...byFile.entries()].filter(([, arr]) => arr.length > 1).map(([file, arr]) => ({
12747
+ file,
12748
+ adapters: arr.map((s) => s.id),
12749
+ state: arr[0].state,
12750
+ originAdapter: arr[0].originAdapter
12751
+ }));
12752
+ }
12613
12753
 
12614
12754
  // src/commands/adapters.ts
12615
- var TARGETS2 = {
12616
- codex: { target: "codex", file: "AGENTS.md", label: "Codex", supportsInject: true },
12617
- claude: { target: "claude", file: "CLAUDE.md", label: "Claude Code", supportsInject: true },
12618
- opencode: { target: "opencode", file: "AGENTS.md", label: "OpenCode", supportsInject: true },
12619
- antigravity: { target: "antigravity", file: "AGENTS.md", label: "Antigravity", supportsInject: true },
12620
- kiro: { target: "kiro", file: "AGENTS.md", label: "Kiro", supportsInject: true }
12621
- };
12755
+ var ADAPTER_LIST = ADAPTERS.map((a) => a.id).join(", ");
12622
12756
  function runAdaptersInstall(adapter, opts = {}) {
12623
12757
  const dir = cwd();
12624
12758
  requireConfig(dir);
12625
- const spec = TARGETS2[adapter];
12759
+ const spec = findAdapter(adapter);
12626
12760
  if (!spec) {
12627
- console.error(`Unknown adapter: "${adapter}". Available: ${Object.keys(TARGETS2).join(", ")}.`);
12761
+ console.error(`Unknown adapter: "${adapter}". Available: ${ADAPTER_LIST}.`);
12628
12762
  process.exit(1);
12629
12763
  return;
12630
12764
  }
@@ -12653,7 +12787,7 @@ function runAdaptersInstall(adapter, opts = {}) {
12653
12787
  return;
12654
12788
  }
12655
12789
  if (existing === null) {
12656
- const content2 = renderAdapterMarkdown(ctx, spec.target);
12790
+ const content2 = renderAdapterMarkdown(ctx, spec.id);
12657
12791
  if (opts.dryRun) {
12658
12792
  console.log(`# ${rel} preview`, "");
12659
12793
  console.log(content2);
@@ -12684,7 +12818,7 @@ function runAdaptersInstall(adapter, opts = {}) {
12684
12818
  outro2(`${rel} ready.`);
12685
12819
  return;
12686
12820
  }
12687
- const content = renderAdapterMarkdown(ctx, spec.target);
12821
+ const content = renderAdapterMarkdown(ctx, spec.id);
12688
12822
  if (opts.dryRun) {
12689
12823
  console.log(`# ${rel} preview`, "");
12690
12824
  console.log(content);
@@ -12704,6 +12838,58 @@ function runAdaptersInstall(adapter, opts = {}) {
12704
12838
  printCommandFooter("adapters install codex");
12705
12839
  outro2(`${rel} ready.`);
12706
12840
  }
12841
+ function runAdaptersList(opts = {}) {
12842
+ if (opts.json) {
12843
+ console.log(JSON.stringify({ adapters: ADAPTERS.map((a) => ({ id: a.id, label: a.label, file: a.file, supports_inject: a.supportsInject })) }, null, 2));
12844
+ return;
12845
+ }
12846
+ const pad = Math.max(...ADAPTERS.map((a) => a.id.length));
12847
+ console.log("Available adapters:\n");
12848
+ for (const a of ADAPTERS) {
12849
+ console.log(` ${a.id.padEnd(pad)} ${a.file.padEnd(10)} ${a.supportsInject ? "Supports --inject" : ""}`.trimEnd());
12850
+ }
12851
+ console.log("\nInstall one with:\n kaddo adapters install <adapter>");
12852
+ console.log("\nPreview with:\n kaddo adapters install <adapter> --dry-run");
12853
+ }
12854
+ function runAdaptersStatus(opts = {}) {
12855
+ const dir = cwd();
12856
+ requireConfig(dir);
12857
+ const statuses = buildAdapterStatuses(dir);
12858
+ if (opts.json) {
12859
+ console.log(JSON.stringify({
12860
+ adapters: statuses.map((s) => ({
12861
+ id: s.id,
12862
+ label: s.label,
12863
+ file: s.file,
12864
+ state: s.state,
12865
+ origin_adapter: s.originAdapter,
12866
+ supports_inject: s.supportsInject,
12867
+ recommended_action: s.recommendedAction
12868
+ })),
12869
+ shared_files: buildSharedFileStatuses(statuses).map((f) => ({
12870
+ file: f.file,
12871
+ adapters: f.adapters,
12872
+ state: f.state,
12873
+ origin_adapter: f.originAdapter
12874
+ }))
12875
+ }, null, 2));
12876
+ return;
12877
+ }
12878
+ const idPad = Math.max(...statuses.map((s) => s.id.length));
12879
+ console.log("Adapter status:\n");
12880
+ for (const s of statuses) {
12881
+ const origin = s.originAdapter && s.originAdapter !== s.id ? ` by ${s.originAdapter}` : "";
12882
+ console.log(` ${s.id.padEnd(idPad)} ${s.file.padEnd(10)} ${s.state}${origin}`);
12883
+ }
12884
+ const actionable = statuses.filter((s) => s.state !== "injected" && s.state !== "full-generated");
12885
+ if (actionable.length > 0) {
12886
+ console.log("\nRecommended actions:\n");
12887
+ for (const s of actionable) console.log(` ${s.id}:
12888
+ ${s.recommendedAction}`);
12889
+ } else {
12890
+ console.log("\nAll adapters are installed or up to date.");
12891
+ }
12892
+ }
12707
12893
 
12708
12894
  // src/index.ts
12709
12895
  var require2 = createRequire(import.meta.url);
@@ -12762,6 +12948,12 @@ var adaptersCmd = program.command("adapters").description("Generate adapters tha
12762
12948
  adaptersCmd.command("install <adapter>").description("Generate an adapter file (codex/opencode/antigravity/kiro \u2192 AGENTS.md, claude \u2192 CLAUDE.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) => {
12763
12949
  runAdaptersInstall(adapter, opts);
12764
12950
  });
12951
+ adaptersCmd.command("list").alias("ls").description("List the supported adapters and their target files").option("--json", "Output JSON").action((opts) => {
12952
+ runAdaptersList(opts);
12953
+ });
12954
+ adaptersCmd.command("status").alias("check").description("Show the install state of each adapter in this project (read-only)").option("--json", "Output JSON").action((opts) => {
12955
+ runAdaptersStatus(opts);
12956
+ });
12765
12957
  program.command("export <adapter>").description("Alias for `kaddo adapters install <adapter>` (codex/opencode/antigravity/kiro \u2192 AGENTS.md, claude \u2192 CLAUDE.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) => {
12766
12958
  runAdaptersInstall(adapter, opts);
12767
12959
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.31.0",
3
+ "version": "3.33.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {