@kaddo/cli 3.55.0 → 3.57.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/dist/index.js +216 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ import * as p from "@clack/prompts";
|
|
|
45
45
|
var intro2 = (title) => p.intro(title);
|
|
46
46
|
var outro2 = (msg) => p.outro(msg);
|
|
47
47
|
var log2 = p.log;
|
|
48
|
+
var cancel2 = (msg) => p.cancel(msg);
|
|
48
49
|
async function text2(opts) {
|
|
49
50
|
const val = await p.text(opts);
|
|
50
51
|
if (p.isCancel(val)) {
|
|
@@ -1145,8 +1146,8 @@ function loadConfig(dir) {
|
|
|
1145
1146
|
const parsed = configSchema.safeParse(raw ?? {});
|
|
1146
1147
|
if (!parsed.success) {
|
|
1147
1148
|
const issues = parsed.error.issues.map((i) => {
|
|
1148
|
-
const
|
|
1149
|
-
return
|
|
1149
|
+
const path7 = i.path.join(".");
|
|
1150
|
+
return path7 ? ` - ${path7}: ${i.message}` : ` - ${i.message}`;
|
|
1150
1151
|
}).join("\n");
|
|
1151
1152
|
throw new ConfigError(`Invalid .kaddo/config.yml:
|
|
1152
1153
|
${issues}`);
|
|
@@ -6000,7 +6001,7 @@ function parseArtifact(filePath, raw) {
|
|
|
6000
6001
|
status: String(data.status ?? ""),
|
|
6001
6002
|
phase: String(data.phase ?? ""),
|
|
6002
6003
|
initiative: String(data.initiative ?? data.source_initiative ?? ""),
|
|
6003
|
-
source: data.source ? String(data.source) : "",
|
|
6004
|
+
source: data.source && typeof data.source === "object" ? String(data.source.type ?? "") : data.source ? String(data.source) : "",
|
|
6004
6005
|
sourceId: String(data.source_id ?? ""),
|
|
6005
6006
|
rawFrontmatter: data,
|
|
6006
6007
|
decisions: Array.isArray(data.decisions) ? data.decisions.map(String).filter(Boolean) : [],
|
|
@@ -6192,10 +6193,10 @@ function analyzeGuard(touchedFiles, artifacts, silentWithoutOwnership) {
|
|
|
6192
6193
|
import { parse as parseYaml4, stringify as stringifyYaml2 } from "yaml";
|
|
6193
6194
|
var IGNORE_FILE = ".kaddo/ignores.yml";
|
|
6194
6195
|
function loadIgnores(dir) {
|
|
6195
|
-
const
|
|
6196
|
-
if (!exists(
|
|
6196
|
+
const path7 = join(dir, IGNORE_FILE);
|
|
6197
|
+
if (!exists(path7)) return [];
|
|
6197
6198
|
try {
|
|
6198
|
-
const raw = readFile(
|
|
6199
|
+
const raw = readFile(path7);
|
|
6199
6200
|
const parsed = parseYaml4(raw);
|
|
6200
6201
|
return Array.isArray(parsed) ? parsed : [];
|
|
6201
6202
|
} catch {
|
|
@@ -6203,7 +6204,7 @@ function loadIgnores(dir) {
|
|
|
6203
6204
|
}
|
|
6204
6205
|
}
|
|
6205
6206
|
function saveIgnore(dir, entry) {
|
|
6206
|
-
const
|
|
6207
|
+
const path7 = join(dir, IGNORE_FILE);
|
|
6207
6208
|
const existing = loadIgnores(dir);
|
|
6208
6209
|
const idx = existing.findIndex((e) => e.artifact_id === entry.artifact_id);
|
|
6209
6210
|
if (idx >= 0) {
|
|
@@ -6211,17 +6212,17 @@ function saveIgnore(dir, entry) {
|
|
|
6211
6212
|
} else {
|
|
6212
6213
|
existing.push(entry);
|
|
6213
6214
|
}
|
|
6214
|
-
writeFile(
|
|
6215
|
+
writeFile(path7, stringifyYaml2(existing));
|
|
6215
6216
|
}
|
|
6216
6217
|
function isIgnored(ignores, artifactId) {
|
|
6217
6218
|
return ignores.find((e) => e.artifact_id === artifactId);
|
|
6218
6219
|
}
|
|
6219
6220
|
function removeIgnore(dir, artifactId) {
|
|
6220
|
-
const
|
|
6221
|
+
const path7 = join(dir, IGNORE_FILE);
|
|
6221
6222
|
const existing = loadIgnores(dir);
|
|
6222
6223
|
const filtered = existing.filter((e) => e.artifact_id !== artifactId);
|
|
6223
6224
|
if (filtered.length === existing.length) return false;
|
|
6224
|
-
writeFile(
|
|
6225
|
+
writeFile(path7, stringifyYaml2(filtered));
|
|
6225
6226
|
return true;
|
|
6226
6227
|
}
|
|
6227
6228
|
|
|
@@ -6243,11 +6244,11 @@ function moduleArtifactCoverage(dir, id) {
|
|
|
6243
6244
|
};
|
|
6244
6245
|
}
|
|
6245
6246
|
function loadMappedModules(dir) {
|
|
6246
|
-
const
|
|
6247
|
-
if (!exists(
|
|
6247
|
+
const path7 = join(dir, DESCRIPTOR_PATH);
|
|
6248
|
+
if (!exists(path7)) return [];
|
|
6248
6249
|
let parsed;
|
|
6249
6250
|
try {
|
|
6250
|
-
parsed = parseYaml5(readFile(
|
|
6251
|
+
parsed = parseYaml5(readFile(path7));
|
|
6251
6252
|
} catch {
|
|
6252
6253
|
return [];
|
|
6253
6254
|
}
|
|
@@ -6676,7 +6677,7 @@ function buildGuardHistory(dir) {
|
|
|
6676
6677
|
const d = hotspotDir(t.code_path);
|
|
6677
6678
|
hotspotMap.set(d, (hotspotMap.get(d) ?? 0) + 1);
|
|
6678
6679
|
}
|
|
6679
|
-
const hotspots = [...hotspotMap.entries()].map(([
|
|
6680
|
+
const hotspots = [...hotspotMap.entries()].map(([path7, warnings]) => ({ path: path7, warnings })).sort((a, b) => b.warnings - a.warnings);
|
|
6680
6681
|
return {
|
|
6681
6682
|
available: true,
|
|
6682
6683
|
total_runs: sorted.length,
|
|
@@ -7377,7 +7378,7 @@ function sectionParagraph(md, title) {
|
|
|
7377
7378
|
}
|
|
7378
7379
|
return "";
|
|
7379
7380
|
}
|
|
7380
|
-
function parseCapsule(id,
|
|
7381
|
+
function parseCapsule(id, path7, md) {
|
|
7381
7382
|
const { data } = matter3(md);
|
|
7382
7383
|
const updatedAt = data.updated_at ? String(data.updated_at) : void 0;
|
|
7383
7384
|
let ageDays = null;
|
|
@@ -7387,7 +7388,7 @@ function parseCapsule(id, path6, md) {
|
|
|
7387
7388
|
}
|
|
7388
7389
|
return {
|
|
7389
7390
|
id,
|
|
7390
|
-
path:
|
|
7391
|
+
path: path7,
|
|
7391
7392
|
system: data.system ? String(data.system) : id,
|
|
7392
7393
|
owner: data.owner ? String(data.owner) : void 0,
|
|
7393
7394
|
updatedAt,
|
|
@@ -7473,9 +7474,9 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7473
7474
|
];
|
|
7474
7475
|
const presentLayers = [];
|
|
7475
7476
|
for (const layer2 of layerDocs) {
|
|
7476
|
-
const
|
|
7477
|
-
if (
|
|
7478
|
-
addNode({ id: layer2.id, type: layer2.type, label: layer2.label, path:
|
|
7477
|
+
const path7 = layer2.files.map((f) => `${KNOWLEDGE2}/${f}`).find((rel) => exists(join(dir, rel)));
|
|
7478
|
+
if (path7) {
|
|
7479
|
+
addNode({ id: layer2.id, type: layer2.type, label: layer2.label, path: path7 });
|
|
7479
7480
|
presentLayers.push(layer2.id);
|
|
7480
7481
|
}
|
|
7481
7482
|
}
|
|
@@ -8983,10 +8984,10 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
8983
8984
|
const discovery = state === "pre-ai" || state === "legacy";
|
|
8984
8985
|
const resolveAgent = (agent) => {
|
|
8985
8986
|
const file = agent.endsWith(".md") ? agent : `${agent}.md`;
|
|
8986
|
-
const
|
|
8987
|
-
const installed = isFile(join(dir,
|
|
8987
|
+
const path7 = agentInstallPath(file);
|
|
8988
|
+
const installed = isFile(join(dir, path7));
|
|
8988
8989
|
const group = agentGroupOf(file);
|
|
8989
|
-
return { agentPath:
|
|
8990
|
+
return { agentPath: path7, agentInstalled: installed, installCommand: installed ? void 0 : `kaddo add agents --group ${group}` };
|
|
8990
8991
|
};
|
|
8991
8992
|
const refine = (id, agent, target, quality, verb = "complete") => {
|
|
8992
8993
|
const ar = resolveAgent(agent);
|
|
@@ -9026,12 +9027,23 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
9026
9027
|
if (oq.summary.blocking_open > 0) {
|
|
9027
9028
|
return { id: "questions", phase: "Knowledge Refinement", label: "Run `kaddo questions` to see source locations and resolution guidance, then resolve, assume or defer the blocking open questions.", command: "kaddo questions", reason: `${oq.summary.blocking_open} blocking open question(s) remain.` };
|
|
9028
9029
|
}
|
|
9030
|
+
const st = buildDeliveryState(dir);
|
|
9031
|
+
const secondary = buildSecondaryRecommendations(st);
|
|
9029
9032
|
const roadmap = roadmapSignal(dir);
|
|
9033
|
+
if (roadmap !== "has-candidates" && st.draft_work_items > 0) {
|
|
9034
|
+
return {
|
|
9035
|
+
id: "refine-work-item",
|
|
9036
|
+
phase: "Active Delivery",
|
|
9037
|
+
label: "Refine the existing draft Work Item with the work-item-agent.",
|
|
9038
|
+
agent: "work-item-agent",
|
|
9039
|
+
skill: "work-item-refinement",
|
|
9040
|
+
reason: `There ${st.draft_work_items === 1 ? "is" : "are"} ${st.draft_work_items} draft Work Item${st.draft_work_items === 1 ? "" : "s"}. Refine before defining roadmap candidates.`,
|
|
9041
|
+
...secondary.length ? { secondary } : {}
|
|
9042
|
+
};
|
|
9043
|
+
}
|
|
9030
9044
|
if (roadmap !== "has-candidates") {
|
|
9031
9045
|
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." };
|
|
9032
9046
|
}
|
|
9033
|
-
const st = buildDeliveryState(dir);
|
|
9034
|
-
const secondary = buildSecondaryRecommendations(st);
|
|
9035
9047
|
if (st.total_work_items === 0) {
|
|
9036
9048
|
return {
|
|
9037
9049
|
id: "create-work-item",
|
|
@@ -9400,7 +9412,25 @@ function isValidSource(s) {
|
|
|
9400
9412
|
return VALID_SOURCES.includes(s);
|
|
9401
9413
|
}
|
|
9402
9414
|
function parseWorkItemSource(frontmatter) {
|
|
9403
|
-
const
|
|
9415
|
+
const rawSource = frontmatter.source;
|
|
9416
|
+
if (rawSource != null && typeof rawSource === "object" && !Array.isArray(rawSource)) {
|
|
9417
|
+
const obj = rawSource;
|
|
9418
|
+
const t = optStr(obj.type);
|
|
9419
|
+
const type = t && isValidSource(t) ? t : "unknown";
|
|
9420
|
+
return {
|
|
9421
|
+
type,
|
|
9422
|
+
id: optStr(obj.id) ?? optStr(frontmatter.source_id),
|
|
9423
|
+
title: optStr(obj.title) ?? optStr(frontmatter.source_title),
|
|
9424
|
+
context: optStr(obj.context) ?? optStr(frontmatter.source_context),
|
|
9425
|
+
provider: optStr(obj.provider) ?? optStr(frontmatter.source_provider),
|
|
9426
|
+
url: optStr(obj.url) ?? optStr(frontmatter.source_url),
|
|
9427
|
+
imported_at: optStr(obj.imported_at) ?? optStr(frontmatter.source_imported_at),
|
|
9428
|
+
synced_at: optStr(obj.synced_at) ?? optStr(frontmatter.source_synced_at),
|
|
9429
|
+
inferred: obj.inferred === true || obj.inferred === "true",
|
|
9430
|
+
reason: t && !isValidSource(t) ? `Invalid source type in object: "${t}".` : void 0
|
|
9431
|
+
};
|
|
9432
|
+
}
|
|
9433
|
+
const raw = rawSource ? String(rawSource) : "";
|
|
9404
9434
|
if (raw && isValidSource(raw)) {
|
|
9405
9435
|
return {
|
|
9406
9436
|
type: raw,
|
|
@@ -12731,10 +12761,10 @@ ${globs.map((g) => ` - ${g}`).join("\n")}`);
|
|
|
12731
12761
|
import { parse as parseYaml13, stringify as stringifyYaml5 } from "yaml";
|
|
12732
12762
|
var DESCRIPTOR_PATH2 = "knowledge/module.yml";
|
|
12733
12763
|
function readDescriptor(dir) {
|
|
12734
|
-
const
|
|
12735
|
-
if (!exists(
|
|
12764
|
+
const path7 = join(dir, DESCRIPTOR_PATH2);
|
|
12765
|
+
if (!exists(path7)) return null;
|
|
12736
12766
|
try {
|
|
12737
|
-
return parseYaml13(readFile(
|
|
12767
|
+
return parseYaml13(readFile(path7));
|
|
12738
12768
|
} catch {
|
|
12739
12769
|
return null;
|
|
12740
12770
|
}
|
|
@@ -14339,10 +14369,10 @@ function slugify4(name) {
|
|
|
14339
14369
|
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
14340
14370
|
}
|
|
14341
14371
|
function readModulesDescriptor(dir) {
|
|
14342
|
-
const
|
|
14343
|
-
if (!exists(
|
|
14372
|
+
const path7 = join(dir, DESCRIPTOR_PATH3);
|
|
14373
|
+
if (!exists(path7)) return { version: 1, modules: [] };
|
|
14344
14374
|
try {
|
|
14345
|
-
const parsed = parseYaml14(readFile(
|
|
14375
|
+
const parsed = parseYaml14(readFile(path7));
|
|
14346
14376
|
return { version: parsed.version ?? 1, modules: parsed.modules ?? [] };
|
|
14347
14377
|
} catch {
|
|
14348
14378
|
return { version: 1, modules: [] };
|
|
@@ -16410,6 +16440,156 @@ function runAssetsUpdate(kind, opts = {}) {
|
|
|
16410
16440
|
outro2(`${LABEL[kind]} update complete.`);
|
|
16411
16441
|
}
|
|
16412
16442
|
|
|
16443
|
+
// src/commands/ready.ts
|
|
16444
|
+
import fs4 from "fs";
|
|
16445
|
+
import path6 from "path";
|
|
16446
|
+
import matter11 from "gray-matter";
|
|
16447
|
+
function validateReadiness(content, frontmatter) {
|
|
16448
|
+
const warnings = [];
|
|
16449
|
+
const body = content.replace(/^---[\s\S]*?---/, "").trim();
|
|
16450
|
+
const lower = body.toLowerCase();
|
|
16451
|
+
if (!frontmatter.domains || Array.isArray(frontmatter.domains) && frontmatter.domains.length === 0) {
|
|
16452
|
+
warnings.push({ field: "domains", message: "No domains declared." });
|
|
16453
|
+
}
|
|
16454
|
+
const code = frontmatter.code;
|
|
16455
|
+
if (!code || Array.isArray(code) && code.length === 0) {
|
|
16456
|
+
warnings.push({ field: "code", message: "No code ownership globs declared." });
|
|
16457
|
+
}
|
|
16458
|
+
const hasAC = /## acceptance criteria|## criterios de aceptación/i.test(body);
|
|
16459
|
+
if (!hasAC) {
|
|
16460
|
+
warnings.push({ field: "acceptance_criteria", message: "No acceptance criteria section found." });
|
|
16461
|
+
} else {
|
|
16462
|
+
const acSection = extractSection(body, /## acceptance criteria|## criterios de aceptación/i);
|
|
16463
|
+
if (acSection && acSection.trim().length === 0) {
|
|
16464
|
+
warnings.push({ field: "acceptance_criteria", message: "Acceptance criteria section is empty." });
|
|
16465
|
+
}
|
|
16466
|
+
}
|
|
16467
|
+
const hasValidation = /## validation|## validación/i.test(body);
|
|
16468
|
+
if (!hasValidation) {
|
|
16469
|
+
warnings.push({ field: "validation", message: "No validation section found." });
|
|
16470
|
+
}
|
|
16471
|
+
const hasOQ = /## open questions|## preguntas abiertas/i.test(body);
|
|
16472
|
+
if (hasOQ) {
|
|
16473
|
+
const oqSection = extractSection(body, /## open questions|## preguntas abiertas/i);
|
|
16474
|
+
if (oqSection && !isResolvedSection(oqSection)) {
|
|
16475
|
+
warnings.push({ field: "open_questions", message: "Open questions are still present." });
|
|
16476
|
+
}
|
|
16477
|
+
}
|
|
16478
|
+
return warnings;
|
|
16479
|
+
}
|
|
16480
|
+
function extractSection(body, headerPattern) {
|
|
16481
|
+
const lines = body.split(/\r?\n/);
|
|
16482
|
+
let capture = false;
|
|
16483
|
+
const result = [];
|
|
16484
|
+
for (const line of lines) {
|
|
16485
|
+
if (capture) {
|
|
16486
|
+
if (/^#{1,3}\s/.test(line)) break;
|
|
16487
|
+
result.push(line);
|
|
16488
|
+
} else if (headerPattern.test(line)) {
|
|
16489
|
+
capture = true;
|
|
16490
|
+
}
|
|
16491
|
+
}
|
|
16492
|
+
return capture ? result.join("\n").trim() : null;
|
|
16493
|
+
}
|
|
16494
|
+
function isResolvedSection(text3) {
|
|
16495
|
+
const t = text3.trim().toLowerCase();
|
|
16496
|
+
return t === "" || /^(none|ninguna|resolved|resueltas|deferred|diferidas)\.?$/i.test(t);
|
|
16497
|
+
}
|
|
16498
|
+
function transitionToReady(filePath) {
|
|
16499
|
+
const raw = readFile(filePath);
|
|
16500
|
+
const { data, content } = matter11(raw);
|
|
16501
|
+
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
16502
|
+
data.status = "ready";
|
|
16503
|
+
data.ready_at = today2;
|
|
16504
|
+
const newContent = matter11.stringify(content, data);
|
|
16505
|
+
const posix = filePath.replace(/\\/g, "/");
|
|
16506
|
+
let newPath = filePath;
|
|
16507
|
+
if (posix.includes("/work-items/draft/")) {
|
|
16508
|
+
const readyDir = path6.dirname(filePath).replace(/[/\\]draft$/, path6.sep + "ready");
|
|
16509
|
+
ensureDir(readyDir);
|
|
16510
|
+
const fileName = path6.basename(filePath);
|
|
16511
|
+
newPath = path6.join(readyDir, fileName);
|
|
16512
|
+
}
|
|
16513
|
+
return { newPath, newContent };
|
|
16514
|
+
}
|
|
16515
|
+
function findWorkItem(dir, id) {
|
|
16516
|
+
const wis = discoverWorkItems(dir);
|
|
16517
|
+
return wis.find((w) => w.id.toLowerCase() === id.toLowerCase()) ?? null;
|
|
16518
|
+
}
|
|
16519
|
+
async function runReady(id, opts = {}) {
|
|
16520
|
+
const dir = process.cwd();
|
|
16521
|
+
intro2("kaddo ready " + id);
|
|
16522
|
+
const config = loadConfig(dir);
|
|
16523
|
+
if (!config) {
|
|
16524
|
+
log2.error("Kaddo is not initialized. Run `kaddo init` first.");
|
|
16525
|
+
process.exit(1);
|
|
16526
|
+
}
|
|
16527
|
+
const wi = findWorkItem(dir, id);
|
|
16528
|
+
if (!wi) {
|
|
16529
|
+
log2.error(`Work Item ${id} not found.`);
|
|
16530
|
+
log2.info("Run `kaddo history` or check knowledge/delivery/work-items/ for available IDs.");
|
|
16531
|
+
process.exit(1);
|
|
16532
|
+
}
|
|
16533
|
+
if (wi.lifecycle === "ready") {
|
|
16534
|
+
log2.info(`Work Item ${wi.id} is already ready.`);
|
|
16535
|
+
log2.info("Suggested next: kaddo context && kaddo understand");
|
|
16536
|
+
outro2("Nothing to do.");
|
|
16537
|
+
return;
|
|
16538
|
+
}
|
|
16539
|
+
if (wi.lifecycle !== "draft") {
|
|
16540
|
+
log2.error(`Work Item ${wi.id} is in state "${wi.lifecycle}", not "draft". Only draft Work Items can be marked as ready.`);
|
|
16541
|
+
process.exit(1);
|
|
16542
|
+
}
|
|
16543
|
+
const raw = readFile(wi.filePath);
|
|
16544
|
+
const { data } = matter11(raw);
|
|
16545
|
+
const source = parseWorkItemSource(data);
|
|
16546
|
+
const warnings = validateReadiness(raw, data);
|
|
16547
|
+
log2.info(`Work Item found:`);
|
|
16548
|
+
log2.info(` ${wi.id} \u2014 ${wi.title}`);
|
|
16549
|
+
log2.info("");
|
|
16550
|
+
log2.info(` Status: draft \u2192 ready`);
|
|
16551
|
+
log2.info(` Type: ${wi.type}`);
|
|
16552
|
+
log2.info(` Knowledge level: ${wi.knowledgeLevel || "unset"}`);
|
|
16553
|
+
log2.info(` Domains: ${wi.domains.length > 0 ? wi.domains.join(", ") : "none"}`);
|
|
16554
|
+
log2.info(` Source: ${renderSourceCompact(source)}`);
|
|
16555
|
+
if (wi.codeGlobs.length > 0) {
|
|
16556
|
+
log2.info(` Code ownership:`);
|
|
16557
|
+
for (const g of wi.codeGlobs) log2.info(` - ${g}`);
|
|
16558
|
+
} else {
|
|
16559
|
+
log2.info(` Code ownership: none`);
|
|
16560
|
+
}
|
|
16561
|
+
if (warnings.length > 0) {
|
|
16562
|
+
log2.warn("");
|
|
16563
|
+
log2.warn("This Work Item may not be ready:");
|
|
16564
|
+
for (const w of warnings) {
|
|
16565
|
+
log2.warn(` - ${w.message}`);
|
|
16566
|
+
}
|
|
16567
|
+
}
|
|
16568
|
+
if (!opts.yes) {
|
|
16569
|
+
log2.info("");
|
|
16570
|
+
const proceed = await confirm2({ message: "Mark this Work Item as ready for implementation?" });
|
|
16571
|
+
if (!proceed) {
|
|
16572
|
+
cancel2("Cancelled.");
|
|
16573
|
+
return;
|
|
16574
|
+
}
|
|
16575
|
+
}
|
|
16576
|
+
const { newPath, newContent } = transitionToReady(wi.filePath);
|
|
16577
|
+
if (newPath !== wi.filePath) {
|
|
16578
|
+
writeFile(newPath, newContent);
|
|
16579
|
+
fs4.unlinkSync(wi.filePath);
|
|
16580
|
+
log2.success(`Updated status: ready`);
|
|
16581
|
+
log2.success(`Moved file:`);
|
|
16582
|
+
log2.info(` ${path6.relative(dir, wi.filePath)}`);
|
|
16583
|
+
log2.info(` \u2192 ${path6.relative(dir, newPath)}`);
|
|
16584
|
+
} else {
|
|
16585
|
+
writeFile(wi.filePath, newContent);
|
|
16586
|
+
log2.success(`Updated status: ready`);
|
|
16587
|
+
}
|
|
16588
|
+
log2.info("");
|
|
16589
|
+
log2.info("Run `kaddo context && kaddo understand` to refresh the handoff.");
|
|
16590
|
+
outro2(`Work Item ${wi.id} is ready.`);
|
|
16591
|
+
}
|
|
16592
|
+
|
|
16413
16593
|
// src/index.ts
|
|
16414
16594
|
var require2 = createRequire(import.meta.url);
|
|
16415
16595
|
var { version } = require2("../package.json");
|
|
@@ -16427,12 +16607,15 @@ program.command("bootstrap").description("Build the initial knowledge base for a
|
|
|
16427
16607
|
program.command("create [type]").description("Create a work item (feature, bugfix, hotfix, spike, chore). Use --from roadmap to create from a roadmap candidate.").option("--from <source>", "Create from a source artifact (currently: roadmap)").action(async (type, opts) => {
|
|
16428
16608
|
await runCreate(type ?? "", opts);
|
|
16429
16609
|
});
|
|
16610
|
+
program.command("ready <id>").description("Mark a draft Work Item as ready for implementation after human review").option("--yes", "Skip confirmation prompt").action(async (id, opts) => {
|
|
16611
|
+
await runReady(id, opts);
|
|
16612
|
+
});
|
|
16430
16613
|
var capsuleCmd = program.command("capsule").description("Export this project as a Knowledge Capsule, or import an external one as context");
|
|
16431
16614
|
capsuleCmd.command("export").description("Write a Knowledge Capsule about this project to .kaddo/exports/").action(() => {
|
|
16432
16615
|
runCapsuleExport();
|
|
16433
16616
|
});
|
|
16434
|
-
capsuleCmd.command("add <path>").description("Register an external Knowledge Capsule as project context (.kaddo/external.yml)").action((
|
|
16435
|
-
runCapsuleAdd(
|
|
16617
|
+
capsuleCmd.command("add <path>").description("Register an external Knowledge Capsule as project context (.kaddo/external.yml)").action((path7) => {
|
|
16618
|
+
runCapsuleAdd(path7);
|
|
16436
16619
|
});
|
|
16437
16620
|
var graphCmd = program.command("graph").description("Export the lightweight, file-based knowledge graph of the project");
|
|
16438
16621
|
graphCmd.command("export").description("Write the knowledge graph to .kaddo/graph.json and .kaddo/graph.mmd").option("--scope <scope>", "Graph scope: active (default) or all").option("--format <format>", "Output format: json, mermaid (default: both)").action((opts) => {
|