@kaddo/cli 3.32.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 +1 -0
  2. package/dist/index.js +108 -45
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -528,6 +528,7 @@ create --from roadmap → owners → guard → explain`.
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
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 |
531
532
 
532
533
  **Optional modules (installed with `kaddo add`):**
533
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`,");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.32.0",
3
+ "version": "3.33.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {