@kaddo/cli 3.56.0 → 3.58.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 +212 -34
- 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}`);
|
|
@@ -2231,6 +2232,8 @@ validation (how to test it), definition of done, open questions and dependencies
|
|
|
2231
2232
|
- Do not expand scope without explicit confirmation.
|
|
2232
2233
|
- Do not create mega Work Items \u2014 split when it covers multiple outcomes.
|
|
2233
2234
|
- Keep acceptance criteria testable.
|
|
2235
|
+
- This skill refines scope and acceptance criteria but does not approve implementation readiness.
|
|
2236
|
+
Readiness requires human confirmation through \`kaddo ready\` or the MCP \`mark_work_item_ready\` action.
|
|
2234
2237
|
|
|
2235
2238
|
## Quality checklist
|
|
2236
2239
|
|
|
@@ -2636,9 +2639,9 @@ var RESPONSIBILITY_MATRIX = {
|
|
|
2636
2639
|
agent: "work-item-agent",
|
|
2637
2640
|
responsibleFor: ["Work Item refinement"],
|
|
2638
2641
|
produces: ["knowledge/delivery/work-items/"],
|
|
2639
|
-
canSuggest: ["implementation-agent"],
|
|
2642
|
+
canSuggest: ["kaddo ready", "mark_work_item_ready", "implementation-agent"],
|
|
2640
2643
|
cannotSuggest: ["branches", "commits", "pull requests", "code"],
|
|
2641
|
-
next: ["implementation-agent"]
|
|
2644
|
+
next: ["kaddo ready (human review)", "implementation-agent"]
|
|
2642
2645
|
},
|
|
2643
2646
|
"implementation-agent": {
|
|
2644
2647
|
agent: "implementation-agent",
|
|
@@ -3651,7 +3654,16 @@ and \`blocked\` as active work; \`completed\` and \`archived\` are historical kn
|
|
|
3651
3654
|
|
|
3652
3655
|
## Handoff
|
|
3653
3656
|
|
|
3654
|
-
|
|
3657
|
+
After refining a Work Item, **do not mark it ready automatically**. If the Work Item appears
|
|
3658
|
+
complete (acceptance criteria, validation, code globs, domains all present, open questions
|
|
3659
|
+
resolved), recommend human review and the ready transition:
|
|
3660
|
+
|
|
3661
|
+
- **CLI:** \`kaddo ready <WI-ID>\`
|
|
3662
|
+
- **MCP:** \`mark_work_item_ready({ id: "<WI-ID>" })\`
|
|
3663
|
+
|
|
3664
|
+
The transition to \`ready\` requires explicit human confirmation. Only after a human marks the
|
|
3665
|
+
Work Item as ready should it be handed off to the implementation-agent.
|
|
3666
|
+
|
|
3655
3667
|
You do **not** suggest branches, commits or pull requests \u2014 implementation (including any Git
|
|
3656
3668
|
branch suggestion) is the implementation-agent's responsibility, and only by respecting the
|
|
3657
3669
|
project Git strategy. Your job ends at a clear, traceable Work Item that **states how to test it**.
|
|
@@ -6000,7 +6012,7 @@ function parseArtifact(filePath, raw) {
|
|
|
6000
6012
|
status: String(data.status ?? ""),
|
|
6001
6013
|
phase: String(data.phase ?? ""),
|
|
6002
6014
|
initiative: String(data.initiative ?? data.source_initiative ?? ""),
|
|
6003
|
-
source: data.source ? String(data.source) : "",
|
|
6015
|
+
source: data.source && typeof data.source === "object" ? String(data.source.type ?? "") : data.source ? String(data.source) : "",
|
|
6004
6016
|
sourceId: String(data.source_id ?? ""),
|
|
6005
6017
|
rawFrontmatter: data,
|
|
6006
6018
|
decisions: Array.isArray(data.decisions) ? data.decisions.map(String).filter(Boolean) : [],
|
|
@@ -6192,10 +6204,10 @@ function analyzeGuard(touchedFiles, artifacts, silentWithoutOwnership) {
|
|
|
6192
6204
|
import { parse as parseYaml4, stringify as stringifyYaml2 } from "yaml";
|
|
6193
6205
|
var IGNORE_FILE = ".kaddo/ignores.yml";
|
|
6194
6206
|
function loadIgnores(dir) {
|
|
6195
|
-
const
|
|
6196
|
-
if (!exists(
|
|
6207
|
+
const path7 = join(dir, IGNORE_FILE);
|
|
6208
|
+
if (!exists(path7)) return [];
|
|
6197
6209
|
try {
|
|
6198
|
-
const raw = readFile(
|
|
6210
|
+
const raw = readFile(path7);
|
|
6199
6211
|
const parsed = parseYaml4(raw);
|
|
6200
6212
|
return Array.isArray(parsed) ? parsed : [];
|
|
6201
6213
|
} catch {
|
|
@@ -6203,7 +6215,7 @@ function loadIgnores(dir) {
|
|
|
6203
6215
|
}
|
|
6204
6216
|
}
|
|
6205
6217
|
function saveIgnore(dir, entry) {
|
|
6206
|
-
const
|
|
6218
|
+
const path7 = join(dir, IGNORE_FILE);
|
|
6207
6219
|
const existing = loadIgnores(dir);
|
|
6208
6220
|
const idx = existing.findIndex((e) => e.artifact_id === entry.artifact_id);
|
|
6209
6221
|
if (idx >= 0) {
|
|
@@ -6211,17 +6223,17 @@ function saveIgnore(dir, entry) {
|
|
|
6211
6223
|
} else {
|
|
6212
6224
|
existing.push(entry);
|
|
6213
6225
|
}
|
|
6214
|
-
writeFile(
|
|
6226
|
+
writeFile(path7, stringifyYaml2(existing));
|
|
6215
6227
|
}
|
|
6216
6228
|
function isIgnored(ignores, artifactId) {
|
|
6217
6229
|
return ignores.find((e) => e.artifact_id === artifactId);
|
|
6218
6230
|
}
|
|
6219
6231
|
function removeIgnore(dir, artifactId) {
|
|
6220
|
-
const
|
|
6232
|
+
const path7 = join(dir, IGNORE_FILE);
|
|
6221
6233
|
const existing = loadIgnores(dir);
|
|
6222
6234
|
const filtered = existing.filter((e) => e.artifact_id !== artifactId);
|
|
6223
6235
|
if (filtered.length === existing.length) return false;
|
|
6224
|
-
writeFile(
|
|
6236
|
+
writeFile(path7, stringifyYaml2(filtered));
|
|
6225
6237
|
return true;
|
|
6226
6238
|
}
|
|
6227
6239
|
|
|
@@ -6243,11 +6255,11 @@ function moduleArtifactCoverage(dir, id) {
|
|
|
6243
6255
|
};
|
|
6244
6256
|
}
|
|
6245
6257
|
function loadMappedModules(dir) {
|
|
6246
|
-
const
|
|
6247
|
-
if (!exists(
|
|
6258
|
+
const path7 = join(dir, DESCRIPTOR_PATH);
|
|
6259
|
+
if (!exists(path7)) return [];
|
|
6248
6260
|
let parsed;
|
|
6249
6261
|
try {
|
|
6250
|
-
parsed = parseYaml5(readFile(
|
|
6262
|
+
parsed = parseYaml5(readFile(path7));
|
|
6251
6263
|
} catch {
|
|
6252
6264
|
return [];
|
|
6253
6265
|
}
|
|
@@ -6676,7 +6688,7 @@ function buildGuardHistory(dir) {
|
|
|
6676
6688
|
const d = hotspotDir(t.code_path);
|
|
6677
6689
|
hotspotMap.set(d, (hotspotMap.get(d) ?? 0) + 1);
|
|
6678
6690
|
}
|
|
6679
|
-
const hotspots = [...hotspotMap.entries()].map(([
|
|
6691
|
+
const hotspots = [...hotspotMap.entries()].map(([path7, warnings]) => ({ path: path7, warnings })).sort((a, b) => b.warnings - a.warnings);
|
|
6680
6692
|
return {
|
|
6681
6693
|
available: true,
|
|
6682
6694
|
total_runs: sorted.length,
|
|
@@ -7377,7 +7389,7 @@ function sectionParagraph(md, title) {
|
|
|
7377
7389
|
}
|
|
7378
7390
|
return "";
|
|
7379
7391
|
}
|
|
7380
|
-
function parseCapsule(id,
|
|
7392
|
+
function parseCapsule(id, path7, md) {
|
|
7381
7393
|
const { data } = matter3(md);
|
|
7382
7394
|
const updatedAt = data.updated_at ? String(data.updated_at) : void 0;
|
|
7383
7395
|
let ageDays = null;
|
|
@@ -7387,7 +7399,7 @@ function parseCapsule(id, path6, md) {
|
|
|
7387
7399
|
}
|
|
7388
7400
|
return {
|
|
7389
7401
|
id,
|
|
7390
|
-
path:
|
|
7402
|
+
path: path7,
|
|
7391
7403
|
system: data.system ? String(data.system) : id,
|
|
7392
7404
|
owner: data.owner ? String(data.owner) : void 0,
|
|
7393
7405
|
updatedAt,
|
|
@@ -7473,9 +7485,9 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7473
7485
|
];
|
|
7474
7486
|
const presentLayers = [];
|
|
7475
7487
|
for (const layer2 of layerDocs) {
|
|
7476
|
-
const
|
|
7477
|
-
if (
|
|
7478
|
-
addNode({ id: layer2.id, type: layer2.type, label: layer2.label, path:
|
|
7488
|
+
const path7 = layer2.files.map((f) => `${KNOWLEDGE2}/${f}`).find((rel) => exists(join(dir, rel)));
|
|
7489
|
+
if (path7) {
|
|
7490
|
+
addNode({ id: layer2.id, type: layer2.type, label: layer2.label, path: path7 });
|
|
7479
7491
|
presentLayers.push(layer2.id);
|
|
7480
7492
|
}
|
|
7481
7493
|
}
|
|
@@ -8903,6 +8915,7 @@ function buildDeliveryState(dir) {
|
|
|
8903
8915
|
return {
|
|
8904
8916
|
phase: "",
|
|
8905
8917
|
draft_work_items: byState("draft"),
|
|
8918
|
+
refined_draft_work_items: wis.filter((w) => w.lifecycle === "draft" && w.rawFrontmatter.refined_by).length,
|
|
8906
8919
|
ready_work_items: byState("ready"),
|
|
8907
8920
|
in_progress_work_items: byState("in-progress"),
|
|
8908
8921
|
blocked_work_items: byState("blocked"),
|
|
@@ -8983,10 +8996,10 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
8983
8996
|
const discovery = state === "pre-ai" || state === "legacy";
|
|
8984
8997
|
const resolveAgent = (agent) => {
|
|
8985
8998
|
const file = agent.endsWith(".md") ? agent : `${agent}.md`;
|
|
8986
|
-
const
|
|
8987
|
-
const installed = isFile(join(dir,
|
|
8999
|
+
const path7 = agentInstallPath(file);
|
|
9000
|
+
const installed = isFile(join(dir, path7));
|
|
8988
9001
|
const group = agentGroupOf(file);
|
|
8989
|
-
return { agentPath:
|
|
9002
|
+
return { agentPath: path7, agentInstalled: installed, installCommand: installed ? void 0 : `kaddo add agents --group ${group}` };
|
|
8990
9003
|
};
|
|
8991
9004
|
const refine = (id, agent, target, quality, verb = "complete") => {
|
|
8992
9005
|
const ar = resolveAgent(agent);
|
|
@@ -9030,6 +9043,17 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
9030
9043
|
const secondary = buildSecondaryRecommendations(st);
|
|
9031
9044
|
const roadmap = roadmapSignal(dir);
|
|
9032
9045
|
if (roadmap !== "has-candidates" && st.draft_work_items > 0) {
|
|
9046
|
+
if (st.refined_draft_work_items > 0) {
|
|
9047
|
+
return {
|
|
9048
|
+
id: "review-work-item",
|
|
9049
|
+
phase: "Active Delivery",
|
|
9050
|
+
label: "Review the refined draft Work Item and mark it ready with `kaddo ready`.",
|
|
9051
|
+
command: "kaddo ready",
|
|
9052
|
+
mcpAction: "kaddo_mark_work_item_ready",
|
|
9053
|
+
reason: `There ${st.refined_draft_work_items === 1 ? "is" : "are"} ${st.refined_draft_work_items} refined draft Work Item${st.refined_draft_work_items === 1 ? "" : "s"} awaiting human review.`,
|
|
9054
|
+
...secondary.length ? { secondary } : {}
|
|
9055
|
+
};
|
|
9056
|
+
}
|
|
9033
9057
|
return {
|
|
9034
9058
|
id: "refine-work-item",
|
|
9035
9059
|
phase: "Active Delivery",
|
|
@@ -9835,7 +9859,8 @@ function mapNextStepId(id) {
|
|
|
9835
9859
|
"refine-product": "define-product",
|
|
9836
9860
|
"refine-capabilities": "discover-capabilities",
|
|
9837
9861
|
"refine-current-state": "describe-architecture",
|
|
9838
|
-
"refine-codebase": "describe-architecture"
|
|
9862
|
+
"refine-codebase": "describe-architecture",
|
|
9863
|
+
"review-work-item": "refine-work-item"
|
|
9839
9864
|
};
|
|
9840
9865
|
return MAP[id] ?? id;
|
|
9841
9866
|
}
|
|
@@ -12760,10 +12785,10 @@ ${globs.map((g) => ` - ${g}`).join("\n")}`);
|
|
|
12760
12785
|
import { parse as parseYaml13, stringify as stringifyYaml5 } from "yaml";
|
|
12761
12786
|
var DESCRIPTOR_PATH2 = "knowledge/module.yml";
|
|
12762
12787
|
function readDescriptor(dir) {
|
|
12763
|
-
const
|
|
12764
|
-
if (!exists(
|
|
12788
|
+
const path7 = join(dir, DESCRIPTOR_PATH2);
|
|
12789
|
+
if (!exists(path7)) return null;
|
|
12765
12790
|
try {
|
|
12766
|
-
return parseYaml13(readFile(
|
|
12791
|
+
return parseYaml13(readFile(path7));
|
|
12767
12792
|
} catch {
|
|
12768
12793
|
return null;
|
|
12769
12794
|
}
|
|
@@ -14368,10 +14393,10 @@ function slugify4(name) {
|
|
|
14368
14393
|
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
14369
14394
|
}
|
|
14370
14395
|
function readModulesDescriptor(dir) {
|
|
14371
|
-
const
|
|
14372
|
-
if (!exists(
|
|
14396
|
+
const path7 = join(dir, DESCRIPTOR_PATH3);
|
|
14397
|
+
if (!exists(path7)) return { version: 1, modules: [] };
|
|
14373
14398
|
try {
|
|
14374
|
-
const parsed = parseYaml14(readFile(
|
|
14399
|
+
const parsed = parseYaml14(readFile(path7));
|
|
14375
14400
|
return { version: parsed.version ?? 1, modules: parsed.modules ?? [] };
|
|
14376
14401
|
} catch {
|
|
14377
14402
|
return { version: 1, modules: [] };
|
|
@@ -16439,6 +16464,156 @@ function runAssetsUpdate(kind, opts = {}) {
|
|
|
16439
16464
|
outro2(`${LABEL[kind]} update complete.`);
|
|
16440
16465
|
}
|
|
16441
16466
|
|
|
16467
|
+
// src/commands/ready.ts
|
|
16468
|
+
import fs4 from "fs";
|
|
16469
|
+
import path6 from "path";
|
|
16470
|
+
import matter11 from "gray-matter";
|
|
16471
|
+
function validateReadiness(content, frontmatter) {
|
|
16472
|
+
const warnings = [];
|
|
16473
|
+
const body = content.replace(/^---[\s\S]*?---/, "").trim();
|
|
16474
|
+
const lower = body.toLowerCase();
|
|
16475
|
+
if (!frontmatter.domains || Array.isArray(frontmatter.domains) && frontmatter.domains.length === 0) {
|
|
16476
|
+
warnings.push({ field: "domains", message: "No domains declared." });
|
|
16477
|
+
}
|
|
16478
|
+
const code = frontmatter.code;
|
|
16479
|
+
if (!code || Array.isArray(code) && code.length === 0) {
|
|
16480
|
+
warnings.push({ field: "code", message: "No code ownership globs declared." });
|
|
16481
|
+
}
|
|
16482
|
+
const hasAC = /## acceptance criteria|## criterios de aceptación/i.test(body);
|
|
16483
|
+
if (!hasAC) {
|
|
16484
|
+
warnings.push({ field: "acceptance_criteria", message: "No acceptance criteria section found." });
|
|
16485
|
+
} else {
|
|
16486
|
+
const acSection = extractSection(body, /## acceptance criteria|## criterios de aceptación/i);
|
|
16487
|
+
if (acSection && acSection.trim().length === 0) {
|
|
16488
|
+
warnings.push({ field: "acceptance_criteria", message: "Acceptance criteria section is empty." });
|
|
16489
|
+
}
|
|
16490
|
+
}
|
|
16491
|
+
const hasValidation = /## validation|## validación/i.test(body);
|
|
16492
|
+
if (!hasValidation) {
|
|
16493
|
+
warnings.push({ field: "validation", message: "No validation section found." });
|
|
16494
|
+
}
|
|
16495
|
+
const hasOQ = /## open questions|## preguntas abiertas/i.test(body);
|
|
16496
|
+
if (hasOQ) {
|
|
16497
|
+
const oqSection = extractSection(body, /## open questions|## preguntas abiertas/i);
|
|
16498
|
+
if (oqSection && !isResolvedSection(oqSection)) {
|
|
16499
|
+
warnings.push({ field: "open_questions", message: "Open questions are still present." });
|
|
16500
|
+
}
|
|
16501
|
+
}
|
|
16502
|
+
return warnings;
|
|
16503
|
+
}
|
|
16504
|
+
function extractSection(body, headerPattern) {
|
|
16505
|
+
const lines = body.split(/\r?\n/);
|
|
16506
|
+
let capture = false;
|
|
16507
|
+
const result = [];
|
|
16508
|
+
for (const line of lines) {
|
|
16509
|
+
if (capture) {
|
|
16510
|
+
if (/^#{1,3}\s/.test(line)) break;
|
|
16511
|
+
result.push(line);
|
|
16512
|
+
} else if (headerPattern.test(line)) {
|
|
16513
|
+
capture = true;
|
|
16514
|
+
}
|
|
16515
|
+
}
|
|
16516
|
+
return capture ? result.join("\n").trim() : null;
|
|
16517
|
+
}
|
|
16518
|
+
function isResolvedSection(text3) {
|
|
16519
|
+
const t = text3.trim().toLowerCase();
|
|
16520
|
+
return t === "" || /^(none|ninguna|resolved|resueltas|deferred|diferidas)\.?$/i.test(t);
|
|
16521
|
+
}
|
|
16522
|
+
function transitionToReady(filePath) {
|
|
16523
|
+
const raw = readFile(filePath);
|
|
16524
|
+
const { data, content } = matter11(raw);
|
|
16525
|
+
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
16526
|
+
data.status = "ready";
|
|
16527
|
+
data.ready_at = today2;
|
|
16528
|
+
const newContent = matter11.stringify(content, data);
|
|
16529
|
+
const posix = filePath.replace(/\\/g, "/");
|
|
16530
|
+
let newPath = filePath;
|
|
16531
|
+
if (posix.includes("/work-items/draft/")) {
|
|
16532
|
+
const readyDir = path6.dirname(filePath).replace(/[/\\]draft$/, path6.sep + "ready");
|
|
16533
|
+
ensureDir(readyDir);
|
|
16534
|
+
const fileName = path6.basename(filePath);
|
|
16535
|
+
newPath = path6.join(readyDir, fileName);
|
|
16536
|
+
}
|
|
16537
|
+
return { newPath, newContent };
|
|
16538
|
+
}
|
|
16539
|
+
function findWorkItem(dir, id) {
|
|
16540
|
+
const wis = discoverWorkItems(dir);
|
|
16541
|
+
return wis.find((w) => w.id.toLowerCase() === id.toLowerCase()) ?? null;
|
|
16542
|
+
}
|
|
16543
|
+
async function runReady(id, opts = {}) {
|
|
16544
|
+
const dir = process.cwd();
|
|
16545
|
+
intro2("kaddo ready " + id);
|
|
16546
|
+
const config = loadConfig(dir);
|
|
16547
|
+
if (!config) {
|
|
16548
|
+
log2.error("Kaddo is not initialized. Run `kaddo init` first.");
|
|
16549
|
+
process.exit(1);
|
|
16550
|
+
}
|
|
16551
|
+
const wi = findWorkItem(dir, id);
|
|
16552
|
+
if (!wi) {
|
|
16553
|
+
log2.error(`Work Item ${id} not found.`);
|
|
16554
|
+
log2.info("Run `kaddo history` or check knowledge/delivery/work-items/ for available IDs.");
|
|
16555
|
+
process.exit(1);
|
|
16556
|
+
}
|
|
16557
|
+
if (wi.lifecycle === "ready") {
|
|
16558
|
+
log2.info(`Work Item ${wi.id} is already ready.`);
|
|
16559
|
+
log2.info("Suggested next: kaddo context && kaddo understand");
|
|
16560
|
+
outro2("Nothing to do.");
|
|
16561
|
+
return;
|
|
16562
|
+
}
|
|
16563
|
+
if (wi.lifecycle !== "draft") {
|
|
16564
|
+
log2.error(`Work Item ${wi.id} is in state "${wi.lifecycle}", not "draft". Only draft Work Items can be marked as ready.`);
|
|
16565
|
+
process.exit(1);
|
|
16566
|
+
}
|
|
16567
|
+
const raw = readFile(wi.filePath);
|
|
16568
|
+
const { data } = matter11(raw);
|
|
16569
|
+
const source = parseWorkItemSource(data);
|
|
16570
|
+
const warnings = validateReadiness(raw, data);
|
|
16571
|
+
log2.info(`Work Item found:`);
|
|
16572
|
+
log2.info(` ${wi.id} \u2014 ${wi.title}`);
|
|
16573
|
+
log2.info("");
|
|
16574
|
+
log2.info(` Status: draft \u2192 ready`);
|
|
16575
|
+
log2.info(` Type: ${wi.type}`);
|
|
16576
|
+
log2.info(` Knowledge level: ${wi.knowledgeLevel || "unset"}`);
|
|
16577
|
+
log2.info(` Domains: ${wi.domains.length > 0 ? wi.domains.join(", ") : "none"}`);
|
|
16578
|
+
log2.info(` Source: ${renderSourceCompact(source)}`);
|
|
16579
|
+
if (wi.codeGlobs.length > 0) {
|
|
16580
|
+
log2.info(` Code ownership:`);
|
|
16581
|
+
for (const g of wi.codeGlobs) log2.info(` - ${g}`);
|
|
16582
|
+
} else {
|
|
16583
|
+
log2.info(` Code ownership: none`);
|
|
16584
|
+
}
|
|
16585
|
+
if (warnings.length > 0) {
|
|
16586
|
+
log2.warn("");
|
|
16587
|
+
log2.warn("This Work Item may not be ready:");
|
|
16588
|
+
for (const w of warnings) {
|
|
16589
|
+
log2.warn(` - ${w.message}`);
|
|
16590
|
+
}
|
|
16591
|
+
}
|
|
16592
|
+
if (!opts.yes) {
|
|
16593
|
+
log2.info("");
|
|
16594
|
+
const proceed = await confirm2({ message: "Mark this Work Item as ready for implementation?" });
|
|
16595
|
+
if (!proceed) {
|
|
16596
|
+
cancel2("Cancelled.");
|
|
16597
|
+
return;
|
|
16598
|
+
}
|
|
16599
|
+
}
|
|
16600
|
+
const { newPath, newContent } = transitionToReady(wi.filePath);
|
|
16601
|
+
if (newPath !== wi.filePath) {
|
|
16602
|
+
writeFile(newPath, newContent);
|
|
16603
|
+
fs4.unlinkSync(wi.filePath);
|
|
16604
|
+
log2.success(`Updated status: ready`);
|
|
16605
|
+
log2.success(`Moved file:`);
|
|
16606
|
+
log2.info(` ${path6.relative(dir, wi.filePath)}`);
|
|
16607
|
+
log2.info(` \u2192 ${path6.relative(dir, newPath)}`);
|
|
16608
|
+
} else {
|
|
16609
|
+
writeFile(wi.filePath, newContent);
|
|
16610
|
+
log2.success(`Updated status: ready`);
|
|
16611
|
+
}
|
|
16612
|
+
log2.info("");
|
|
16613
|
+
log2.info("Run `kaddo context && kaddo understand` to refresh the handoff.");
|
|
16614
|
+
outro2(`Work Item ${wi.id} is ready.`);
|
|
16615
|
+
}
|
|
16616
|
+
|
|
16442
16617
|
// src/index.ts
|
|
16443
16618
|
var require2 = createRequire(import.meta.url);
|
|
16444
16619
|
var { version } = require2("../package.json");
|
|
@@ -16456,12 +16631,15 @@ program.command("bootstrap").description("Build the initial knowledge base for a
|
|
|
16456
16631
|
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) => {
|
|
16457
16632
|
await runCreate(type ?? "", opts);
|
|
16458
16633
|
});
|
|
16634
|
+
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) => {
|
|
16635
|
+
await runReady(id, opts);
|
|
16636
|
+
});
|
|
16459
16637
|
var capsuleCmd = program.command("capsule").description("Export this project as a Knowledge Capsule, or import an external one as context");
|
|
16460
16638
|
capsuleCmd.command("export").description("Write a Knowledge Capsule about this project to .kaddo/exports/").action(() => {
|
|
16461
16639
|
runCapsuleExport();
|
|
16462
16640
|
});
|
|
16463
|
-
capsuleCmd.command("add <path>").description("Register an external Knowledge Capsule as project context (.kaddo/external.yml)").action((
|
|
16464
|
-
runCapsuleAdd(
|
|
16641
|
+
capsuleCmd.command("add <path>").description("Register an external Knowledge Capsule as project context (.kaddo/external.yml)").action((path7) => {
|
|
16642
|
+
runCapsuleAdd(path7);
|
|
16465
16643
|
});
|
|
16466
16644
|
var graphCmd = program.command("graph").description("Export the lightweight, file-based knowledge graph of the project");
|
|
16467
16645
|
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) => {
|