@kaddo/cli 3.44.0 → 3.45.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 +264 -96
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -543,6 +543,7 @@ create --from roadmap → owners → guard → explain`.
|
|
|
543
543
|
| v3.42 | Agent & skill version metadata: installed agents/skills carry a `version:`; `kaddo agents status` / `kaddo skills status` classify up-to-date/outdated/unknown-version/modified/missing; `agents update` / `skills update` refresh outdated safely (never overwrite edits without `--force`); MCP `kaddo://installed-assets` |
|
|
544
544
|
| v3.43 | Capability-grounded roadmap: each `RM-xxx` candidate is graded on related domain / capability / source signals; `roadmap_quality` surfaced in `explain`/`context`/`understand`; `create --from roadmap` preserves `source_roadmap_candidate` + related metadata into the Work Item; roadmap-agent emits grounded fields (never materializes Work Items); MCP `kaddo://roadmap-quality` |
|
|
545
545
|
| v3.44 | Roadmap counting alignment + materialization quality: `explain`/`context` separate **Roadmap initiatives** from **Work Item candidates** (`## Roadmap Status`); two-level `roadmapQuality` (initiatives + work_item_candidates); `create --from roadmap` normalizes metadata — fills `domains` from `related_domain`, splits comma-joined `related_capabilities` into a real list, carries `source_roadmap_initiative`/`source_work_item_candidate`/`source_signals`/`decision_candidates`, improved Source + Context-From-Roadmap body + ADR warning; MCP `kaddo://work-item-candidates` |
|
|
546
|
+
| v3.45 | State-aware next step: `resolveNextStep` decides from the real delivery state (draft/ready/in-progress, ownership, ADRs, adapters) instead of always suggesting `create --from roadmap` — draft → work-item-agent, ready → adapter/implementation-agent, in-progress → guard; parallel **secondary** recommendations (ownership, ADRs, remaining candidates); `deliveryState` + recommendation in `explain`/`context`; MCP `kaddo://next-step` |
|
|
546
547
|
|
|
547
548
|
**Optional modules (installed with `kaddo add`):**
|
|
548
549
|
|
package/dist/index.js
CHANGED
|
@@ -8113,7 +8113,124 @@ function buildSharedFileStatuses(statuses) {
|
|
|
8113
8113
|
}));
|
|
8114
8114
|
}
|
|
8115
8115
|
|
|
8116
|
+
// src/core/decisions.ts
|
|
8117
|
+
var CANDIDATES_DISCOVERY = "knowledge/tech/discovery/decision-candidates.md";
|
|
8118
|
+
var CANDIDATES_LEGACY = "knowledge/tech/decision-candidates.md";
|
|
8119
|
+
var DECISIONS_DIR = "knowledge/tech/decisions";
|
|
8120
|
+
function resolveCandidatesPath(dir) {
|
|
8121
|
+
const discovery = exists(join(dir, CANDIDATES_DISCOVERY));
|
|
8122
|
+
const legacy = exists(join(dir, CANDIDATES_LEGACY));
|
|
8123
|
+
if (discovery) return { path: CANDIDATES_DISCOVERY, legacy: false, bothExist: legacy };
|
|
8124
|
+
if (legacy) return { path: CANDIDATES_LEGACY, legacy: true, bothExist: false };
|
|
8125
|
+
return { path: null, legacy: false, bothExist: false };
|
|
8126
|
+
}
|
|
8127
|
+
function cleanCandidateTitle(title) {
|
|
8128
|
+
return title.replace(/^\s*#{1,6}\s+/, "").replace(/^\s*[-*]\s+/, "").replace(/^\s*\(?\d+\)?[.):]\s+/, "").trim();
|
|
8129
|
+
}
|
|
8130
|
+
function slugify2(s) {
|
|
8131
|
+
return cleanCandidateTitle(s).toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 70).replace(/-+$/g, "");
|
|
8132
|
+
}
|
|
8133
|
+
function parseDecisionCandidates(md) {
|
|
8134
|
+
const out = [];
|
|
8135
|
+
for (const line of md.split(/\r?\n/)) {
|
|
8136
|
+
const m = line.match(/^##\s+(.+?)\s*$/);
|
|
8137
|
+
if (m) {
|
|
8138
|
+
const raw = m[1].trim();
|
|
8139
|
+
if (!raw || /^_.*_$/.test(raw)) continue;
|
|
8140
|
+
const t = cleanCandidateTitle(raw);
|
|
8141
|
+
if (t) out.push(t);
|
|
8142
|
+
}
|
|
8143
|
+
}
|
|
8144
|
+
return out;
|
|
8145
|
+
}
|
|
8146
|
+
function countAdrs(dir) {
|
|
8147
|
+
const base = join(dir, DECISIONS_DIR);
|
|
8148
|
+
if (!exists(base)) return { total: 0, draft: 0, accepted: 0 };
|
|
8149
|
+
let total = 0;
|
|
8150
|
+
let draft = 0;
|
|
8151
|
+
let accepted = 0;
|
|
8152
|
+
for (const entry of readDir(base)) {
|
|
8153
|
+
if (!entry.endsWith(".md") || entry === ".gitkeep") continue;
|
|
8154
|
+
const full = join(base, entry);
|
|
8155
|
+
if (!isFile(full)) continue;
|
|
8156
|
+
total += 1;
|
|
8157
|
+
let content = "";
|
|
8158
|
+
try {
|
|
8159
|
+
content = readFile(full);
|
|
8160
|
+
} catch {
|
|
8161
|
+
continue;
|
|
8162
|
+
}
|
|
8163
|
+
const status = content.match(/^\s*status:\s*([a-z-]+)/im)?.[1]?.toLowerCase();
|
|
8164
|
+
if (status === "accepted") accepted += 1;
|
|
8165
|
+
else draft += 1;
|
|
8166
|
+
}
|
|
8167
|
+
return { total, draft, accepted };
|
|
8168
|
+
}
|
|
8169
|
+
function buildTechDecisions(dir) {
|
|
8170
|
+
const resolved = resolveCandidatesPath(dir);
|
|
8171
|
+
let titles = [];
|
|
8172
|
+
if (resolved.path) {
|
|
8173
|
+
try {
|
|
8174
|
+
titles = parseDecisionCandidates(readFile(join(dir, resolved.path)));
|
|
8175
|
+
} catch {
|
|
8176
|
+
titles = [];
|
|
8177
|
+
}
|
|
8178
|
+
}
|
|
8179
|
+
const { total, draft, accepted } = countAdrs(dir);
|
|
8180
|
+
const candidate_list = titles.map((title, i) => {
|
|
8181
|
+
const n = String(total + i + 1).padStart(3, "0");
|
|
8182
|
+
return { title, source: resolved.path, suggestedAdrFile: `${DECISIONS_DIR}/ADR-${n}-${slugify2(title)}.md` };
|
|
8183
|
+
});
|
|
8184
|
+
let status;
|
|
8185
|
+
if (accepted > 0) status = "accepted-adrs";
|
|
8186
|
+
else if (total > 0) status = "draft-adrs";
|
|
8187
|
+
else if (titles.length > 0) status = "candidates";
|
|
8188
|
+
else status = "none";
|
|
8189
|
+
return {
|
|
8190
|
+
status,
|
|
8191
|
+
candidates: titles.length,
|
|
8192
|
+
adrs: total,
|
|
8193
|
+
draft_adrs: draft,
|
|
8194
|
+
accepted_adrs: accepted,
|
|
8195
|
+
candidate_list,
|
|
8196
|
+
candidates_source: resolved.path,
|
|
8197
|
+
candidates_legacy_location: resolved.legacy,
|
|
8198
|
+
candidates_both_exist: resolved.bothExist
|
|
8199
|
+
};
|
|
8200
|
+
}
|
|
8201
|
+
|
|
8116
8202
|
// src/core/next-step.ts
|
|
8203
|
+
function buildDeliveryState(dir) {
|
|
8204
|
+
const wis = discoverWorkItems(dir);
|
|
8205
|
+
const byState = (s) => wis.filter((w) => w.lifecycle === s).length;
|
|
8206
|
+
const total = wis.length;
|
|
8207
|
+
const withOwnership = wis.filter((w) => w.codeGlobs.length > 0).length;
|
|
8208
|
+
const td = buildTechDecisions(dir);
|
|
8209
|
+
const roadmapPath = join(dir, "knowledge/delivery/roadmap.md");
|
|
8210
|
+
const roadmapMd = exists(roadmapPath) ? safeRead(roadmapPath) : null;
|
|
8211
|
+
const stats = roadmapStats(roadmapMd, total);
|
|
8212
|
+
const adapters = installedAdapters(dir);
|
|
8213
|
+
return {
|
|
8214
|
+
phase: "",
|
|
8215
|
+
draft_work_items: byState("draft"),
|
|
8216
|
+
ready_work_items: byState("ready"),
|
|
8217
|
+
in_progress_work_items: byState("in-progress"),
|
|
8218
|
+
blocked_work_items: byState("blocked"),
|
|
8219
|
+
total_work_items: total,
|
|
8220
|
+
ownership_coverage: `${withOwnership}/${total}`,
|
|
8221
|
+
remaining_work_item_candidates: stats.remaining_work_item_candidates,
|
|
8222
|
+
decision_candidates: td.candidates,
|
|
8223
|
+
accepted_adrs: td.accepted_adrs,
|
|
8224
|
+
adapters_installed: adapters.length
|
|
8225
|
+
};
|
|
8226
|
+
}
|
|
8227
|
+
function safeRead(p2) {
|
|
8228
|
+
try {
|
|
8229
|
+
return readFile(p2);
|
|
8230
|
+
} catch {
|
|
8231
|
+
return null;
|
|
8232
|
+
}
|
|
8233
|
+
}
|
|
8117
8234
|
function roadmapSignal(dir) {
|
|
8118
8235
|
const p2 = join(dir, "knowledge/delivery/roadmap.md");
|
|
8119
8236
|
if (!exists(p2)) return "missing";
|
|
@@ -8210,15 +8327,117 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
8210
8327
|
if (roadmap !== "has-candidates") {
|
|
8211
8328
|
return { id: "roadmap", phase: "Planning", label: "Use roadmap-agent to define roadmap candidates (`kaddo roadmap`).", command: "kaddo roadmap", agent: "roadmap-agent", target: "knowledge/delivery/roadmap.md", reason: "The roadmap has no candidates yet." };
|
|
8212
8329
|
}
|
|
8213
|
-
const
|
|
8214
|
-
|
|
8215
|
-
|
|
8330
|
+
const st = buildDeliveryState(dir);
|
|
8331
|
+
const secondary = buildSecondaryRecommendations(st);
|
|
8332
|
+
if (st.total_work_items === 0) {
|
|
8333
|
+
return {
|
|
8334
|
+
id: "create-work-item",
|
|
8335
|
+
phase: "Delivery Preparation",
|
|
8336
|
+
label: "Run `kaddo create --from roadmap` to materialize the first Work Item.",
|
|
8337
|
+
command: "kaddo create --from roadmap",
|
|
8338
|
+
reason: "The roadmap has candidates but no Work Item exists yet.",
|
|
8339
|
+
...secondary.length ? { secondary } : {}
|
|
8340
|
+
};
|
|
8341
|
+
}
|
|
8342
|
+
const adapters = st.adapters_installed;
|
|
8343
|
+
if (st.ready_work_items > 0) {
|
|
8344
|
+
if (adapters === 0) {
|
|
8345
|
+
return {
|
|
8346
|
+
id: "install-adapter",
|
|
8347
|
+
phase: "Active Delivery",
|
|
8348
|
+
label: "Install or configure an adapter before implementation (`kaddo adapters list`).",
|
|
8349
|
+
command: "kaddo adapters list",
|
|
8350
|
+
reason: `${st.ready_work_items} Work Item(s) are ready but no adapter is installed.`,
|
|
8351
|
+
...secondary.length ? { secondary } : {}
|
|
8352
|
+
};
|
|
8353
|
+
}
|
|
8354
|
+
return {
|
|
8355
|
+
id: "implement",
|
|
8356
|
+
phase: "Active Delivery",
|
|
8357
|
+
label: "Use the implementation-agent or your installed adapter to plan implementation.",
|
|
8358
|
+
agent: "implementation-agent",
|
|
8359
|
+
reason: `${st.ready_work_items} Work Item(s) are ready and an adapter is installed.`,
|
|
8360
|
+
...secondary.length ? { secondary } : {}
|
|
8361
|
+
};
|
|
8216
8362
|
}
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8363
|
+
if (st.in_progress_work_items > 0) {
|
|
8364
|
+
return {
|
|
8365
|
+
id: "guard",
|
|
8366
|
+
phase: "Active Delivery",
|
|
8367
|
+
label: "Run `kaddo guard` and update affected knowledge after significant changes.",
|
|
8368
|
+
command: "kaddo guard",
|
|
8369
|
+
reason: `${st.in_progress_work_items} Work Item(s) are in progress.`,
|
|
8370
|
+
...secondary.length ? { secondary } : {}
|
|
8371
|
+
};
|
|
8220
8372
|
}
|
|
8221
|
-
|
|
8373
|
+
if (st.draft_work_items > 0) {
|
|
8374
|
+
return {
|
|
8375
|
+
id: "refine-work-item",
|
|
8376
|
+
phase: "Active Delivery",
|
|
8377
|
+
label: "Refine the existing draft Work Item with the work-item-agent.",
|
|
8378
|
+
agent: "work-item-agent",
|
|
8379
|
+
skill: "work-item-refinement",
|
|
8380
|
+
reason: `There ${st.draft_work_items === 1 ? "is" : "are"} ${st.draft_work_items} draft Work Item${st.draft_work_items === 1 ? "" : "s"} and no Work Item is ready.`,
|
|
8381
|
+
...secondary.length ? { secondary } : {}
|
|
8382
|
+
};
|
|
8383
|
+
}
|
|
8384
|
+
if (st.blocked_work_items > 0) {
|
|
8385
|
+
return {
|
|
8386
|
+
id: "resolve-blocker",
|
|
8387
|
+
phase: "Active Delivery",
|
|
8388
|
+
label: "Resolve the blocker on the blocked Work Item with the work-item-agent.",
|
|
8389
|
+
agent: "work-item-agent",
|
|
8390
|
+
reason: `${st.blocked_work_items} Work Item(s) are blocked.`,
|
|
8391
|
+
...secondary.length ? { secondary } : {}
|
|
8392
|
+
};
|
|
8393
|
+
}
|
|
8394
|
+
if (st.remaining_work_item_candidates > 0) {
|
|
8395
|
+
return {
|
|
8396
|
+
id: "materialize-more-work-items",
|
|
8397
|
+
phase: "Maintenance",
|
|
8398
|
+
label: `Materialize the remaining ${st.remaining_work_item_candidates} Work Item candidate(s) with \`kaddo create --from roadmap\`.`,
|
|
8399
|
+
command: "kaddo create --from roadmap",
|
|
8400
|
+
reason: "No active Work Items remain; roadmap candidates are still pending.",
|
|
8401
|
+
...secondary.length ? { secondary } : {}
|
|
8402
|
+
};
|
|
8403
|
+
}
|
|
8404
|
+
return {
|
|
8405
|
+
id: "plan-next",
|
|
8406
|
+
phase: "Maintenance",
|
|
8407
|
+
label: "Use the roadmap-agent to plan the next initiative.",
|
|
8408
|
+
agent: "roadmap-agent",
|
|
8409
|
+
reason: "No active Work Items and no remaining roadmap candidates."
|
|
8410
|
+
};
|
|
8411
|
+
}
|
|
8412
|
+
function buildSecondaryRecommendations(st) {
|
|
8413
|
+
const out = [];
|
|
8414
|
+
const [withOwnership] = st.ownership_coverage.split("/").map(Number);
|
|
8415
|
+
if (st.total_work_items > 0 && withOwnership < st.total_work_items) {
|
|
8416
|
+
out.push({
|
|
8417
|
+
id: "suggest-ownership",
|
|
8418
|
+
label: "Run `kaddo owners suggest` for Work Items without code ownership.",
|
|
8419
|
+
command: "kaddo owners suggest",
|
|
8420
|
+
reason: `Ownership coverage is ${st.ownership_coverage}.`
|
|
8421
|
+
});
|
|
8422
|
+
}
|
|
8423
|
+
if (st.total_work_items > 0 && st.decision_candidates > 0 && st.accepted_adrs === 0) {
|
|
8424
|
+
out.push({
|
|
8425
|
+
id: "materialize-adrs",
|
|
8426
|
+
label: "Use the adr-writing skill (`kaddo adr`) to materialize decision candidates into ADRs before implementing related technical Work Items.",
|
|
8427
|
+
command: "kaddo adr",
|
|
8428
|
+
skill: "adr-writing",
|
|
8429
|
+
reason: `There are ${st.decision_candidates} technical decision candidate(s) and ${st.accepted_adrs} accepted ADR(s).`
|
|
8430
|
+
});
|
|
8431
|
+
}
|
|
8432
|
+
if (st.total_work_items > 0 && st.remaining_work_item_candidates > 0) {
|
|
8433
|
+
out.push({
|
|
8434
|
+
id: "materialize-more-work-items",
|
|
8435
|
+
label: `Later, materialize the remaining ${st.remaining_work_item_candidates} Work Item candidate(s) with \`kaddo create --from roadmap\`.`,
|
|
8436
|
+
command: "kaddo create --from roadmap",
|
|
8437
|
+
reason: `There are ${st.remaining_work_item_candidates} remaining Work Item candidate(s).`
|
|
8438
|
+
});
|
|
8439
|
+
}
|
|
8440
|
+
return out;
|
|
8222
8441
|
}
|
|
8223
8442
|
|
|
8224
8443
|
// src/core/readiness.ts
|
|
@@ -8313,92 +8532,6 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
8313
8532
|
};
|
|
8314
8533
|
}
|
|
8315
8534
|
|
|
8316
|
-
// src/core/decisions.ts
|
|
8317
|
-
var CANDIDATES_DISCOVERY = "knowledge/tech/discovery/decision-candidates.md";
|
|
8318
|
-
var CANDIDATES_LEGACY = "knowledge/tech/decision-candidates.md";
|
|
8319
|
-
var DECISIONS_DIR = "knowledge/tech/decisions";
|
|
8320
|
-
function resolveCandidatesPath(dir) {
|
|
8321
|
-
const discovery = exists(join(dir, CANDIDATES_DISCOVERY));
|
|
8322
|
-
const legacy = exists(join(dir, CANDIDATES_LEGACY));
|
|
8323
|
-
if (discovery) return { path: CANDIDATES_DISCOVERY, legacy: false, bothExist: legacy };
|
|
8324
|
-
if (legacy) return { path: CANDIDATES_LEGACY, legacy: true, bothExist: false };
|
|
8325
|
-
return { path: null, legacy: false, bothExist: false };
|
|
8326
|
-
}
|
|
8327
|
-
function cleanCandidateTitle(title) {
|
|
8328
|
-
return title.replace(/^\s*#{1,6}\s+/, "").replace(/^\s*[-*]\s+/, "").replace(/^\s*\(?\d+\)?[.):]\s+/, "").trim();
|
|
8329
|
-
}
|
|
8330
|
-
function slugify2(s) {
|
|
8331
|
-
return cleanCandidateTitle(s).toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 70).replace(/-+$/g, "");
|
|
8332
|
-
}
|
|
8333
|
-
function parseDecisionCandidates(md) {
|
|
8334
|
-
const out = [];
|
|
8335
|
-
for (const line of md.split(/\r?\n/)) {
|
|
8336
|
-
const m = line.match(/^##\s+(.+?)\s*$/);
|
|
8337
|
-
if (m) {
|
|
8338
|
-
const raw = m[1].trim();
|
|
8339
|
-
if (!raw || /^_.*_$/.test(raw)) continue;
|
|
8340
|
-
const t = cleanCandidateTitle(raw);
|
|
8341
|
-
if (t) out.push(t);
|
|
8342
|
-
}
|
|
8343
|
-
}
|
|
8344
|
-
return out;
|
|
8345
|
-
}
|
|
8346
|
-
function countAdrs(dir) {
|
|
8347
|
-
const base = join(dir, DECISIONS_DIR);
|
|
8348
|
-
if (!exists(base)) return { total: 0, draft: 0, accepted: 0 };
|
|
8349
|
-
let total = 0;
|
|
8350
|
-
let draft = 0;
|
|
8351
|
-
let accepted = 0;
|
|
8352
|
-
for (const entry of readDir(base)) {
|
|
8353
|
-
if (!entry.endsWith(".md") || entry === ".gitkeep") continue;
|
|
8354
|
-
const full = join(base, entry);
|
|
8355
|
-
if (!isFile(full)) continue;
|
|
8356
|
-
total += 1;
|
|
8357
|
-
let content = "";
|
|
8358
|
-
try {
|
|
8359
|
-
content = readFile(full);
|
|
8360
|
-
} catch {
|
|
8361
|
-
continue;
|
|
8362
|
-
}
|
|
8363
|
-
const status = content.match(/^\s*status:\s*([a-z-]+)/im)?.[1]?.toLowerCase();
|
|
8364
|
-
if (status === "accepted") accepted += 1;
|
|
8365
|
-
else draft += 1;
|
|
8366
|
-
}
|
|
8367
|
-
return { total, draft, accepted };
|
|
8368
|
-
}
|
|
8369
|
-
function buildTechDecisions(dir) {
|
|
8370
|
-
const resolved = resolveCandidatesPath(dir);
|
|
8371
|
-
let titles = [];
|
|
8372
|
-
if (resolved.path) {
|
|
8373
|
-
try {
|
|
8374
|
-
titles = parseDecisionCandidates(readFile(join(dir, resolved.path)));
|
|
8375
|
-
} catch {
|
|
8376
|
-
titles = [];
|
|
8377
|
-
}
|
|
8378
|
-
}
|
|
8379
|
-
const { total, draft, accepted } = countAdrs(dir);
|
|
8380
|
-
const candidate_list = titles.map((title, i) => {
|
|
8381
|
-
const n = String(total + i + 1).padStart(3, "0");
|
|
8382
|
-
return { title, source: resolved.path, suggestedAdrFile: `${DECISIONS_DIR}/ADR-${n}-${slugify2(title)}.md` };
|
|
8383
|
-
});
|
|
8384
|
-
let status;
|
|
8385
|
-
if (accepted > 0) status = "accepted-adrs";
|
|
8386
|
-
else if (total > 0) status = "draft-adrs";
|
|
8387
|
-
else if (titles.length > 0) status = "candidates";
|
|
8388
|
-
else status = "none";
|
|
8389
|
-
return {
|
|
8390
|
-
status,
|
|
8391
|
-
candidates: titles.length,
|
|
8392
|
-
adrs: total,
|
|
8393
|
-
draft_adrs: draft,
|
|
8394
|
-
accepted_adrs: accepted,
|
|
8395
|
-
candidate_list,
|
|
8396
|
-
candidates_source: resolved.path,
|
|
8397
|
-
candidates_legacy_location: resolved.legacy,
|
|
8398
|
-
candidates_both_exist: resolved.bothExist
|
|
8399
|
-
};
|
|
8400
|
-
}
|
|
8401
|
-
|
|
8402
8535
|
// src/core/assets.ts
|
|
8403
8536
|
import matter4 from "gray-matter";
|
|
8404
8537
|
function canonicalAgents() {
|
|
@@ -8956,9 +9089,12 @@ function renderExplanationHuman(exp) {
|
|
|
8956
9089
|
}
|
|
8957
9090
|
lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
|
|
8958
9091
|
lines.push("");
|
|
8959
|
-
|
|
9092
|
+
const rec = exp.nextStepRecommendation;
|
|
9093
|
+
const secondary = rec.secondary ?? [];
|
|
9094
|
+
const steps = secondary.length > 0 || /Delivery|Active|Maintenance/.test(rec.phase) ? [rec.label, ...secondary.map((s2) => s2.label)] : exp.suggestedNextSteps;
|
|
9095
|
+
if (steps.length > 0) {
|
|
8960
9096
|
lines.push("## Suggested Next Steps");
|
|
8961
|
-
|
|
9097
|
+
steps.forEach((s2, i) => lines.push(`${i + 1}. ${s2}`));
|
|
8962
9098
|
lines.push("");
|
|
8963
9099
|
}
|
|
8964
9100
|
const r = exp.readiness;
|
|
@@ -9431,6 +9567,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
9431
9567
|
nextStep: nextStepRecommendation.label,
|
|
9432
9568
|
recommendedAgents: nextStepRecommendation.agent ? [nextStepRecommendation.agent] : phase.recommendedAgents
|
|
9433
9569
|
};
|
|
9570
|
+
const deliveryState = { ...buildDeliveryState(dir), phase: nextStepRecommendation.phase };
|
|
9434
9571
|
return {
|
|
9435
9572
|
version: CONTEXT_PACK_VERSION,
|
|
9436
9573
|
generatedAt: now.toISOString(),
|
|
@@ -9463,6 +9600,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
9463
9600
|
roadmap,
|
|
9464
9601
|
phase: unifiedPhase,
|
|
9465
9602
|
nextStepRecommendation,
|
|
9603
|
+
deliveryState,
|
|
9466
9604
|
techDecisions,
|
|
9467
9605
|
techKnowledge,
|
|
9468
9606
|
roadmapQuality: buildRoadmapQuality(dir),
|
|
@@ -9527,6 +9665,31 @@ function renderContextPack(pack) {
|
|
|
9527
9665
|
parts.push(`Next step: ${pack.phase.nextStep}
|
|
9528
9666
|
`);
|
|
9529
9667
|
}
|
|
9668
|
+
const ds = pack.deliveryState;
|
|
9669
|
+
const rec = pack.nextStepRecommendation;
|
|
9670
|
+
if (ds.total_work_items > 0 || rec.phase !== "Setup") {
|
|
9671
|
+
parts.push("## Delivery State\n");
|
|
9672
|
+
parts.push(
|
|
9673
|
+
[
|
|
9674
|
+
`- Phase: ${ds.phase}`,
|
|
9675
|
+
`- Draft Work Items: ${ds.draft_work_items}`,
|
|
9676
|
+
`- Ready Work Items: ${ds.ready_work_items}`,
|
|
9677
|
+
`- In-progress Work Items: ${ds.in_progress_work_items}`,
|
|
9678
|
+
`- Ownership coverage: ${ds.ownership_coverage}`,
|
|
9679
|
+
`- Remaining Work Item candidates: ${ds.remaining_work_item_candidates}`
|
|
9680
|
+
].join("\n") + "\n"
|
|
9681
|
+
);
|
|
9682
|
+
parts.push("## Next Step Recommendation\n");
|
|
9683
|
+
const recLines = [`- ${rec.label}`, ` - id: ${rec.id}`, ` - reason: ${rec.reason}`];
|
|
9684
|
+
if (rec.agent) recLines.push(` - agent: ${rec.agent}`);
|
|
9685
|
+
if (rec.skill) recLines.push(` - skill: ${rec.skill}`);
|
|
9686
|
+
if (rec.command) recLines.push(` - command: \`${rec.command}\``);
|
|
9687
|
+
parts.push(recLines.join("\n") + "\n");
|
|
9688
|
+
if (rec.secondary && rec.secondary.length > 0) {
|
|
9689
|
+
parts.push("Also (secondary):\n");
|
|
9690
|
+
parts.push(rec.secondary.map((s) => `- ${s.label}`).join("\n") + "\n");
|
|
9691
|
+
}
|
|
9692
|
+
}
|
|
9530
9693
|
parts.push("## Knowledge Layers\n");
|
|
9531
9694
|
parts.push(
|
|
9532
9695
|
"Project knowledge is organized in four layers: **Business \u2192 Product \u2192 Tech \u2192 Delivery**.\n"
|
|
@@ -10030,8 +10193,13 @@ function runUnderstand() {
|
|
|
10030
10193
|
for (const r of assessment.reasons) console.log(` - ${r}`);
|
|
10031
10194
|
}
|
|
10032
10195
|
if (rec.agent) console.log(`Recommended: ${rec.agent}`);
|
|
10196
|
+
if (rec.skill) console.log(`Recommended skill: ${rec.skill}`);
|
|
10033
10197
|
console.log(`Next step: ${rec.label}`);
|
|
10034
10198
|
if (rec.reason) console.log(`Why: ${rec.reason}`);
|
|
10199
|
+
if (rec.secondary && rec.secondary.length > 0) {
|
|
10200
|
+
console.log("Also:");
|
|
10201
|
+
for (const s of rec.secondary) console.log(` - ${s.label}`);
|
|
10202
|
+
}
|
|
10035
10203
|
const installedSkills = discoverInstalledSkills(dir);
|
|
10036
10204
|
if (installedSkills.length > 0 && assessment.recommendedAgents.length > 0) {
|
|
10037
10205
|
const recSkills = skillsForAgents(installedSkills, assessment.recommendedAgents);
|
|
@@ -10053,7 +10221,7 @@ function runUnderstand() {
|
|
|
10053
10221
|
console.log(`Roadmap quality: ${rqi.grounded}/${rqi.total} initiatives grounded.`);
|
|
10054
10222
|
console.log(" \u2192 Use roadmap-agent to ground roadmap initiatives in capability domains, gaps and source signals");
|
|
10055
10223
|
console.log(" before `kaddo create --from roadmap`.");
|
|
10056
|
-
} else if (rqi.total > 0 && rqi.grounded === rqi.total) {
|
|
10224
|
+
} else if (rqi.total > 0 && rqi.grounded === rqi.total && exp.roadmap.materialized_work_items === 0) {
|
|
10057
10225
|
console.log("");
|
|
10058
10226
|
console.log("Roadmap initiatives are grounded. \u2192 Run `kaddo create --from roadmap` to materialize the first Work Item.");
|
|
10059
10227
|
}
|