@kaddo/cli 3.6.0 → 3.7.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 +203 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1907,7 +1907,9 @@ existing Work Item file to refine.
|
|
|
1907
1907
|
|
|
1908
1908
|
## Expected Output
|
|
1909
1909
|
|
|
1910
|
-
A refined Work Item intended to be saved
|
|
1910
|
+
A refined Work Item intended to be saved under the lifecycle workspace:
|
|
1911
|
+
\`knowledge/delivery/work-items/draft/\`, \`ready/\`, \`in-progress/\`, \`blocked/\`,
|
|
1912
|
+
\`completed/\` or \`archived/\`.
|
|
1911
1913
|
|
|
1912
1914
|
## Instructions
|
|
1913
1915
|
|
|
@@ -1915,9 +1917,10 @@ A refined Work Item intended to be saved as \`knowledge/delivery/work-items/*.md
|
|
|
1915
1917
|
2. Split the candidate if it is too large for a single Work Item.
|
|
1916
1918
|
3. Validate the Knowledge Level (K0\u2013K4) and propose a different one if needed.
|
|
1917
1919
|
4. Propose acceptance criteria.
|
|
1918
|
-
5. Propose
|
|
1919
|
-
6.
|
|
1920
|
-
7.
|
|
1920
|
+
5. Propose Out of scope and Validation sections.
|
|
1921
|
+
6. Propose a Definition of Done.
|
|
1922
|
+
7. Identify open questions and assumptions.
|
|
1923
|
+
8. Suggest ownership candidates (code globs) if evident.
|
|
1921
1924
|
|
|
1922
1925
|
## Constraints
|
|
1923
1926
|
|
|
@@ -1939,6 +1942,10 @@ A refined Work Item intended to be saved as \`knowledge/delivery/work-items/*.md
|
|
|
1939
1942
|
|
|
1940
1943
|
**Acceptance criteria:**
|
|
1941
1944
|
|
|
1945
|
+
**Out of scope:**
|
|
1946
|
+
|
|
1947
|
+
**Validation:**
|
|
1948
|
+
|
|
1942
1949
|
**Definition of Done:**
|
|
1943
1950
|
|
|
1944
1951
|
**Open questions:**
|
|
@@ -1948,7 +1955,9 @@ A refined Work Item intended to be saved as \`knowledge/delivery/work-items/*.md
|
|
|
1948
1955
|
|
|
1949
1956
|
## Where to Save the Result
|
|
1950
1957
|
|
|
1951
|
-
Save
|
|
1958
|
+
Save new output as a draft under \`knowledge/delivery/work-items/draft/\` unless a human
|
|
1959
|
+
explicitly asks for another lifecycle state. Treat only \`draft\`, \`ready\`, \`in-progress\`
|
|
1960
|
+
and \`blocked\` as active work; \`completed\` and \`archived\` are historical knowledge.
|
|
1952
1961
|
|
|
1953
1962
|
## Delivery workflow
|
|
1954
1963
|
|
|
@@ -3182,6 +3191,7 @@ function roadmapStats(markdown, materialized) {
|
|
|
3182
3191
|
|
|
3183
3192
|
// src/commands/create.ts
|
|
3184
3193
|
var WORK_ITEMS_DIR = "knowledge/delivery/work-items";
|
|
3194
|
+
var DRAFT_DIR = `${WORK_ITEMS_DIR}/draft`;
|
|
3185
3195
|
var ROADMAP_PATH = "knowledge/delivery/roadmap.md";
|
|
3186
3196
|
function printStateGuidance(dir) {
|
|
3187
3197
|
let config;
|
|
@@ -3200,13 +3210,20 @@ function printStateGuidance(dir) {
|
|
|
3200
3210
|
function nextWorkItemId(dir) {
|
|
3201
3211
|
const wiDir = join(dir, WORK_ITEMS_DIR);
|
|
3202
3212
|
if (!exists(wiDir)) return "WI-001";
|
|
3203
|
-
|
|
3204
|
-
const
|
|
3205
|
-
const
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3213
|
+
let max = 0;
|
|
3214
|
+
const walk = (d) => {
|
|
3215
|
+
for (const entry of readDir(d)) {
|
|
3216
|
+
const full = join(d, entry);
|
|
3217
|
+
if (isFile(full)) {
|
|
3218
|
+
const m = entry.match(/WI-(\d+)/);
|
|
3219
|
+
if (m) max = Math.max(max, parseInt(m[1], 10));
|
|
3220
|
+
} else if (!entry.startsWith(".")) {
|
|
3221
|
+
walk(full);
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
};
|
|
3225
|
+
walk(wiDir);
|
|
3226
|
+
return `WI-${String(max + 1).padStart(3, "0")}`;
|
|
3210
3227
|
}
|
|
3211
3228
|
function slugify(s) {
|
|
3212
3229
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 50);
|
|
@@ -3222,7 +3239,9 @@ function buildFrontMatter(id, type, level, title, answers) {
|
|
|
3222
3239
|
`id: ${id}`,
|
|
3223
3240
|
`title: "${title}"`,
|
|
3224
3241
|
`knowledge_level: ${level}`,
|
|
3225
|
-
`status:
|
|
3242
|
+
`status: draft`,
|
|
3243
|
+
`phase: now`,
|
|
3244
|
+
`initiative:`,
|
|
3226
3245
|
`domains: []`,
|
|
3227
3246
|
`code: []`,
|
|
3228
3247
|
`created_at: ${today}`,
|
|
@@ -3274,6 +3293,14 @@ ${answers.design}
|
|
|
3274
3293
|
${answers.risks}
|
|
3275
3294
|
`);
|
|
3276
3295
|
}
|
|
3296
|
+
sections.push(`## Out of scope
|
|
3297
|
+
|
|
3298
|
+
_Not included in this Work Item._
|
|
3299
|
+
`);
|
|
3300
|
+
sections.push(`## Validation
|
|
3301
|
+
|
|
3302
|
+
_How will this be validated?_
|
|
3303
|
+
`);
|
|
3277
3304
|
if (qualityGate.length > 0) {
|
|
3278
3305
|
sections.push(`## Definition of Done
|
|
3279
3306
|
|
|
@@ -3298,7 +3325,9 @@ function buildModuleFrontMatter(id, modType, title, answers) {
|
|
|
3298
3325
|
`id: ${id}`,
|
|
3299
3326
|
`title: "${title}"`,
|
|
3300
3327
|
`knowledge_level: ${modType.knowledgeLevel}`,
|
|
3301
|
-
`status:
|
|
3328
|
+
`status: draft`,
|
|
3329
|
+
`phase: now`,
|
|
3330
|
+
`initiative:`,
|
|
3302
3331
|
`domains: []`,
|
|
3303
3332
|
`code: []`,
|
|
3304
3333
|
`created_at: ${today}`,
|
|
@@ -3330,6 +3359,14 @@ ${answer}
|
|
|
3330
3359
|
${modType.qualityGate.map((g) => `- [ ] ${g}`).join("\n")}
|
|
3331
3360
|
`);
|
|
3332
3361
|
}
|
|
3362
|
+
sections.push(`## Out of scope
|
|
3363
|
+
|
|
3364
|
+
_Not included in this Work Item._
|
|
3365
|
+
`);
|
|
3366
|
+
sections.push(`## Validation
|
|
3367
|
+
|
|
3368
|
+
_How will this be validated?_
|
|
3369
|
+
`);
|
|
3333
3370
|
sections.push(`## Learning
|
|
3334
3371
|
|
|
3335
3372
|
_What did we learn from this change? Update after completion._
|
|
@@ -3379,7 +3416,7 @@ async function runCreate(type, opts = {}) {
|
|
|
3379
3416
|
const id = nextWorkItemId(dir);
|
|
3380
3417
|
const slug = slugify(title);
|
|
3381
3418
|
const fileName = `${id}-${slug}.md`;
|
|
3382
|
-
const filePath = join(dir,
|
|
3419
|
+
const filePath = join(dir, DRAFT_DIR, fileName);
|
|
3383
3420
|
const frontMatter2 = buildFrontMatter(id, workItemType, level, title.trim(), answers);
|
|
3384
3421
|
const body = buildBody(workItemType, level, title.trim(), answers, levelDef.qualityGate);
|
|
3385
3422
|
const content = `${frontMatter2}
|
|
@@ -3390,7 +3427,8 @@ ${body}`;
|
|
|
3390
3427
|
process.exit(1);
|
|
3391
3428
|
}
|
|
3392
3429
|
writeFile(filePath, content);
|
|
3393
|
-
log2.success(`Created ${
|
|
3430
|
+
log2.success(`Created ${DRAFT_DIR}/${fileName}`);
|
|
3431
|
+
log2.info(`New Work Items start in \`draft\`. Move to \`ready\` when scope and acceptance are set.`);
|
|
3394
3432
|
log2.info(`Add code globs to the front matter \`code:\` field to enable Guard Lite.`);
|
|
3395
3433
|
outro2(`Work item ${id} created.`);
|
|
3396
3434
|
}
|
|
@@ -3419,14 +3457,14 @@ async function runCreateModule(dir, modType) {
|
|
|
3419
3457
|
const id = nextWorkItemId(dir);
|
|
3420
3458
|
const slug = slugify(title);
|
|
3421
3459
|
const fileName = `${id}-${slug}.md`;
|
|
3422
|
-
const filePath = join(dir,
|
|
3460
|
+
const filePath = join(dir, DRAFT_DIR, fileName);
|
|
3423
3461
|
const frontMatter2 = buildModuleFrontMatter(id, modType, title.trim(), answers);
|
|
3424
3462
|
const body = buildModuleBody(modType, title.trim(), answers);
|
|
3425
3463
|
const content = `${frontMatter2}
|
|
3426
3464
|
|
|
3427
3465
|
${body}`;
|
|
3428
3466
|
writeFile(filePath, content);
|
|
3429
|
-
log2.success(`Created ${
|
|
3467
|
+
log2.success(`Created ${DRAFT_DIR}/${fileName}`);
|
|
3430
3468
|
log2.info(`Add code globs to the front matter \`code:\` field to enable Guard Lite.`);
|
|
3431
3469
|
outro2(`Work item ${id} created.`);
|
|
3432
3470
|
}
|
|
@@ -3444,13 +3482,16 @@ function resolveCandidateLevel(candidate, type) {
|
|
|
3444
3482
|
function buildRoadmapFrontMatter(id, type, level, title, candidate, answers) {
|
|
3445
3483
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
3446
3484
|
const summary = (answers.problem?.split(".")[0] ?? candidate.expectedValue ?? title).trim();
|
|
3485
|
+
const initiative = candidate.initiative?.title ?? candidate.initiative?.id ?? "";
|
|
3447
3486
|
const lines = [
|
|
3448
3487
|
"---",
|
|
3449
3488
|
`type: ${type}`,
|
|
3450
3489
|
`id: ${id}`,
|
|
3451
3490
|
`title: "${title}"`,
|
|
3452
3491
|
`knowledge_level: ${level}`,
|
|
3453
|
-
`status:
|
|
3492
|
+
`status: draft`,
|
|
3493
|
+
`phase: now`,
|
|
3494
|
+
`initiative: "${initiative.replace(/"/g, "'")}"`,
|
|
3454
3495
|
`domains: []`,
|
|
3455
3496
|
`code: []`,
|
|
3456
3497
|
`created_at: ${today}`,
|
|
@@ -3525,6 +3566,14 @@ ${candidate.notes}
|
|
|
3525
3566
|
sections.push(`## Open Questions
|
|
3526
3567
|
|
|
3527
3568
|
${formatList(candidate.openQuestions)}
|
|
3569
|
+
`);
|
|
3570
|
+
sections.push(`## Out of scope
|
|
3571
|
+
|
|
3572
|
+
_Not included in this Work Item._
|
|
3573
|
+
`);
|
|
3574
|
+
sections.push(`## Validation
|
|
3575
|
+
|
|
3576
|
+
_How will this be validated?_
|
|
3528
3577
|
`);
|
|
3529
3578
|
if (qualityGate.length > 0)
|
|
3530
3579
|
sections.push(`## Definition of Done
|
|
@@ -3607,8 +3656,8 @@ async function runCreateFromRoadmap(dir, cliType) {
|
|
|
3607
3656
|
}
|
|
3608
3657
|
const id = nextWorkItemId(dir);
|
|
3609
3658
|
const { fileName, content } = buildRoadmapWorkItem({ id, type, level, candidate, answers });
|
|
3610
|
-
writeFile(join(dir,
|
|
3611
|
-
log2.success(`Created ${
|
|
3659
|
+
writeFile(join(dir, DRAFT_DIR, fileName), content);
|
|
3660
|
+
log2.success(`Created ${DRAFT_DIR}/${fileName}`);
|
|
3612
3661
|
log2.info(`Traced to roadmap candidate ${candidate.id}${candidate.initiative?.id ? ` (initiative ${candidate.initiative.id})` : ""}.`);
|
|
3613
3662
|
log2.info(`Add code globs to the front matter \`code:\` field to enable Guard Lite.`);
|
|
3614
3663
|
outro2(`Work item ${id} created from roadmap.`);
|
|
@@ -3676,7 +3725,9 @@ function parseArtifact(filePath, raw) {
|
|
|
3676
3725
|
knowledgeLevel: String(data.knowledge_level ?? ""),
|
|
3677
3726
|
codeGlobs: globs,
|
|
3678
3727
|
domains: Array.isArray(data.domains) ? data.domains : [],
|
|
3679
|
-
status: String(data.status ?? "")
|
|
3728
|
+
status: String(data.status ?? ""),
|
|
3729
|
+
phase: String(data.phase ?? ""),
|
|
3730
|
+
initiative: String(data.initiative ?? data.source_initiative ?? "")
|
|
3680
3731
|
};
|
|
3681
3732
|
} catch {
|
|
3682
3733
|
return null;
|
|
@@ -4511,6 +4562,52 @@ function renderLayersMarkdown(layers) {
|
|
|
4511
4562
|
return lines.join("\n").trimEnd();
|
|
4512
4563
|
}
|
|
4513
4564
|
|
|
4565
|
+
// src/core/lifecycle.ts
|
|
4566
|
+
var LIFECYCLE_STATES = [
|
|
4567
|
+
"draft",
|
|
4568
|
+
"ready",
|
|
4569
|
+
"in-progress",
|
|
4570
|
+
"blocked",
|
|
4571
|
+
"completed",
|
|
4572
|
+
"archived"
|
|
4573
|
+
];
|
|
4574
|
+
var ACTIVE_STATES = ["draft", "ready", "in-progress", "blocked"];
|
|
4575
|
+
var LEGACY_STATUS_MAP = {
|
|
4576
|
+
done: "completed",
|
|
4577
|
+
cancelled: "archived",
|
|
4578
|
+
canceled: "archived",
|
|
4579
|
+
"in-progress": "in-progress"
|
|
4580
|
+
};
|
|
4581
|
+
var STATE_SET = new Set(LIFECYCLE_STATES);
|
|
4582
|
+
function isLifecycleState(s) {
|
|
4583
|
+
return STATE_SET.has(s);
|
|
4584
|
+
}
|
|
4585
|
+
function isActiveState(s) {
|
|
4586
|
+
return ACTIVE_STATES.includes(s);
|
|
4587
|
+
}
|
|
4588
|
+
function lifecycleFolderOf(filePath) {
|
|
4589
|
+
const p2 = filePath.replace(/\\/g, "/");
|
|
4590
|
+
const m = p2.match(/\/delivery\/work-items\/([^/]+)\//);
|
|
4591
|
+
if (m && isLifecycleState(m[1])) return m[1];
|
|
4592
|
+
return null;
|
|
4593
|
+
}
|
|
4594
|
+
function lifecycleStateOf(item) {
|
|
4595
|
+
const status = (item.status ?? "").trim().toLowerCase();
|
|
4596
|
+
if (isLifecycleState(status)) return status;
|
|
4597
|
+
if (status && LEGACY_STATUS_MAP[status]) return LEGACY_STATUS_MAP[status];
|
|
4598
|
+
const folder = lifecycleFolderOf(item.filePath ?? "");
|
|
4599
|
+
if (folder) return folder;
|
|
4600
|
+
return "ready";
|
|
4601
|
+
}
|
|
4602
|
+
function emptyLifecycleCounts() {
|
|
4603
|
+
return Object.fromEntries(LIFECYCLE_STATES.map((s) => [s, 0]));
|
|
4604
|
+
}
|
|
4605
|
+
function lifecycleCounts(states) {
|
|
4606
|
+
const counts = emptyLifecycleCounts();
|
|
4607
|
+
for (const s of states) counts[s]++;
|
|
4608
|
+
return counts;
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4514
4611
|
// src/core/project-explain.ts
|
|
4515
4612
|
var ARCH_DIR3 = "knowledge";
|
|
4516
4613
|
function first(values) {
|
|
@@ -4598,15 +4695,27 @@ function buildProjectExplanation(dir) {
|
|
|
4598
4695
|
id: a.id || a.title,
|
|
4599
4696
|
title: a.title,
|
|
4600
4697
|
status: a.status,
|
|
4698
|
+
lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
|
|
4699
|
+
initiative: a.initiative,
|
|
4601
4700
|
knowledgeLevel: a.knowledgeLevel,
|
|
4602
4701
|
hasOwnership: a.codeGlobs.length > 0,
|
|
4603
4702
|
domains: a.domains
|
|
4604
4703
|
}));
|
|
4704
|
+
const byState = lifecycleCounts(items.map((i) => i.lifecycle));
|
|
4705
|
+
const initiativeMap = /* @__PURE__ */ new Map();
|
|
4706
|
+
for (const i of items) {
|
|
4707
|
+
const name = i.initiative || "Unassigned";
|
|
4708
|
+
if (!initiativeMap.has(name)) initiativeMap.set(name, emptyLifecycleCounts());
|
|
4709
|
+
initiativeMap.get(name)[i.lifecycle]++;
|
|
4710
|
+
}
|
|
4711
|
+
const initiatives = [...initiativeMap.entries()].map(([name, states]) => ({ name, states })).sort((a, b) => a.name.localeCompare(b.name));
|
|
4605
4712
|
const workItems = {
|
|
4606
4713
|
total: items.length,
|
|
4607
|
-
inProgress: items.filter((i) => i.
|
|
4714
|
+
inProgress: items.filter((i) => i.lifecycle === "in-progress").length,
|
|
4608
4715
|
done: items.filter((i) => i.status === "done").length,
|
|
4609
4716
|
cancelled: items.filter((i) => i.status === "cancelled").length,
|
|
4717
|
+
byState,
|
|
4718
|
+
initiatives,
|
|
4610
4719
|
items
|
|
4611
4720
|
};
|
|
4612
4721
|
const withOwnership = items.filter((i) => i.hasOwnership).length;
|
|
@@ -4675,6 +4784,14 @@ function buildProjectExplanation(dir) {
|
|
|
4675
4784
|
function stateLabel(state) {
|
|
4676
4785
|
return state === "pre-ai" ? "pre-ai" : state;
|
|
4677
4786
|
}
|
|
4787
|
+
var LIFECYCLE_LABEL = {
|
|
4788
|
+
draft: "Draft",
|
|
4789
|
+
ready: "Ready",
|
|
4790
|
+
"in-progress": "In Progress",
|
|
4791
|
+
blocked: "Blocked",
|
|
4792
|
+
completed: "Completed",
|
|
4793
|
+
archived: "Archived"
|
|
4794
|
+
};
|
|
4678
4795
|
function renderExplanationHuman(exp) {
|
|
4679
4796
|
const lines = [];
|
|
4680
4797
|
lines.push("# Project Explanation");
|
|
@@ -4722,9 +4839,29 @@ function renderExplanationHuman(exp) {
|
|
|
4722
4839
|
`- Ownership coverage: ${exp.ownership.workItemsWithOwnership}/${exp.ownership.workItemsTotal} work items`
|
|
4723
4840
|
);
|
|
4724
4841
|
lines.push("");
|
|
4725
|
-
|
|
4842
|
+
if (exp.workItems.total > 0) {
|
|
4843
|
+
lines.push("## Work Items");
|
|
4844
|
+
for (const s of LIFECYCLE_STATES) {
|
|
4845
|
+
lines.push(`- ${LIFECYCLE_LABEL[s]}: ${exp.workItems.byState[s]}`);
|
|
4846
|
+
}
|
|
4847
|
+
lines.push("");
|
|
4848
|
+
const grouped = exp.workItems.initiatives.filter(
|
|
4849
|
+
(g) => LIFECYCLE_STATES.some((s) => g.states[s] > 0)
|
|
4850
|
+
);
|
|
4851
|
+
if (grouped.length > 0) {
|
|
4852
|
+
lines.push("## Work Items by Initiative");
|
|
4853
|
+
for (const g of grouped) {
|
|
4854
|
+
const parts = LIFECYCLE_STATES.filter((s) => g.states[s] > 0).map(
|
|
4855
|
+
(s) => `${LIFECYCLE_LABEL[s]}: ${g.states[s]}`
|
|
4856
|
+
);
|
|
4857
|
+
lines.push(`- ${g.name} \u2014 ${parts.join(" \xB7 ")}`);
|
|
4858
|
+
}
|
|
4859
|
+
lines.push("");
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
const active = exp.workItems.items.filter((i) => i.lifecycle === "in-progress");
|
|
4726
4863
|
if (active.length > 0) {
|
|
4727
|
-
lines.push("##
|
|
4864
|
+
lines.push("## In Progress");
|
|
4728
4865
|
for (const wi of active) {
|
|
4729
4866
|
const level = wi.knowledgeLevel ? ` [${wi.knowledgeLevel}]` : "";
|
|
4730
4867
|
const owned = wi.hasOwnership ? " \u25CF" : " \u25CB";
|
|
@@ -5036,6 +5173,7 @@ function toContextWorkItem(a) {
|
|
|
5036
5173
|
type: a.type,
|
|
5037
5174
|
title: a.title,
|
|
5038
5175
|
status: a.status,
|
|
5176
|
+
lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
|
|
5039
5177
|
knowledgeLevel: a.knowledgeLevel,
|
|
5040
5178
|
domains: a.domains
|
|
5041
5179
|
};
|
|
@@ -5043,6 +5181,9 @@ function toContextWorkItem(a) {
|
|
|
5043
5181
|
function toContextArtifact(a) {
|
|
5044
5182
|
return { id: a.id, type: a.type, title: a.title, summary: a.summary, codeGlobs: a.codeGlobs };
|
|
5045
5183
|
}
|
|
5184
|
+
function isDeliveryWorkItem(a) {
|
|
5185
|
+
return a.filePath.replace(/\\/g, "/").includes("/delivery/work-items/") && Boolean(a.type);
|
|
5186
|
+
}
|
|
5046
5187
|
function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
5047
5188
|
const missing = [];
|
|
5048
5189
|
const scanJson = readScanJson(dir);
|
|
@@ -5065,7 +5206,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
5065
5206
|
const archPath = join(dir, ARCH_DIR5);
|
|
5066
5207
|
const allArtifacts = exists(archPath) ? readArtifacts(archPath) : [];
|
|
5067
5208
|
const workItems = allArtifacts.filter(
|
|
5068
|
-
(a) => a
|
|
5209
|
+
(a) => isDeliveryWorkItem(a) && isActiveState(lifecycleStateOf({ status: a.status, filePath: a.filePath }))
|
|
5069
5210
|
);
|
|
5070
5211
|
if (workItems.length === 0) {
|
|
5071
5212
|
missing.push("No work items found.");
|
|
@@ -5102,7 +5243,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
5102
5243
|
roadmapSummary,
|
|
5103
5244
|
inventoryAvailable,
|
|
5104
5245
|
workItems: workItems.map(toContextWorkItem),
|
|
5105
|
-
artifacts:
|
|
5246
|
+
artifacts: allArtifacts.filter((a) => a.codeGlobs.length > 0).map(toContextArtifact)
|
|
5106
5247
|
},
|
|
5107
5248
|
layers,
|
|
5108
5249
|
roadmap,
|
|
@@ -5195,17 +5336,17 @@ function renderContextPack(pack) {
|
|
|
5195
5336
|
}
|
|
5196
5337
|
}
|
|
5197
5338
|
parts.push((knowledge.roadmapSummary || "No roadmap baseline found.") + "\n");
|
|
5198
|
-
parts.push("##
|
|
5339
|
+
parts.push("## Active Work Items\n");
|
|
5199
5340
|
if (knowledge.workItems.length > 0) {
|
|
5200
5341
|
const lines = knowledge.workItems.map((wi) => {
|
|
5201
5342
|
const level = wi.knowledgeLevel ? ` [${wi.knowledgeLevel}]` : "";
|
|
5202
|
-
const status = wi.status ? ` (${wi.status})` : "";
|
|
5343
|
+
const status = wi.lifecycle ? ` (${wi.lifecycle})` : wi.status ? ` (${wi.status})` : "";
|
|
5203
5344
|
const domains = wi.domains.length > 0 ? ` \xB7 domains: ${wi.domains.join(", ")}` : "";
|
|
5204
5345
|
return `- ${wi.id || wi.title} [${wi.type}]${level}${status} \u2014 ${wi.title}${domains}`;
|
|
5205
5346
|
});
|
|
5206
5347
|
parts.push(lines.join("\n") + "\n");
|
|
5207
5348
|
} else {
|
|
5208
|
-
parts.push("No work items found.\n");
|
|
5349
|
+
parts.push("No active work items found.\n");
|
|
5209
5350
|
}
|
|
5210
5351
|
parts.push("## Artifacts and Ownership\n");
|
|
5211
5352
|
if (knowledge.artifacts.length > 0) {
|
|
@@ -5457,7 +5598,9 @@ function toActive(a) {
|
|
|
5457
5598
|
function activeWorkItems(dir) {
|
|
5458
5599
|
const archDir = join(dir, "knowledge");
|
|
5459
5600
|
if (!exists(archDir)) return [];
|
|
5460
|
-
return readArtifacts(archDir).filter(
|
|
5601
|
+
return readArtifacts(archDir).filter(
|
|
5602
|
+
(a) => isWorkItem(a) && lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "in-progress"
|
|
5603
|
+
).map(toActive);
|
|
5461
5604
|
}
|
|
5462
5605
|
function branchPrefix(type) {
|
|
5463
5606
|
switch (type) {
|
|
@@ -5575,6 +5718,24 @@ function runUnderstand() {
|
|
|
5575
5718
|
if (groupAgents.length > 0) {
|
|
5576
5719
|
console.log(`Agents for this phase: ${groupAgents.join(", ")}`);
|
|
5577
5720
|
}
|
|
5721
|
+
const exp = buildProjectExplanation(dir);
|
|
5722
|
+
if (exp.workItems.total > 0) {
|
|
5723
|
+
const bs = exp.workItems.byState;
|
|
5724
|
+
console.log("");
|
|
5725
|
+
console.log("Current active work:");
|
|
5726
|
+
console.log(` Draft: ${bs.draft} Ready: ${bs.ready} In Progress: ${bs["in-progress"]} Blocked: ${bs.blocked}`);
|
|
5727
|
+
const firstReady = exp.workItems.items.find((i) => i.lifecycle === "ready");
|
|
5728
|
+
const firstInProgress = exp.workItems.items.find((i) => i.lifecycle === "in-progress");
|
|
5729
|
+
if (firstInProgress) {
|
|
5730
|
+
console.log(` \u2192 Continue ${firstInProgress.id} \u2014 ${firstInProgress.title} (in progress).`);
|
|
5731
|
+
} else if (firstReady) {
|
|
5732
|
+
console.log(` \u2192 Recommended next step: start ${firstReady.id} \u2014 ${firstReady.title}.`);
|
|
5733
|
+
} else if (bs.draft > 0) {
|
|
5734
|
+
console.log(" \u2192 Refine a draft Work Item to `ready` (scope + acceptance defined).");
|
|
5735
|
+
} else if (bs.blocked > 0) {
|
|
5736
|
+
console.log(" \u2192 All active work is blocked. Resolve the blockers to move forward.");
|
|
5737
|
+
}
|
|
5738
|
+
}
|
|
5578
5739
|
const active = activeWorkItems(dir);
|
|
5579
5740
|
if (active.length > 0) {
|
|
5580
5741
|
console.log("");
|
|
@@ -6492,11 +6653,12 @@ var WORK_ITEM = `---
|
|
|
6492
6653
|
type: feature
|
|
6493
6654
|
id: WI-001
|
|
6494
6655
|
title: "Short, action-oriented title"
|
|
6495
|
-
status:
|
|
6656
|
+
status: draft
|
|
6496
6657
|
knowledge_level: K2
|
|
6497
6658
|
source: manual
|
|
6498
6659
|
source_id:
|
|
6499
|
-
|
|
6660
|
+
phase: now
|
|
6661
|
+
initiative:
|
|
6500
6662
|
domains: []
|
|
6501
6663
|
capabilities: []
|
|
6502
6664
|
code: []
|
|
@@ -6527,6 +6689,14 @@ _Optional. Key decisions or approach. Keep it minimal at low knowledge levels._
|
|
|
6527
6689
|
|
|
6528
6690
|
_Optional. What could go wrong?_
|
|
6529
6691
|
|
|
6692
|
+
## Out of scope
|
|
6693
|
+
|
|
6694
|
+
_What is intentionally not included in this Work Item?_
|
|
6695
|
+
|
|
6696
|
+
## Validation
|
|
6697
|
+
|
|
6698
|
+
_How will this be validated?_
|
|
6699
|
+
|
|
6530
6700
|
## Definition of Done
|
|
6531
6701
|
|
|
6532
6702
|
- [ ] Code merged
|