@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.
- package/README.md +1 -0
- package/dist/index.js +108 -45
- 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
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
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
|
|
2739
|
-
and propose assumptions for the user to confirm before refining \u2014 don't bake in
|
|
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
|
|
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
|
|
3365
|
-
authentication or the Work Item's scope.
|
|
3366
|
-
|
|
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
|
|
8304
|
-
if (
|
|
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
|
|
8373
|
+
for (const eq of extractFromMarkdown(md)) {
|
|
8339
8374
|
seq += 1;
|
|
8340
|
-
const { classification, reason } = classifyQuestion(
|
|
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:
|
|
8380
|
+
question: eq.text,
|
|
8346
8381
|
classification,
|
|
8382
|
+
resolution_status: eq.resolution_status,
|
|
8347
8383
|
reason,
|
|
8348
|
-
...
|
|
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 (
|
|
8400
|
+
else if (blockingOpen.length > 0) readiness = "needs_decisions";
|
|
8358
8401
|
else readiness = "ready";
|
|
8359
|
-
const suggested_assumptions =
|
|
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
|
|
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(`-
|
|
8389
|
-
L.push(`-
|
|
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
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
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.
|
|
8559
|
+
if (oq.summary.blocking_open > 0) {
|
|
8501
8560
|
console.log("");
|
|
8502
|
-
console.log(`Open questions: ${oq.summary.
|
|
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: ${
|
|
12285
|
-
console.log(`
|
|
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("
|
|
12295
|
-
list2("
|
|
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
|
|
12448
|
-
L.push("resolve, assume or defer them before generating the roadmap
|
|
12449
|
-
L.push("
|
|
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
|
|
12572
|
-
L.push("resolve, assume or defer them
|
|
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`,");
|