@kaddo/mcp 3.59.0 → 3.61.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 +2393 -738
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,85 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
|
|
28
|
+
// ../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
|
|
29
|
+
var require_src = __commonJS({
|
|
30
|
+
"../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js"(exports, module) {
|
|
31
|
+
"use strict";
|
|
32
|
+
var ESC = "\x1B";
|
|
33
|
+
var CSI = `${ESC}[`;
|
|
34
|
+
var beep = "\x07";
|
|
35
|
+
var cursor = {
|
|
36
|
+
to(x2, y) {
|
|
37
|
+
if (!y) return `${CSI}${x2 + 1}G`;
|
|
38
|
+
return `${CSI}${y + 1};${x2 + 1}H`;
|
|
39
|
+
},
|
|
40
|
+
move(x2, y) {
|
|
41
|
+
let ret = "";
|
|
42
|
+
if (x2 < 0) ret += `${CSI}${-x2}D`;
|
|
43
|
+
else if (x2 > 0) ret += `${CSI}${x2}C`;
|
|
44
|
+
if (y < 0) ret += `${CSI}${-y}A`;
|
|
45
|
+
else if (y > 0) ret += `${CSI}${y}B`;
|
|
46
|
+
return ret;
|
|
47
|
+
},
|
|
48
|
+
up: (count = 1) => `${CSI}${count}A`,
|
|
49
|
+
down: (count = 1) => `${CSI}${count}B`,
|
|
50
|
+
forward: (count = 1) => `${CSI}${count}C`,
|
|
51
|
+
backward: (count = 1) => `${CSI}${count}D`,
|
|
52
|
+
nextLine: (count = 1) => `${CSI}E`.repeat(count),
|
|
53
|
+
prevLine: (count = 1) => `${CSI}F`.repeat(count),
|
|
54
|
+
left: `${CSI}G`,
|
|
55
|
+
hide: `${CSI}?25l`,
|
|
56
|
+
show: `${CSI}?25h`,
|
|
57
|
+
save: `${ESC}7`,
|
|
58
|
+
restore: `${ESC}8`
|
|
59
|
+
};
|
|
60
|
+
var scroll = {
|
|
61
|
+
up: (count = 1) => `${CSI}S`.repeat(count),
|
|
62
|
+
down: (count = 1) => `${CSI}T`.repeat(count)
|
|
63
|
+
};
|
|
64
|
+
var erase = {
|
|
65
|
+
screen: `${CSI}2J`,
|
|
66
|
+
up: (count = 1) => `${CSI}1J`.repeat(count),
|
|
67
|
+
down: (count = 1) => `${CSI}J`.repeat(count),
|
|
68
|
+
line: `${CSI}2K`,
|
|
69
|
+
lineEnd: `${CSI}K`,
|
|
70
|
+
lineStart: `${CSI}1K`,
|
|
71
|
+
lines(count) {
|
|
72
|
+
let clear = "";
|
|
73
|
+
for (let i = 0; i < count; i++)
|
|
74
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
75
|
+
if (count)
|
|
76
|
+
clear += cursor.left;
|
|
77
|
+
return clear;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
81
|
+
}
|
|
82
|
+
});
|
|
2
83
|
|
|
3
84
|
// src/index.ts
|
|
4
85
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -6,7 +87,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
6
87
|
// src/server.ts
|
|
7
88
|
import { createRequire } from "module";
|
|
8
89
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
-
import { z as
|
|
90
|
+
import { z as z3 } from "zod";
|
|
10
91
|
|
|
11
92
|
// src/catalog.ts
|
|
12
93
|
import matter from "gray-matter";
|
|
@@ -170,7 +251,7 @@ function listFiles(root, relDir, filterExt) {
|
|
|
170
251
|
function sectionParagraph(md, title) {
|
|
171
252
|
const lines = md.split(/\r?\n/);
|
|
172
253
|
const re = new RegExp(`^##\\s+${title}\\s*$`, "i");
|
|
173
|
-
const start = lines.findIndex((
|
|
254
|
+
const start = lines.findIndex((l2) => re.test(l2));
|
|
174
255
|
if (start < 0) return "";
|
|
175
256
|
for (let i = start + 1; i < lines.length; i++) {
|
|
176
257
|
if (/^##\s+/.test(lines[i])) break;
|
|
@@ -231,7 +312,7 @@ function listAgents(root) {
|
|
|
231
312
|
}
|
|
232
313
|
function getAgentPrompt(root, name) {
|
|
233
314
|
const want = name.replace(/\.md$/, "");
|
|
234
|
-
const info = listAgents(root).find((
|
|
315
|
+
const info = listAgents(root).find((a2) => a2.name === want);
|
|
235
316
|
if (!info) return null;
|
|
236
317
|
const content = readText(root, info.path);
|
|
237
318
|
if (content === null) return null;
|
|
@@ -269,7 +350,7 @@ function listSkills(root) {
|
|
|
269
350
|
path: rel
|
|
270
351
|
});
|
|
271
352
|
}
|
|
272
|
-
return out.sort((
|
|
353
|
+
return out.sort((a2, b2) => a2.id.localeCompare(b2.id));
|
|
273
354
|
}
|
|
274
355
|
function getSkill(root, id) {
|
|
275
356
|
const want = id.replace(/\.md$/, "");
|
|
@@ -352,6 +433,7 @@ var languageSchema = z.enum(["en", "es"], {
|
|
|
352
433
|
message: `project.language must be one of: ${PROJECT_LANGUAGES.join(", ")}`
|
|
353
434
|
})
|
|
354
435
|
});
|
|
436
|
+
var multirepoRoleSchema = z.enum(["core", "module"]).optional();
|
|
355
437
|
var configSchema = z.object({
|
|
356
438
|
version: z.union([z.string(), z.number()]).optional(),
|
|
357
439
|
project: z.object({
|
|
@@ -359,11 +441,20 @@ var configSchema = z.object({
|
|
|
359
441
|
state: projectStateSchema.default(DEFAULTS.state),
|
|
360
442
|
structure: structureSchema.default(DEFAULTS.structure),
|
|
361
443
|
language: languageSchema.default(DEFAULTS.language),
|
|
444
|
+
role: multirepoRoleSchema,
|
|
362
445
|
domains: z.array(z.string()).optional()
|
|
363
446
|
}).passthrough().default({}),
|
|
364
447
|
team: z.object({
|
|
365
448
|
size: teamSizeSchema.default(DEFAULTS.teamSize)
|
|
366
449
|
}).passthrough().default({}),
|
|
450
|
+
multirepo: z.object({
|
|
451
|
+
role: multirepoRoleSchema,
|
|
452
|
+
modules_file: z.string().optional(),
|
|
453
|
+
parent_system: z.string().optional()
|
|
454
|
+
}).passthrough().optional(),
|
|
455
|
+
module: z.object({
|
|
456
|
+
id: z.string().optional()
|
|
457
|
+
}).passthrough().optional(),
|
|
367
458
|
knowledge: z.unknown().optional(),
|
|
368
459
|
guard: z.unknown().optional(),
|
|
369
460
|
scan: z.unknown().optional()
|
|
@@ -392,6 +483,12 @@ ${issues}`);
|
|
|
392
483
|
}
|
|
393
484
|
return parsed.data;
|
|
394
485
|
}
|
|
486
|
+
function projectRole(config) {
|
|
487
|
+
return config.project.role ?? config.multirepo?.role;
|
|
488
|
+
}
|
|
489
|
+
function isModule(config) {
|
|
490
|
+
return projectRole(config) === "module";
|
|
491
|
+
}
|
|
395
492
|
|
|
396
493
|
// ../cli/src/services/artifact-reader.ts
|
|
397
494
|
import matter3 from "gray-matter";
|
|
@@ -466,8 +563,8 @@ function isActiveState(s) {
|
|
|
466
563
|
}
|
|
467
564
|
function lifecycleFolderOf(filePath) {
|
|
468
565
|
const p = filePath.replace(/\\/g, "/");
|
|
469
|
-
const
|
|
470
|
-
if (
|
|
566
|
+
const m2 = p.match(/\/delivery\/work-items\/([^/]+)\//);
|
|
567
|
+
if (m2 && isLifecycleState(m2[1])) return m2[1];
|
|
471
568
|
return null;
|
|
472
569
|
}
|
|
473
570
|
function lifecycleStateOf(item) {
|
|
@@ -497,8 +594,8 @@ function relativeTo(dir, filePath) {
|
|
|
497
594
|
const full = toPosix2(filePath);
|
|
498
595
|
return full.startsWith(base + "/") ? full.slice(base.length + 1) : full;
|
|
499
596
|
}
|
|
500
|
-
function isWorkItemArtifact(
|
|
501
|
-
return toPosix2(
|
|
597
|
+
function isWorkItemArtifact(a2) {
|
|
598
|
+
return toPosix2(a2.filePath).includes("/delivery/work-items/") && Boolean(a2.type);
|
|
502
599
|
}
|
|
503
600
|
function classifyLayer(posixPath) {
|
|
504
601
|
if (posixPath.includes("/knowledge/business/")) return "business";
|
|
@@ -509,29 +606,29 @@ function classifyLayer(posixPath) {
|
|
|
509
606
|
if (posixPath.includes("/knowledge/delivery/")) return "delivery";
|
|
510
607
|
return "unknown";
|
|
511
608
|
}
|
|
512
|
-
function enrich(dir,
|
|
513
|
-
const posix = toPosix2(
|
|
514
|
-
const isWi = isWorkItemArtifact(
|
|
609
|
+
function enrich(dir, a2) {
|
|
610
|
+
const posix = toPosix2(a2.filePath);
|
|
611
|
+
const isWi = isWorkItemArtifact(a2);
|
|
515
612
|
return {
|
|
516
|
-
...
|
|
517
|
-
relPath: relativeTo(dir,
|
|
613
|
+
...a2,
|
|
614
|
+
relPath: relativeTo(dir, a2.filePath),
|
|
518
615
|
layer: classifyLayer(posix),
|
|
519
616
|
isWorkItem: isWi,
|
|
520
|
-
lifecycle: isWi ? lifecycleStateOf({ status:
|
|
617
|
+
lifecycle: isWi ? lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) : void 0
|
|
521
618
|
};
|
|
522
619
|
}
|
|
523
620
|
function discoverKnowledge(dir) {
|
|
524
621
|
const archDir = join(dir, ARCH_DIR);
|
|
525
622
|
if (!exists(archDir)) return [];
|
|
526
|
-
return readArtifacts(archDir).map((
|
|
623
|
+
return readArtifacts(archDir).map((a2) => enrich(dir, a2));
|
|
527
624
|
}
|
|
528
625
|
function discoverWorkItems(dir) {
|
|
529
|
-
return discoverKnowledge(dir).filter((
|
|
626
|
+
return discoverKnowledge(dir).filter((a2) => a2.isWorkItem);
|
|
530
627
|
}
|
|
531
628
|
|
|
532
629
|
// ../cli/src/core/delivery-phase.ts
|
|
533
630
|
function layer(layers, name) {
|
|
534
|
-
return layers.find((
|
|
631
|
+
return layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
535
632
|
}
|
|
536
633
|
var NOT_READY_LAYER = ["Missing", "Placeholder", "Weak"];
|
|
537
634
|
function baseComplete(layers) {
|
|
@@ -554,9 +651,9 @@ function determinePhase(input) {
|
|
|
554
651
|
if (active > 0) return "Active Delivery";
|
|
555
652
|
return "Maintenance";
|
|
556
653
|
}
|
|
557
|
-
function ownershipPct(
|
|
558
|
-
if (
|
|
559
|
-
return Math.round(
|
|
654
|
+
function ownershipPct(o2) {
|
|
655
|
+
if (o2.workItemsTotal === 0) return 100;
|
|
656
|
+
return Math.round(o2.workItemsWithOwnership / o2.workItemsTotal * 100);
|
|
560
657
|
}
|
|
561
658
|
function buildReasons(input) {
|
|
562
659
|
const reasons = [];
|
|
@@ -598,19 +695,19 @@ function assessPhase(input) {
|
|
|
598
695
|
let llmInstructions = [];
|
|
599
696
|
switch (phase) {
|
|
600
697
|
case "Discovery": {
|
|
601
|
-
const
|
|
602
|
-
recommendedAgents = [
|
|
603
|
-
nextStep =
|
|
604
|
-
llmInstructions = [`Use the ${
|
|
698
|
+
const m2 = firstMissingLayerAgent(input.layers);
|
|
699
|
+
recommendedAgents = [m2.agent];
|
|
700
|
+
nextStep = m2.step;
|
|
701
|
+
llmInstructions = [`Use the ${m2.agent} to fill the missing base knowledge.`, "Do not write code."];
|
|
605
702
|
break;
|
|
606
703
|
}
|
|
607
704
|
case "Knowledge Refinement": {
|
|
608
|
-
const
|
|
609
|
-
recommendedAgents = [
|
|
610
|
-
nextStep =
|
|
705
|
+
const m2 = firstUnrefinedLayerAgent(input.layers);
|
|
706
|
+
recommendedAgents = [m2.agent];
|
|
707
|
+
nextStep = m2.step;
|
|
611
708
|
llmInstructions = [
|
|
612
709
|
"The baseline files exist but still look like bootstrap placeholders.",
|
|
613
|
-
`Use the ${
|
|
710
|
+
`Use the ${m2.agent} to replace the placeholders with real, project-specific knowledge.`,
|
|
614
711
|
"Do not write code."
|
|
615
712
|
];
|
|
616
713
|
break;
|
|
@@ -691,31 +788,1373 @@ function assessPhase(input) {
|
|
|
691
788
|
return { phase, reasons, recommendedAgents, nextStep, llmInstructions };
|
|
692
789
|
}
|
|
693
790
|
|
|
694
|
-
// ../cli/src/core/capsule.ts
|
|
695
|
-
import matter4 from "gray-matter";
|
|
696
|
-
import { parse as
|
|
791
|
+
// ../cli/src/core/capsule.ts
|
|
792
|
+
import matter4 from "gray-matter";
|
|
793
|
+
import { parse as parseYaml6, stringify as stringifyYaml2 } from "yaml";
|
|
794
|
+
|
|
795
|
+
// ../cli/src/services/owners.ts
|
|
796
|
+
import { parse as parseYaml3 } from "yaml";
|
|
797
|
+
var CONFIG_PATH = ".kaddo/config.yml";
|
|
798
|
+
function loadOwners(dir) {
|
|
799
|
+
const configPath = join(dir, CONFIG_PATH);
|
|
800
|
+
if (!exists(configPath)) return {};
|
|
801
|
+
try {
|
|
802
|
+
const config = parseYaml3(readFile(configPath));
|
|
803
|
+
const raw = config.owners ?? {};
|
|
804
|
+
const result = {};
|
|
805
|
+
for (const [domain, people] of Object.entries(raw)) {
|
|
806
|
+
result[domain] = Array.isArray(people) ? people.map(String) : [String(people)];
|
|
807
|
+
}
|
|
808
|
+
return result;
|
|
809
|
+
} catch {
|
|
810
|
+
return {};
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// ../cli/src/services/mapped-modules.ts
|
|
815
|
+
import { parse as parseYaml4 } from "yaml";
|
|
816
|
+
var DESCRIPTOR_PATH = ".kaddo/modules.yml";
|
|
817
|
+
function toStringArray(value) {
|
|
818
|
+
return Array.isArray(value) ? value.map((v) => String(v)).filter(Boolean) : [];
|
|
819
|
+
}
|
|
820
|
+
function moduleArtifactCoverage(dir, id) {
|
|
821
|
+
const base = join(dir, "knowledge", "tech", "modules", id);
|
|
822
|
+
return {
|
|
823
|
+
moduleDesign: exists(join(base, "module-design.md")),
|
|
824
|
+
stack: exists(join(base, "stack.md")),
|
|
825
|
+
security: exists(join(base, "security.md")),
|
|
826
|
+
standards: exists(join(base, "standards.md")),
|
|
827
|
+
diagrams: exists(join(base, "diagrams")),
|
|
828
|
+
adrs: exists(join(base, "adrs"))
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
function loadMappedModules(dir) {
|
|
832
|
+
const path3 = join(dir, DESCRIPTOR_PATH);
|
|
833
|
+
if (!exists(path3)) return [];
|
|
834
|
+
let parsed;
|
|
835
|
+
try {
|
|
836
|
+
parsed = parseYaml4(readFile(path3));
|
|
837
|
+
} catch {
|
|
838
|
+
return [];
|
|
839
|
+
}
|
|
840
|
+
const raw = Array.isArray(parsed?.modules) ? parsed.modules : [];
|
|
841
|
+
const modules = [];
|
|
842
|
+
for (const entry of raw) {
|
|
843
|
+
if (!entry || typeof entry !== "object") continue;
|
|
844
|
+
const m2 = entry;
|
|
845
|
+
const id = typeof m2.id === "string" ? m2.id : "";
|
|
846
|
+
if (!id) continue;
|
|
847
|
+
modules.push({
|
|
848
|
+
id,
|
|
849
|
+
name: typeof m2.name === "string" ? m2.name : void 0,
|
|
850
|
+
repoPath: typeof m2.repoPath === "string" ? m2.repoPath : "",
|
|
851
|
+
type: typeof m2.type === "string" ? m2.type : void 0,
|
|
852
|
+
mainTechnology: typeof m2.mainTechnology === "string" ? m2.mainTechnology : void 0,
|
|
853
|
+
owner: typeof m2.owner === "string" ? m2.owner : void 0,
|
|
854
|
+
capabilities: toStringArray(m2.capabilities),
|
|
855
|
+
code: toStringArray(m2.code),
|
|
856
|
+
status: typeof m2.status === "string" ? m2.status : void 0,
|
|
857
|
+
artifacts: moduleArtifactCoverage(dir, id)
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
return modules;
|
|
861
|
+
}
|
|
862
|
+
function detectModuleStatus(coreDir, repoPath) {
|
|
863
|
+
const moduleDir = join(coreDir, repoPath);
|
|
864
|
+
const configPath = join(moduleDir, ".kaddo", "config.yml");
|
|
865
|
+
const hasConfig = exists(configPath);
|
|
866
|
+
if (!hasConfig) {
|
|
867
|
+
return {
|
|
868
|
+
status: "not_configured",
|
|
869
|
+
configured: false,
|
|
870
|
+
moduleContext: false,
|
|
871
|
+
currentState: false,
|
|
872
|
+
codebase: false,
|
|
873
|
+
warning: `Run \`kaddo init\` inside \`${repoPath}\` and select multirepo \u2192 module.`
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
let parsed = null;
|
|
877
|
+
try {
|
|
878
|
+
parsed = parseYaml4(readFile(configPath));
|
|
879
|
+
} catch {
|
|
880
|
+
}
|
|
881
|
+
const project = parsed?.project;
|
|
882
|
+
const multirepo = parsed?.multirepo;
|
|
883
|
+
const role = project?.role ?? multirepo?.role;
|
|
884
|
+
if (role !== "module") {
|
|
885
|
+
return {
|
|
886
|
+
status: "invalid",
|
|
887
|
+
configured: true,
|
|
888
|
+
role,
|
|
889
|
+
moduleContext: false,
|
|
890
|
+
currentState: false,
|
|
891
|
+
codebase: false,
|
|
892
|
+
warning: `Repository has Kaddo configured but project.role is not module.`
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
return {
|
|
896
|
+
status: "configured",
|
|
897
|
+
configured: true,
|
|
898
|
+
role: "module",
|
|
899
|
+
moduleContext: exists(join(moduleDir, "knowledge", "module", "module-context.md")),
|
|
900
|
+
currentState: exists(join(moduleDir, "knowledge", "tech", "current-state.md")),
|
|
901
|
+
codebase: exists(join(moduleDir, "knowledge", "tech", "codebase.md"))
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
function readModuleContext(coreDir, repoPath) {
|
|
905
|
+
const p = join(coreDir, repoPath, "knowledge", "module", "module-context.md");
|
|
906
|
+
if (!exists(p)) return null;
|
|
907
|
+
try {
|
|
908
|
+
return readFile(p);
|
|
909
|
+
} catch {
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
function presentArtifacts(coverage) {
|
|
914
|
+
const present = [];
|
|
915
|
+
if (coverage.moduleDesign) present.push("module-design");
|
|
916
|
+
if (coverage.stack) present.push("stack");
|
|
917
|
+
if (coverage.security) present.push("security");
|
|
918
|
+
if (coverage.standards) present.push("standards");
|
|
919
|
+
if (coverage.diagrams) present.push("diagrams");
|
|
920
|
+
if (coverage.adrs) present.push("adrs");
|
|
921
|
+
return present;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// ../../node_modules/.pnpm/@clack+core@0.3.5/node_modules/@clack/core/dist/index.mjs
|
|
925
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
926
|
+
import { stdin as $, stdout as k } from "process";
|
|
927
|
+
import * as f from "readline";
|
|
928
|
+
import _ from "readline";
|
|
929
|
+
import { WriteStream as U } from "tty";
|
|
930
|
+
function q({ onlyFirst: e = false } = {}) {
|
|
931
|
+
const F = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
|
|
932
|
+
return new RegExp(F, e ? void 0 : "g");
|
|
933
|
+
}
|
|
934
|
+
var J = q();
|
|
935
|
+
function T(e) {
|
|
936
|
+
return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
|
|
937
|
+
}
|
|
938
|
+
var j = { exports: {} };
|
|
939
|
+
(function(e) {
|
|
940
|
+
var u = {};
|
|
941
|
+
e.exports = u, u.eastAsianWidth = function(t) {
|
|
942
|
+
var s = t.charCodeAt(0), C2 = t.length == 2 ? t.charCodeAt(1) : 0, D = s;
|
|
943
|
+
return 55296 <= s && s <= 56319 && 56320 <= C2 && C2 <= 57343 && (s &= 1023, C2 &= 1023, D = s << 10 | C2, D += 65536), D == 12288 || 65281 <= D && D <= 65376 || 65504 <= D && D <= 65510 ? "F" : D == 8361 || 65377 <= D && D <= 65470 || 65474 <= D && D <= 65479 || 65482 <= D && D <= 65487 || 65490 <= D && D <= 65495 || 65498 <= D && D <= 65500 || 65512 <= D && D <= 65518 ? "H" : 4352 <= D && D <= 4447 || 4515 <= D && D <= 4519 || 4602 <= D && D <= 4607 || 9001 <= D && D <= 9002 || 11904 <= D && D <= 11929 || 11931 <= D && D <= 12019 || 12032 <= D && D <= 12245 || 12272 <= D && D <= 12283 || 12289 <= D && D <= 12350 || 12353 <= D && D <= 12438 || 12441 <= D && D <= 12543 || 12549 <= D && D <= 12589 || 12593 <= D && D <= 12686 || 12688 <= D && D <= 12730 || 12736 <= D && D <= 12771 || 12784 <= D && D <= 12830 || 12832 <= D && D <= 12871 || 12880 <= D && D <= 13054 || 13056 <= D && D <= 19903 || 19968 <= D && D <= 42124 || 42128 <= D && D <= 42182 || 43360 <= D && D <= 43388 || 44032 <= D && D <= 55203 || 55216 <= D && D <= 55238 || 55243 <= D && D <= 55291 || 63744 <= D && D <= 64255 || 65040 <= D && D <= 65049 || 65072 <= D && D <= 65106 || 65108 <= D && D <= 65126 || 65128 <= D && D <= 65131 || 110592 <= D && D <= 110593 || 127488 <= D && D <= 127490 || 127504 <= D && D <= 127546 || 127552 <= D && D <= 127560 || 127568 <= D && D <= 127569 || 131072 <= D && D <= 194367 || 177984 <= D && D <= 196605 || 196608 <= D && D <= 262141 ? "W" : 32 <= D && D <= 126 || 162 <= D && D <= 163 || 165 <= D && D <= 166 || D == 172 || D == 175 || 10214 <= D && D <= 10221 || 10629 <= D && D <= 10630 ? "Na" : D == 161 || D == 164 || 167 <= D && D <= 168 || D == 170 || 173 <= D && D <= 174 || 176 <= D && D <= 180 || 182 <= D && D <= 186 || 188 <= D && D <= 191 || D == 198 || D == 208 || 215 <= D && D <= 216 || 222 <= D && D <= 225 || D == 230 || 232 <= D && D <= 234 || 236 <= D && D <= 237 || D == 240 || 242 <= D && D <= 243 || 247 <= D && D <= 250 || D == 252 || D == 254 || D == 257 || D == 273 || D == 275 || D == 283 || 294 <= D && D <= 295 || D == 299 || 305 <= D && D <= 307 || D == 312 || 319 <= D && D <= 322 || D == 324 || 328 <= D && D <= 331 || D == 333 || 338 <= D && D <= 339 || 358 <= D && D <= 359 || D == 363 || D == 462 || D == 464 || D == 466 || D == 468 || D == 470 || D == 472 || D == 474 || D == 476 || D == 593 || D == 609 || D == 708 || D == 711 || 713 <= D && D <= 715 || D == 717 || D == 720 || 728 <= D && D <= 731 || D == 733 || D == 735 || 768 <= D && D <= 879 || 913 <= D && D <= 929 || 931 <= D && D <= 937 || 945 <= D && D <= 961 || 963 <= D && D <= 969 || D == 1025 || 1040 <= D && D <= 1103 || D == 1105 || D == 8208 || 8211 <= D && D <= 8214 || 8216 <= D && D <= 8217 || 8220 <= D && D <= 8221 || 8224 <= D && D <= 8226 || 8228 <= D && D <= 8231 || D == 8240 || 8242 <= D && D <= 8243 || D == 8245 || D == 8251 || D == 8254 || D == 8308 || D == 8319 || 8321 <= D && D <= 8324 || D == 8364 || D == 8451 || D == 8453 || D == 8457 || D == 8467 || D == 8470 || 8481 <= D && D <= 8482 || D == 8486 || D == 8491 || 8531 <= D && D <= 8532 || 8539 <= D && D <= 8542 || 8544 <= D && D <= 8555 || 8560 <= D && D <= 8569 || D == 8585 || 8592 <= D && D <= 8601 || 8632 <= D && D <= 8633 || D == 8658 || D == 8660 || D == 8679 || D == 8704 || 8706 <= D && D <= 8707 || 8711 <= D && D <= 8712 || D == 8715 || D == 8719 || D == 8721 || D == 8725 || D == 8730 || 8733 <= D && D <= 8736 || D == 8739 || D == 8741 || 8743 <= D && D <= 8748 || D == 8750 || 8756 <= D && D <= 8759 || 8764 <= D && D <= 8765 || D == 8776 || D == 8780 || D == 8786 || 8800 <= D && D <= 8801 || 8804 <= D && D <= 8807 || 8810 <= D && D <= 8811 || 8814 <= D && D <= 8815 || 8834 <= D && D <= 8835 || 8838 <= D && D <= 8839 || D == 8853 || D == 8857 || D == 8869 || D == 8895 || D == 8978 || 9312 <= D && D <= 9449 || 9451 <= D && D <= 9547 || 9552 <= D && D <= 9587 || 9600 <= D && D <= 9615 || 9618 <= D && D <= 9621 || 9632 <= D && D <= 9633 || 9635 <= D && D <= 9641 || 9650 <= D && D <= 9651 || 9654 <= D && D <= 9655 || 9660 <= D && D <= 9661 || 9664 <= D && D <= 9665 || 9670 <= D && D <= 9672 || D == 9675 || 9678 <= D && D <= 9681 || 9698 <= D && D <= 9701 || D == 9711 || 9733 <= D && D <= 9734 || D == 9737 || 9742 <= D && D <= 9743 || 9748 <= D && D <= 9749 || D == 9756 || D == 9758 || D == 9792 || D == 9794 || 9824 <= D && D <= 9825 || 9827 <= D && D <= 9829 || 9831 <= D && D <= 9834 || 9836 <= D && D <= 9837 || D == 9839 || 9886 <= D && D <= 9887 || 9918 <= D && D <= 9919 || 9924 <= D && D <= 9933 || 9935 <= D && D <= 9953 || D == 9955 || 9960 <= D && D <= 9983 || D == 10045 || D == 10071 || 10102 <= D && D <= 10111 || 11093 <= D && D <= 11097 || 12872 <= D && D <= 12879 || 57344 <= D && D <= 63743 || 65024 <= D && D <= 65039 || D == 65533 || 127232 <= D && D <= 127242 || 127248 <= D && D <= 127277 || 127280 <= D && D <= 127337 || 127344 <= D && D <= 127386 || 917760 <= D && D <= 917999 || 983040 <= D && D <= 1048573 || 1048576 <= D && D <= 1114109 ? "A" : "N";
|
|
944
|
+
}, u.characterLength = function(t) {
|
|
945
|
+
var s = this.eastAsianWidth(t);
|
|
946
|
+
return s == "F" || s == "W" || s == "A" ? 2 : 1;
|
|
947
|
+
};
|
|
948
|
+
function F(t) {
|
|
949
|
+
return t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
|
|
950
|
+
}
|
|
951
|
+
u.length = function(t) {
|
|
952
|
+
for (var s = F(t), C2 = 0, D = 0; D < s.length; D++) C2 = C2 + this.characterLength(s[D]);
|
|
953
|
+
return C2;
|
|
954
|
+
}, u.slice = function(t, s, C2) {
|
|
955
|
+
textLen = u.length(t), s = s || 0, C2 = C2 || 1, s < 0 && (s = textLen + s), C2 < 0 && (C2 = textLen + C2);
|
|
956
|
+
for (var D = "", i = 0, n = F(t), E2 = 0; E2 < n.length; E2++) {
|
|
957
|
+
var h2 = n[E2], o2 = u.length(h2);
|
|
958
|
+
if (i >= s - (o2 == 2 ? 1 : 0)) if (i + o2 <= C2) D += h2;
|
|
959
|
+
else break;
|
|
960
|
+
i += o2;
|
|
961
|
+
}
|
|
962
|
+
return D;
|
|
963
|
+
};
|
|
964
|
+
})(j);
|
|
965
|
+
var Q = j.exports;
|
|
966
|
+
var X = T(Q);
|
|
967
|
+
var DD = function() {
|
|
968
|
+
return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
|
|
969
|
+
};
|
|
970
|
+
var uD = T(DD);
|
|
971
|
+
var d = 10;
|
|
972
|
+
var M = (e = 0) => (u) => `\x1B[${u + e}m`;
|
|
973
|
+
var P = (e = 0) => (u) => `\x1B[${38 + e};5;${u}m`;
|
|
974
|
+
var W = (e = 0) => (u, F, t) => `\x1B[${38 + e};2;${u};${F};${t}m`;
|
|
975
|
+
var r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
|
|
976
|
+
Object.keys(r.modifier);
|
|
977
|
+
var FD = Object.keys(r.color);
|
|
978
|
+
var eD = Object.keys(r.bgColor);
|
|
979
|
+
[...FD, ...eD];
|
|
980
|
+
function tD() {
|
|
981
|
+
const e = /* @__PURE__ */ new Map();
|
|
982
|
+
for (const [u, F] of Object.entries(r)) {
|
|
983
|
+
for (const [t, s] of Object.entries(F)) r[t] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, F[t] = r[t], e.set(s[0], s[1]);
|
|
984
|
+
Object.defineProperty(r, u, { value: F, enumerable: false });
|
|
985
|
+
}
|
|
986
|
+
return Object.defineProperty(r, "codes", { value: e, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = M(), r.color.ansi256 = P(), r.color.ansi16m = W(), r.bgColor.ansi = M(d), r.bgColor.ansi256 = P(d), r.bgColor.ansi16m = W(d), Object.defineProperties(r, { rgbToAnsi256: { value: (u, F, t) => u === F && F === t ? u < 8 ? 16 : u > 248 ? 231 : Math.round((u - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u / 255 * 5) + 6 * Math.round(F / 255 * 5) + Math.round(t / 255 * 5), enumerable: false }, hexToRgb: { value: (u) => {
|
|
987
|
+
const F = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));
|
|
988
|
+
if (!F) return [0, 0, 0];
|
|
989
|
+
let [t] = F;
|
|
990
|
+
t.length === 3 && (t = [...t].map((C2) => C2 + C2).join(""));
|
|
991
|
+
const s = Number.parseInt(t, 16);
|
|
992
|
+
return [s >> 16 & 255, s >> 8 & 255, s & 255];
|
|
993
|
+
}, enumerable: false }, hexToAnsi256: { value: (u) => r.rgbToAnsi256(...r.hexToRgb(u)), enumerable: false }, ansi256ToAnsi: { value: (u) => {
|
|
994
|
+
if (u < 8) return 30 + u;
|
|
995
|
+
if (u < 16) return 90 + (u - 8);
|
|
996
|
+
let F, t, s;
|
|
997
|
+
if (u >= 232) F = ((u - 232) * 10 + 8) / 255, t = F, s = F;
|
|
998
|
+
else {
|
|
999
|
+
u -= 16;
|
|
1000
|
+
const i = u % 36;
|
|
1001
|
+
F = Math.floor(u / 36) / 5, t = Math.floor(i / 6) / 5, s = i % 6 / 5;
|
|
1002
|
+
}
|
|
1003
|
+
const C2 = Math.max(F, t, s) * 2;
|
|
1004
|
+
if (C2 === 0) return 30;
|
|
1005
|
+
let D = 30 + (Math.round(s) << 2 | Math.round(t) << 1 | Math.round(F));
|
|
1006
|
+
return C2 === 2 && (D += 60), D;
|
|
1007
|
+
}, enumerable: false }, rgbToAnsi: { value: (u, F, t) => r.ansi256ToAnsi(r.rgbToAnsi256(u, F, t)), enumerable: false }, hexToAnsi: { value: (u) => r.ansi256ToAnsi(r.hexToAnsi256(u)), enumerable: false } }), r;
|
|
1008
|
+
}
|
|
1009
|
+
var sD = tD();
|
|
1010
|
+
var iD = "]";
|
|
1011
|
+
var w = `${iD}8;;`;
|
|
1012
|
+
var WD = globalThis.process.platform.startsWith("win");
|
|
1013
|
+
|
|
1014
|
+
// ../../node_modules/.pnpm/@clack+prompts@0.7.0/node_modules/@clack/prompts/dist/index.mjs
|
|
1015
|
+
import h from "process";
|
|
1016
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
1017
|
+
function q2() {
|
|
1018
|
+
return h.platform !== "win32" ? h.env.TERM !== "linux" : Boolean(h.env.CI) || Boolean(h.env.WT_SESSION) || Boolean(h.env.TERMINUS_SUBLIME) || h.env.ConEmuTask === "{cmd::Cmder}" || h.env.TERM_PROGRAM === "Terminus-Sublime" || h.env.TERM_PROGRAM === "vscode" || h.env.TERM === "xterm-256color" || h.env.TERM === "alacritty" || h.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
1019
|
+
}
|
|
1020
|
+
var _2 = q2();
|
|
1021
|
+
var o = (r2, n) => _2 ? r2 : n;
|
|
1022
|
+
var H = o("\u25C6", "*");
|
|
1023
|
+
var I = o("\u25A0", "x");
|
|
1024
|
+
var x = o("\u25B2", "x");
|
|
1025
|
+
var S = o("\u25C7", "o");
|
|
1026
|
+
var K = o("\u250C", "T");
|
|
1027
|
+
var a = o("\u2502", "|");
|
|
1028
|
+
var d2 = o("\u2514", "\u2014");
|
|
1029
|
+
var b = o("\u25CF", ">");
|
|
1030
|
+
var E = o("\u25CB", " ");
|
|
1031
|
+
var C = o("\u25FB", "[\u2022]");
|
|
1032
|
+
var w2 = o("\u25FC", "[+]");
|
|
1033
|
+
var M2 = o("\u25FB", "[ ]");
|
|
1034
|
+
var U2 = o("\u25AA", "\u2022");
|
|
1035
|
+
var B = o("\u2500", "-");
|
|
1036
|
+
var Z = o("\u256E", "+");
|
|
1037
|
+
var z2 = o("\u251C", "+");
|
|
1038
|
+
var X2 = o("\u256F", "+");
|
|
1039
|
+
var J2 = o("\u25CF", "\u2022");
|
|
1040
|
+
var Y = o("\u25C6", "*");
|
|
1041
|
+
var Q2 = o("\u25B2", "!");
|
|
1042
|
+
var ee = o("\u25A0", "x");
|
|
1043
|
+
|
|
1044
|
+
// ../cli/src/commands/modules-map.ts
|
|
1045
|
+
import { parse as parseYaml5, stringify as stringifyYaml } from "yaml";
|
|
1046
|
+
|
|
1047
|
+
// ../cli/src/templates/registry.ts
|
|
1048
|
+
var QUALITY = "## Quality checklist";
|
|
1049
|
+
var WORK_ITEM = `---
|
|
1050
|
+
type: feature
|
|
1051
|
+
id: WI-001
|
|
1052
|
+
title: "Short, action-oriented title"
|
|
1053
|
+
status: draft
|
|
1054
|
+
knowledge_level: K2
|
|
1055
|
+
source: manual
|
|
1056
|
+
source_id:
|
|
1057
|
+
phase: now
|
|
1058
|
+
initiative:
|
|
1059
|
+
domains: []
|
|
1060
|
+
capabilities: []
|
|
1061
|
+
code: []
|
|
1062
|
+
created_at: YYYY-MM-DD
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
# <Title>
|
|
1066
|
+
|
|
1067
|
+
> Type: feature \xB7 Level: K2
|
|
1068
|
+
|
|
1069
|
+
## Problem
|
|
1070
|
+
|
|
1071
|
+
_What problem or opportunity does this address?_
|
|
1072
|
+
|
|
1073
|
+
## Expected result
|
|
1074
|
+
|
|
1075
|
+
_What should be true once this is done?_
|
|
1076
|
+
|
|
1077
|
+
## Acceptance criteria
|
|
1078
|
+
|
|
1079
|
+
- [ ] ...
|
|
1080
|
+
|
|
1081
|
+
## Design
|
|
1082
|
+
|
|
1083
|
+
_Optional. Key decisions or approach. Keep it minimal at low knowledge levels._
|
|
1084
|
+
|
|
1085
|
+
## Risks
|
|
1086
|
+
|
|
1087
|
+
_Optional. What could go wrong?_
|
|
1088
|
+
|
|
1089
|
+
## Out of scope
|
|
1090
|
+
|
|
1091
|
+
_What is intentionally not included in this Work Item?_
|
|
1092
|
+
|
|
1093
|
+
## Validation
|
|
1094
|
+
|
|
1095
|
+
_How will this be validated?_
|
|
1096
|
+
|
|
1097
|
+
## Definition of Done
|
|
1098
|
+
|
|
1099
|
+
- [ ] Code merged
|
|
1100
|
+
- [ ] Knowledge updated or intentionally unchanged
|
|
1101
|
+
|
|
1102
|
+
## Learning
|
|
1103
|
+
|
|
1104
|
+
_What did we learn? Fill in after completion (\`kaddo learn\`)._
|
|
1105
|
+
|
|
1106
|
+
${QUALITY}
|
|
1107
|
+
|
|
1108
|
+
- [ ] Title is specific and action-oriented.
|
|
1109
|
+
- [ ] \`code:\` globs declared so Guard can relate changes.
|
|
1110
|
+
- [ ] Knowledge level matches the real uncertainty.
|
|
1111
|
+
`;
|
|
1112
|
+
var ROADMAP = `---
|
|
1113
|
+
type: roadmap
|
|
1114
|
+
updated_at: YYYY-MM-DD
|
|
1115
|
+
---
|
|
1116
|
+
|
|
1117
|
+
# <Project> \u2014 Roadmap
|
|
1118
|
+
|
|
1119
|
+
> Candidates for human review \u2014 not commitments. Generated with the roadmap-agent.
|
|
1120
|
+
|
|
1121
|
+
## Initiatives
|
|
1122
|
+
|
|
1123
|
+
### RM-001 \u2014 <Initiative title>
|
|
1124
|
+
|
|
1125
|
+
**Goal:** ...
|
|
1126
|
+
**Related capabilities:** ...
|
|
1127
|
+
**Impact:** ...
|
|
1128
|
+
**Risk:** ...
|
|
1129
|
+
**Suggested Knowledge Level:** K1 / K2 / K3 / K4
|
|
1130
|
+
**Dependencies:** ...
|
|
1131
|
+
**Why now:** ...
|
|
1132
|
+
|
|
1133
|
+
#### Candidate Work Items
|
|
1134
|
+
|
|
1135
|
+
- **WI-CANDIDATE-001** \u2014 <title> \xB7 type: feature \xB7 level: K2 \xB7 value: ... \xB7 notes: ...
|
|
1136
|
+
|
|
1137
|
+
## Assumptions
|
|
1138
|
+
|
|
1139
|
+
- ...
|
|
1140
|
+
|
|
1141
|
+
**Open questions:**
|
|
1142
|
+
|
|
1143
|
+
- ...
|
|
1144
|
+
|
|
1145
|
+
## Suggested execution order
|
|
1146
|
+
|
|
1147
|
+
1. ...
|
|
1148
|
+
|
|
1149
|
+
## Not now
|
|
1150
|
+
|
|
1151
|
+
- ...
|
|
1152
|
+
|
|
1153
|
+
${QUALITY}
|
|
1154
|
+
|
|
1155
|
+
- [ ] Each initiative has a goal, impact and risk.
|
|
1156
|
+
- [ ] Candidates are marked as candidates, not decisions.
|
|
1157
|
+
- [ ] Priorities reflect the project state (new / pre-ai / legacy).
|
|
1158
|
+
`;
|
|
1159
|
+
var CAPABILITIES = `---
|
|
1160
|
+
type: capabilities
|
|
1161
|
+
updated_at: YYYY-MM-DD
|
|
1162
|
+
---
|
|
1163
|
+
|
|
1164
|
+
# <Project> \u2014 Capabilities
|
|
1165
|
+
|
|
1166
|
+
> What the system can do, from the product's point of view. Refine with capability-agent.
|
|
1167
|
+
|
|
1168
|
+
## CAP-001 \u2014 <Capability name>
|
|
1169
|
+
|
|
1170
|
+
**Description:** ...
|
|
1171
|
+
**Status:** existing / proposed
|
|
1172
|
+
**Related domains:** ...
|
|
1173
|
+
**Evidence:** _where in code/docs this is observed_
|
|
1174
|
+
|
|
1175
|
+
## Assumptions
|
|
1176
|
+
|
|
1177
|
+
- ...
|
|
1178
|
+
|
|
1179
|
+
## Open questions
|
|
1180
|
+
|
|
1181
|
+
- ...
|
|
1182
|
+
|
|
1183
|
+
${QUALITY}
|
|
1184
|
+
|
|
1185
|
+
- [ ] Capabilities describe outcomes, not implementation.
|
|
1186
|
+
- [ ] Each capability cites evidence or is flagged as an assumption.
|
|
1187
|
+
`;
|
|
1188
|
+
var KNOWLEDGE = `---
|
|
1189
|
+
type: current-state
|
|
1190
|
+
updated_at: YYYY-MM-DD
|
|
1191
|
+
---
|
|
1192
|
+
|
|
1193
|
+
# <Project> \u2014 Knowledge
|
|
1194
|
+
|
|
1195
|
+
> What is true about this product right now.
|
|
1196
|
+
|
|
1197
|
+
## Purpose
|
|
1198
|
+
|
|
1199
|
+
_What this product does and who it serves._
|
|
1200
|
+
|
|
1201
|
+
## Architecture overview
|
|
1202
|
+
|
|
1203
|
+
_High-level description of the main components._
|
|
1204
|
+
|
|
1205
|
+
## Key domains
|
|
1206
|
+
|
|
1207
|
+
_Main domains or bounded contexts._
|
|
1208
|
+
|
|
1209
|
+
## Active constraints
|
|
1210
|
+
|
|
1211
|
+
_Technical, regulatory or operational constraints that shape decisions._
|
|
1212
|
+
|
|
1213
|
+
${QUALITY}
|
|
1214
|
+
|
|
1215
|
+
- [ ] Reflects the current reality, not aspirations.
|
|
1216
|
+
- [ ] Constraints are explicit.
|
|
1217
|
+
`;
|
|
1218
|
+
var CURRENT_STATE = `---
|
|
1219
|
+
type: current-state
|
|
1220
|
+
updated_at: YYYY-MM-DD
|
|
1221
|
+
---
|
|
1222
|
+
|
|
1223
|
+
# <Project> \u2014 Current State (Architecture Baseline)
|
|
1224
|
+
|
|
1225
|
+
> Reconstructed baseline. Refine with architecture-agent using \`.kaddo/context-pack.md\`.
|
|
1226
|
+
|
|
1227
|
+
## Components
|
|
1228
|
+
|
|
1229
|
+
_Main services / packages / modules and their responsibilities._
|
|
1230
|
+
|
|
1231
|
+
## Data & integrations
|
|
1232
|
+
|
|
1233
|
+
_Datastores, queues, external APIs._
|
|
1234
|
+
|
|
1235
|
+
## Cross-cutting concerns
|
|
1236
|
+
|
|
1237
|
+
_Auth, logging, config, error handling._
|
|
1238
|
+
|
|
1239
|
+
## Known gaps
|
|
1240
|
+
|
|
1241
|
+
_What is unclear or undocumented._
|
|
1242
|
+
|
|
1243
|
+
## Assumptions
|
|
1244
|
+
|
|
1245
|
+
- ...
|
|
1246
|
+
|
|
1247
|
+
${QUALITY}
|
|
1248
|
+
|
|
1249
|
+
- [ ] Components map to real code areas.
|
|
1250
|
+
- [ ] Gaps and assumptions are explicit, not hidden.
|
|
1251
|
+
`;
|
|
1252
|
+
var ARCHITECTURE_NOTES = `---
|
|
1253
|
+
type: architecture-notes
|
|
1254
|
+
updated_at: YYYY-MM-DD
|
|
1255
|
+
---
|
|
1256
|
+
|
|
1257
|
+
# Architecture Notes
|
|
1258
|
+
|
|
1259
|
+
> Working notes on architecture topics that are not yet ADRs.
|
|
1260
|
+
|
|
1261
|
+
## Topic
|
|
1262
|
+
|
|
1263
|
+
_What is being explored._
|
|
1264
|
+
|
|
1265
|
+
## Context
|
|
1266
|
+
|
|
1267
|
+
_Why it matters now._
|
|
1268
|
+
|
|
1269
|
+
## Options
|
|
1270
|
+
|
|
1271
|
+
- Option A \u2014 ...
|
|
1272
|
+
- Option B \u2014 ...
|
|
1273
|
+
|
|
1274
|
+
## Leaning towards
|
|
1275
|
+
|
|
1276
|
+
_Current inclination and why (not a decision yet)._
|
|
1277
|
+
|
|
1278
|
+
## Open questions
|
|
1279
|
+
|
|
1280
|
+
- ...
|
|
1281
|
+
|
|
1282
|
+
${QUALITY}
|
|
1283
|
+
|
|
1284
|
+
- [ ] Notes are clearly non-binding (not a decision).
|
|
1285
|
+
- [ ] Options capture real trade-offs.
|
|
1286
|
+
`;
|
|
1287
|
+
var DECISION_CANDIDATES = `---
|
|
1288
|
+
type: decision-candidates
|
|
1289
|
+
updated_at: YYYY-MM-DD
|
|
1290
|
+
---
|
|
1291
|
+
|
|
1292
|
+
# Decision Candidates
|
|
1293
|
+
|
|
1294
|
+
> Candidate architecture decisions for human review. Refine with adr-agent.
|
|
1295
|
+
> Promote accepted candidates into individual ADRs.
|
|
1296
|
+
|
|
1297
|
+
## DC-001 \u2014 <Decision title>
|
|
1298
|
+
|
|
1299
|
+
**Context:** ...
|
|
1300
|
+
**Options considered:** ...
|
|
1301
|
+
**Recommended option:** ...
|
|
1302
|
+
**Trade-offs:** ...
|
|
1303
|
+
**Status:** candidate
|
|
1304
|
+
|
|
1305
|
+
${QUALITY}
|
|
1306
|
+
|
|
1307
|
+
- [ ] Each candidate states context and trade-offs.
|
|
1308
|
+
- [ ] Candidates are not presented as final decisions.
|
|
1309
|
+
`;
|
|
1310
|
+
var ADR = `---
|
|
1311
|
+
type: adr
|
|
1312
|
+
id: ADR-0001
|
|
1313
|
+
status: proposed
|
|
1314
|
+
date: YYYY-MM-DD
|
|
1315
|
+
domains: []
|
|
1316
|
+
capabilities: []
|
|
1317
|
+
code: []
|
|
1318
|
+
---
|
|
1319
|
+
|
|
1320
|
+
# ADR-0001 \u2014 <Decision title>
|
|
1321
|
+
|
|
1322
|
+
## Status
|
|
1323
|
+
|
|
1324
|
+
proposed | accepted | superseded
|
|
1325
|
+
|
|
1326
|
+
## Context
|
|
1327
|
+
|
|
1328
|
+
_The forces and constraints that lead to this decision._
|
|
1329
|
+
|
|
1330
|
+
## Decision
|
|
1331
|
+
|
|
1332
|
+
_The decision, stated clearly and in the present tense._
|
|
1333
|
+
|
|
1334
|
+
## Consequences
|
|
1335
|
+
|
|
1336
|
+
_Positive and negative results of the decision._
|
|
1337
|
+
|
|
1338
|
+
## Alternatives considered
|
|
1339
|
+
|
|
1340
|
+
- ...
|
|
1341
|
+
|
|
1342
|
+
${QUALITY}
|
|
1343
|
+
|
|
1344
|
+
- [ ] The decision is unambiguous.
|
|
1345
|
+
- [ ] Consequences include the downsides, not only benefits.
|
|
1346
|
+
- [ ] Superseding ADRs are linked when status changes.
|
|
1347
|
+
`;
|
|
1348
|
+
var MODULE_DESIGN = `---
|
|
1349
|
+
type: module-design
|
|
1350
|
+
module: module-name
|
|
1351
|
+
status: draft
|
|
1352
|
+
owner: unknown
|
|
1353
|
+
repoPath: ../module-repo
|
|
1354
|
+
capabilities: []
|
|
1355
|
+
code: []
|
|
1356
|
+
---
|
|
1357
|
+
|
|
1358
|
+
# <Module> \u2014 Design
|
|
1359
|
+
|
|
1360
|
+
> Refine with module-design-agent using \`.kaddo/context-pack.md\`.
|
|
1361
|
+
|
|
1362
|
+
**Type:** frontend / backend / worker / mobile / library / infrastructure / data
|
|
1363
|
+
**Repository:** ../module-repo
|
|
1364
|
+
**Main technology:** ...
|
|
1365
|
+
**Owner:** ...
|
|
1366
|
+
|
|
1367
|
+
## Purpose
|
|
1368
|
+
|
|
1369
|
+
## Boundaries
|
|
1370
|
+
|
|
1371
|
+
## Inputs / Outputs
|
|
1372
|
+
|
|
1373
|
+
## Dependencies
|
|
1374
|
+
|
|
1375
|
+
## Related capabilities
|
|
1376
|
+
|
|
1377
|
+
- ...
|
|
1378
|
+
|
|
1379
|
+
## Risks & open questions
|
|
1380
|
+
|
|
1381
|
+
${QUALITY}
|
|
1382
|
+
|
|
1383
|
+
- [ ] Boundaries make clear what is in and out of the module.
|
|
1384
|
+
- [ ] Dependencies on other modules are listed.
|
|
1385
|
+
`;
|
|
1386
|
+
var MODULE_STACK = `# <Module> \u2014 Stack
|
|
1387
|
+
|
|
1388
|
+
> Refine with stack-agent.
|
|
1389
|
+
|
|
1390
|
+
**Main technology:** ...
|
|
1391
|
+
|
|
1392
|
+
## Languages
|
|
1393
|
+
|
|
1394
|
+
## Frameworks
|
|
1395
|
+
|
|
1396
|
+
## Data
|
|
1397
|
+
|
|
1398
|
+
## Infrastructure
|
|
1399
|
+
|
|
1400
|
+
## Unknowns / needs confirmation
|
|
1401
|
+
|
|
1402
|
+
${QUALITY}
|
|
1403
|
+
|
|
1404
|
+
- [ ] Reflects the module's actual stack, not the whole system.
|
|
1405
|
+
- [ ] Unknowns are listed rather than guessed.
|
|
1406
|
+
`;
|
|
1407
|
+
var MODULE_SECURITY = `# <Module> \u2014 Security Considerations
|
|
1408
|
+
|
|
1409
|
+
> Refine with security-agent. Kaddo does **not** perform security scanning.
|
|
1410
|
+
|
|
1411
|
+
## Authentication & authorization
|
|
1412
|
+
|
|
1413
|
+
## Data sensitivity
|
|
1414
|
+
|
|
1415
|
+
## Secrets handling
|
|
1416
|
+
|
|
1417
|
+
## Open questions
|
|
1418
|
+
|
|
1419
|
+
${QUALITY}
|
|
1420
|
+
|
|
1421
|
+
- [ ] Documents concerns for humans \u2014 does not claim to audit code.
|
|
1422
|
+
- [ ] Data sensitivity is classified.
|
|
1423
|
+
`;
|
|
1424
|
+
var MODULE_STANDARDS = `# <Module> \u2014 Standards
|
|
1425
|
+
|
|
1426
|
+
> Refine with standards-agent. Keep it lightweight.
|
|
1427
|
+
|
|
1428
|
+
## Coding standards
|
|
1429
|
+
|
|
1430
|
+
## Testing expectations
|
|
1431
|
+
|
|
1432
|
+
## PR checklist
|
|
1433
|
+
|
|
1434
|
+
${QUALITY}
|
|
1435
|
+
|
|
1436
|
+
- [ ] A handful of high-value rules, not a long policy.
|
|
1437
|
+
- [ ] Standards are specific to this module where it differs from the system.
|
|
1438
|
+
`;
|
|
1439
|
+
var MODULE_ADR = `---
|
|
1440
|
+
type: adr
|
|
1441
|
+
id: ADR-0001
|
|
1442
|
+
module: module-name
|
|
1443
|
+
status: proposed
|
|
1444
|
+
date: YYYY-MM-DD
|
|
1445
|
+
code: []
|
|
1446
|
+
---
|
|
1447
|
+
|
|
1448
|
+
# ADR-0001 \u2014 <Module decision title>
|
|
1449
|
+
|
|
1450
|
+
## Status
|
|
1451
|
+
|
|
1452
|
+
proposed | accepted | superseded
|
|
1453
|
+
|
|
1454
|
+
## Context
|
|
1455
|
+
|
|
1456
|
+
_Module-scoped forces and constraints._
|
|
1457
|
+
|
|
1458
|
+
## Decision
|
|
1459
|
+
|
|
1460
|
+
## Consequences
|
|
1461
|
+
|
|
1462
|
+
## Alternatives considered
|
|
1463
|
+
|
|
1464
|
+
- ...
|
|
1465
|
+
|
|
1466
|
+
${QUALITY}
|
|
1467
|
+
|
|
1468
|
+
- [ ] Scoped to this module; system-wide decisions go in the architecture repo.
|
|
1469
|
+
- [ ] Consequences include downsides.
|
|
1470
|
+
`;
|
|
1471
|
+
var SECURITY = `# Security Considerations
|
|
1472
|
+
|
|
1473
|
+
> Global. Install with \`kaddo add security\`. Refine with security-agent.
|
|
1474
|
+
> Kaddo does **not** perform security or vulnerability scanning.
|
|
1475
|
+
|
|
1476
|
+
## Authentication & authorization
|
|
1477
|
+
|
|
1478
|
+
## Data sensitivity
|
|
1479
|
+
|
|
1480
|
+
## Secrets handling
|
|
1481
|
+
|
|
1482
|
+
## Dependency risks
|
|
1483
|
+
|
|
1484
|
+
## Deployment risks
|
|
1485
|
+
|
|
1486
|
+
## Open questions
|
|
1487
|
+
|
|
1488
|
+
${QUALITY}
|
|
1489
|
+
|
|
1490
|
+
- [ ] Documents concerns for humans and agents \u2014 it does not audit code.
|
|
1491
|
+
- [ ] Secrets handling describes where secrets live and how they rotate.
|
|
1492
|
+
`;
|
|
1493
|
+
var STANDARDS = `# Standards
|
|
1494
|
+
|
|
1495
|
+
> Global. Install with \`kaddo add standards\`. Refine with standards-agent.
|
|
1496
|
+
> Keep it lightweight \u2014 a handful of high-value rules beats a long policy.
|
|
1497
|
+
|
|
1498
|
+
## Coding standards
|
|
1499
|
+
|
|
1500
|
+
## Documentation standards
|
|
1501
|
+
|
|
1502
|
+
## Testing expectations
|
|
1503
|
+
|
|
1504
|
+
## PR checklist
|
|
1505
|
+
|
|
1506
|
+
- [ ] Linked to the right Work Item.
|
|
1507
|
+
- [ ] Knowledge updated or intentionally left unchanged.
|
|
1508
|
+
|
|
1509
|
+
${QUALITY}
|
|
1510
|
+
|
|
1511
|
+
- [ ] Rules are high-value and enforceable.
|
|
1512
|
+
- [ ] No documentation theater.
|
|
1513
|
+
`;
|
|
1514
|
+
var STACK = `# Stack
|
|
1515
|
+
|
|
1516
|
+
> Global. Install with \`kaddo add stack\`. Refine with stack-agent.
|
|
1517
|
+
|
|
1518
|
+
## Languages
|
|
1519
|
+
|
|
1520
|
+
## Frameworks
|
|
1521
|
+
|
|
1522
|
+
## Data
|
|
1523
|
+
|
|
1524
|
+
## Infrastructure
|
|
1525
|
+
|
|
1526
|
+
## Tooling
|
|
1527
|
+
|
|
1528
|
+
## Unknowns / needs confirmation
|
|
1529
|
+
|
|
1530
|
+
${QUALITY}
|
|
1531
|
+
|
|
1532
|
+
- [ ] Reflects the detected stack.
|
|
1533
|
+
- [ ] Unknowns are listed, not invented.
|
|
1534
|
+
`;
|
|
1535
|
+
var GIT_STRATEGY = `# Git Strategy
|
|
1536
|
+
|
|
1537
|
+
> Global. Install with \`kaddo add git-strategy\`. Refine with git-strategy-agent.
|
|
1538
|
+
> Kaddo recommends a default and does **not** enforce it in CI.
|
|
1539
|
+
|
|
1540
|
+
## Default strategy
|
|
1541
|
+
|
|
1542
|
+
GitHub Flow + Conventional Commits + SemVer.
|
|
1543
|
+
|
|
1544
|
+
## Branch naming
|
|
1545
|
+
|
|
1546
|
+
\`\`\`txt
|
|
1547
|
+
feature/<work-item-id>-<slug>
|
|
1548
|
+
bugfix/<work-item-id>-<slug>
|
|
1549
|
+
hotfix/<work-item-id>-<slug>
|
|
1550
|
+
\`\`\`
|
|
1551
|
+
|
|
1552
|
+
## Commit convention
|
|
1553
|
+
|
|
1554
|
+
\`\`\`txt
|
|
1555
|
+
feat(scope): message
|
|
1556
|
+
fix(scope): message
|
|
1557
|
+
docs(scope): message
|
|
1558
|
+
\`\`\`
|
|
1559
|
+
|
|
1560
|
+
## Tag strategy
|
|
1561
|
+
|
|
1562
|
+
\`\`\`txt
|
|
1563
|
+
vMAJOR.MINOR.PATCH
|
|
1564
|
+
\`\`\`
|
|
1565
|
+
|
|
1566
|
+
## Customization
|
|
1567
|
+
|
|
1568
|
+
Edit \`.kaddo/git.yml\` to switch strategy: \`github-flow\`, \`gitflow\`,
|
|
1569
|
+
\`trunk-based\` or \`custom\`.
|
|
1570
|
+
|
|
1571
|
+
${QUALITY}
|
|
1572
|
+
|
|
1573
|
+
- [ ] The chosen strategy matches how the team actually works.
|
|
1574
|
+
- [ ] Branch and commit conventions reference Work Items.
|
|
1575
|
+
`;
|
|
1576
|
+
var INCIDENT = `---
|
|
1577
|
+
type: incident
|
|
1578
|
+
id: INC-001
|
|
1579
|
+
status: open
|
|
1580
|
+
severity: SEV3
|
|
1581
|
+
date: YYYY-MM-DD
|
|
1582
|
+
code: []
|
|
1583
|
+
---
|
|
1584
|
+
|
|
1585
|
+
# INC-001 \u2014 <Incident title>
|
|
1586
|
+
|
|
1587
|
+
## Summary
|
|
1588
|
+
|
|
1589
|
+
_What happened, in one or two sentences._
|
|
1590
|
+
|
|
1591
|
+
## Impact
|
|
1592
|
+
|
|
1593
|
+
_Who/what was affected and for how long._
|
|
1594
|
+
|
|
1595
|
+
## Timeline
|
|
1596
|
+
|
|
1597
|
+
- HH:MM \u2014 ...
|
|
1598
|
+
|
|
1599
|
+
## Root cause
|
|
1600
|
+
|
|
1601
|
+
_What actually caused it._
|
|
1602
|
+
|
|
1603
|
+
## Resolution
|
|
1604
|
+
|
|
1605
|
+
_How it was mitigated and fixed._
|
|
1606
|
+
|
|
1607
|
+
## Follow-up actions
|
|
1608
|
+
|
|
1609
|
+
- [ ] ...
|
|
1610
|
+
|
|
1611
|
+
${QUALITY}
|
|
1612
|
+
|
|
1613
|
+
- [ ] Root cause is the real cause, not the trigger.
|
|
1614
|
+
- [ ] Follow-up actions are concrete and owned.
|
|
1615
|
+
`;
|
|
1616
|
+
var RUNBOOK = `---
|
|
1617
|
+
type: runbook
|
|
1618
|
+
title: "<Operation> runbook"
|
|
1619
|
+
updated_at: YYYY-MM-DD
|
|
1620
|
+
---
|
|
1621
|
+
|
|
1622
|
+
# <Operation> \u2014 Runbook
|
|
1623
|
+
|
|
1624
|
+
> How to perform a recurring operational task safely.
|
|
1625
|
+
|
|
1626
|
+
## When to use
|
|
1627
|
+
|
|
1628
|
+
_The situation that triggers this runbook._
|
|
1629
|
+
|
|
1630
|
+
## Prerequisites
|
|
1631
|
+
|
|
1632
|
+
- ...
|
|
1633
|
+
|
|
1634
|
+
## Steps
|
|
1635
|
+
|
|
1636
|
+
1. ...
|
|
1637
|
+
|
|
1638
|
+
## Verification
|
|
1639
|
+
|
|
1640
|
+
_How to confirm success._
|
|
1641
|
+
|
|
1642
|
+
## Rollback
|
|
1643
|
+
|
|
1644
|
+
_How to undo if something goes wrong._
|
|
1645
|
+
|
|
1646
|
+
${QUALITY}
|
|
1647
|
+
|
|
1648
|
+
- [ ] Steps are reproducible by someone who is not the author.
|
|
1649
|
+
- [ ] Rollback is defined.
|
|
1650
|
+
`;
|
|
1651
|
+
var LEGACY_RISKS = `---
|
|
1652
|
+
type: legacy-risks
|
|
1653
|
+
updated_at: YYYY-MM-DD
|
|
1654
|
+
---
|
|
1655
|
+
|
|
1656
|
+
# Legacy Risks
|
|
1657
|
+
|
|
1658
|
+
> High-risk areas to know before changing legacy code. Refine with legacy-agent.
|
|
1659
|
+
|
|
1660
|
+
## RISK-001 \u2014 <Area>
|
|
1661
|
+
|
|
1662
|
+
**What:** ...
|
|
1663
|
+
**Why risky:** ...
|
|
1664
|
+
**Blast radius:** ...
|
|
1665
|
+
**Mitigation:** ...
|
|
1666
|
+
|
|
1667
|
+
${QUALITY}
|
|
1668
|
+
|
|
1669
|
+
- [ ] Risks are specific to code areas, not vague.
|
|
1670
|
+
- [ ] Blast radius is estimated.
|
|
1671
|
+
`;
|
|
1672
|
+
var LEGACY_UNKNOWNS = `---
|
|
1673
|
+
type: legacy-unknowns
|
|
1674
|
+
updated_at: YYYY-MM-DD
|
|
1675
|
+
---
|
|
1676
|
+
|
|
1677
|
+
# Legacy Unknowns
|
|
1678
|
+
|
|
1679
|
+
> What we do not yet understand about the legacy system. Refine with legacy-agent.
|
|
1680
|
+
|
|
1681
|
+
## UNK-001 \u2014 <Question>
|
|
1682
|
+
|
|
1683
|
+
**Question:** ...
|
|
1684
|
+
**Why it matters:** ...
|
|
1685
|
+
**How to find out:** ...
|
|
1686
|
+
|
|
1687
|
+
${QUALITY}
|
|
1688
|
+
|
|
1689
|
+
- [ ] Each unknown has a way to resolve it.
|
|
1690
|
+
- [ ] Unknowns are not silently turned into assumptions.
|
|
1691
|
+
`;
|
|
1692
|
+
var MODERNIZATION_CANDIDATES = `---
|
|
1693
|
+
type: modernization-candidates
|
|
1694
|
+
updated_at: YYYY-MM-DD
|
|
1695
|
+
---
|
|
1696
|
+
|
|
1697
|
+
# Modernization Candidates
|
|
1698
|
+
|
|
1699
|
+
> Candidate modernization efforts for human review. Not commitments.
|
|
1700
|
+
|
|
1701
|
+
## MOD-001 \u2014 <Candidate>
|
|
1702
|
+
|
|
1703
|
+
**Current state:** ...
|
|
1704
|
+
**Target state:** ...
|
|
1705
|
+
**Value:** ...
|
|
1706
|
+
**Risk:** ...
|
|
1707
|
+
**Suggested Knowledge Level:** K1 / K2 / K3 / K4
|
|
1708
|
+
|
|
1709
|
+
${QUALITY}
|
|
1710
|
+
|
|
1711
|
+
- [ ] Candidates state value and risk.
|
|
1712
|
+
- [ ] Marked as candidates, not decisions.
|
|
1713
|
+
`;
|
|
1714
|
+
var BUSINESS_PRODUCT_BRIEF = `---
|
|
1715
|
+
type: product-brief
|
|
1716
|
+
status: draft
|
|
1717
|
+
---
|
|
1718
|
+
|
|
1719
|
+
# Product Brief
|
|
1720
|
+
|
|
1721
|
+
> Created by \`kaddo bootstrap\`. Refine with the business-agent. Mark unknowns as TBD.
|
|
1722
|
+
|
|
1723
|
+
## What is this product?
|
|
1724
|
+
|
|
1725
|
+
TBD
|
|
1726
|
+
|
|
1727
|
+
## Problem it solves
|
|
1728
|
+
|
|
1729
|
+
TBD
|
|
1730
|
+
|
|
1731
|
+
## Target users
|
|
1732
|
+
|
|
1733
|
+
TBD
|
|
1734
|
+
|
|
1735
|
+
## Value proposition
|
|
1736
|
+
|
|
1737
|
+
TBD
|
|
1738
|
+
|
|
1739
|
+
## Out of scope (for the MVP)
|
|
1740
|
+
|
|
1741
|
+
- TBD
|
|
1742
|
+
|
|
1743
|
+
## Assumptions
|
|
1744
|
+
|
|
1745
|
+
- ...
|
|
1746
|
+
|
|
1747
|
+
## Open questions
|
|
1748
|
+
|
|
1749
|
+
- ...
|
|
1750
|
+
|
|
1751
|
+
${QUALITY}
|
|
1752
|
+
|
|
1753
|
+
- [ ] The product can be described in one paragraph.
|
|
1754
|
+
- [ ] The MVP boundary is explicit.
|
|
1755
|
+
`;
|
|
1756
|
+
var BUSINESS_PROBLEM = `---
|
|
1757
|
+
type: problem
|
|
1758
|
+
status: draft
|
|
1759
|
+
---
|
|
1760
|
+
|
|
1761
|
+
# Problem Statement
|
|
1762
|
+
|
|
1763
|
+
> Refine with the business-agent. Do not invent facts.
|
|
1764
|
+
|
|
1765
|
+
## Problem
|
|
1766
|
+
|
|
1767
|
+
TBD
|
|
1768
|
+
|
|
1769
|
+
## Who has it
|
|
1770
|
+
|
|
1771
|
+
TBD
|
|
1772
|
+
|
|
1773
|
+
## Why it matters now
|
|
1774
|
+
|
|
1775
|
+
TBD
|
|
1776
|
+
|
|
1777
|
+
## Current alternatives
|
|
1778
|
+
|
|
1779
|
+
- TBD
|
|
1780
|
+
|
|
1781
|
+
## Assumptions
|
|
1782
|
+
|
|
1783
|
+
- ...
|
|
1784
|
+
|
|
1785
|
+
## Open questions
|
|
1786
|
+
|
|
1787
|
+
- ...
|
|
1788
|
+
|
|
1789
|
+
${QUALITY}
|
|
1790
|
+
|
|
1791
|
+
- [ ] The problem is stated without assuming the solution.
|
|
1792
|
+
- [ ] The affected users are named.
|
|
1793
|
+
`;
|
|
1794
|
+
var BUSINESS_USERS = `---
|
|
1795
|
+
type: users
|
|
1796
|
+
status: draft
|
|
1797
|
+
---
|
|
1798
|
+
|
|
1799
|
+
# Users & Personas
|
|
1800
|
+
|
|
1801
|
+
> Refine with the business-agent.
|
|
1802
|
+
|
|
1803
|
+
## Primary users
|
|
1804
|
+
|
|
1805
|
+
- TBD
|
|
1806
|
+
|
|
1807
|
+
## Secondary users
|
|
1808
|
+
|
|
1809
|
+
- TBD
|
|
1810
|
+
|
|
1811
|
+
## Needs & goals
|
|
1812
|
+
|
|
1813
|
+
- TBD
|
|
1814
|
+
|
|
1815
|
+
## Assumptions
|
|
1816
|
+
|
|
1817
|
+
- ...
|
|
1818
|
+
|
|
1819
|
+
## Open questions
|
|
1820
|
+
|
|
1821
|
+
- ...
|
|
1822
|
+
|
|
1823
|
+
${QUALITY}
|
|
1824
|
+
|
|
1825
|
+
- [ ] Each persona has a goal, not just a label.
|
|
1826
|
+
- [ ] Primary vs secondary users are distinguished.
|
|
1827
|
+
`;
|
|
1828
|
+
var BUSINESS_VALUE_PROPOSITION = `---
|
|
1829
|
+
type: value-proposition
|
|
1830
|
+
status: draft
|
|
1831
|
+
---
|
|
1832
|
+
|
|
1833
|
+
# Value Proposition
|
|
1834
|
+
|
|
1835
|
+
> Refine with the business-agent.
|
|
1836
|
+
|
|
1837
|
+
## For whom
|
|
1838
|
+
|
|
1839
|
+
TBD
|
|
1840
|
+
|
|
1841
|
+
## What we offer
|
|
1842
|
+
|
|
1843
|
+
TBD
|
|
1844
|
+
|
|
1845
|
+
## Why it is better / different
|
|
1846
|
+
|
|
1847
|
+
TBD
|
|
1848
|
+
|
|
1849
|
+
## Assumptions
|
|
1850
|
+
|
|
1851
|
+
- ...
|
|
1852
|
+
|
|
1853
|
+
## Open questions
|
|
1854
|
+
|
|
1855
|
+
- ...
|
|
1856
|
+
|
|
1857
|
+
${QUALITY}
|
|
1858
|
+
|
|
1859
|
+
- [ ] The value is specific, not generic.
|
|
1860
|
+
- [ ] It maps to a real user need.
|
|
1861
|
+
`;
|
|
1862
|
+
var BUSINESS_RULES = `---
|
|
1863
|
+
type: business-rules
|
|
1864
|
+
status: draft
|
|
1865
|
+
---
|
|
1866
|
+
|
|
1867
|
+
# Business Rules
|
|
1868
|
+
|
|
1869
|
+
> Refine with the business-agent. These are product rules, not implementation details.
|
|
1870
|
+
|
|
1871
|
+
## Core rules
|
|
1872
|
+
|
|
1873
|
+
- TBD
|
|
1874
|
+
|
|
1875
|
+
## Edge cases
|
|
1876
|
+
|
|
1877
|
+
- TBD
|
|
1878
|
+
|
|
1879
|
+
## Assumptions
|
|
1880
|
+
|
|
1881
|
+
- ...
|
|
1882
|
+
|
|
1883
|
+
## Open questions
|
|
1884
|
+
|
|
1885
|
+
- ...
|
|
1886
|
+
|
|
1887
|
+
${QUALITY}
|
|
1888
|
+
|
|
1889
|
+
- [ ] Rules are testable statements.
|
|
1890
|
+
- [ ] No implementation detail leaks in.
|
|
1891
|
+
`;
|
|
1892
|
+
var BUSINESS_CONSTRAINTS = `---
|
|
1893
|
+
type: constraints
|
|
1894
|
+
status: draft
|
|
1895
|
+
---
|
|
1896
|
+
|
|
1897
|
+
# Constraints
|
|
1898
|
+
|
|
1899
|
+
> Refine with the business-agent.
|
|
1900
|
+
|
|
1901
|
+
## Business constraints
|
|
1902
|
+
|
|
1903
|
+
- TBD
|
|
1904
|
+
|
|
1905
|
+
## Regulatory / compliance
|
|
1906
|
+
|
|
1907
|
+
- TBD
|
|
1908
|
+
|
|
1909
|
+
## Time / budget / team
|
|
1910
|
+
|
|
1911
|
+
- TBD
|
|
1912
|
+
|
|
1913
|
+
## Assumptions
|
|
1914
|
+
|
|
1915
|
+
- ...
|
|
1916
|
+
|
|
1917
|
+
## Open questions
|
|
1918
|
+
|
|
1919
|
+
- ...
|
|
1920
|
+
|
|
1921
|
+
${QUALITY}
|
|
1922
|
+
|
|
1923
|
+
- [ ] Constraints are real, not aspirational.
|
|
1924
|
+
- [ ] Hard limits are separated from preferences.
|
|
1925
|
+
`;
|
|
1926
|
+
var BUSINESS_GLOSSARY = `---
|
|
1927
|
+
type: glossary
|
|
1928
|
+
status: draft
|
|
1929
|
+
---
|
|
1930
|
+
|
|
1931
|
+
# Glossary
|
|
1932
|
+
|
|
1933
|
+
> Refine with the business-agent. One shared vocabulary avoids ambiguity.
|
|
1934
|
+
|
|
1935
|
+
| Term | Definition |
|
|
1936
|
+
|---|---|
|
|
1937
|
+
| TBD | TBD |
|
|
1938
|
+
|
|
1939
|
+
## Open questions
|
|
1940
|
+
|
|
1941
|
+
- ...
|
|
1942
|
+
|
|
1943
|
+
${QUALITY}
|
|
1944
|
+
|
|
1945
|
+
- [ ] Each term has a single agreed definition.
|
|
1946
|
+
- [ ] Ambiguous terms are flagged.
|
|
1947
|
+
`;
|
|
1948
|
+
var QUALITY_ATTRIBUTES = `---
|
|
1949
|
+
type: quality-attributes
|
|
1950
|
+
status: draft
|
|
1951
|
+
---
|
|
1952
|
+
|
|
1953
|
+
# Quality Attributes
|
|
1954
|
+
|
|
1955
|
+
> Created by \`kaddo bootstrap\`. Refine with the bootstrap-agent. Prioritize honestly.
|
|
1956
|
+
|
|
1957
|
+
## What matters most
|
|
1958
|
+
|
|
1959
|
+
- TBD (e.g. reliability, performance, security, maintainability, cost)
|
|
1960
|
+
|
|
1961
|
+
## Trade-offs accepted
|
|
1962
|
+
|
|
1963
|
+
- TBD
|
|
1964
|
+
|
|
1965
|
+
## Measurable targets (if known)
|
|
1966
|
+
|
|
1967
|
+
- TBD
|
|
1968
|
+
|
|
1969
|
+
## Assumptions
|
|
1970
|
+
|
|
1971
|
+
- ...
|
|
1972
|
+
|
|
1973
|
+
## Open questions
|
|
1974
|
+
|
|
1975
|
+
- ...
|
|
1976
|
+
|
|
1977
|
+
${QUALITY}
|
|
1978
|
+
|
|
1979
|
+
- [ ] Attributes are prioritized, not all "high".
|
|
1980
|
+
- [ ] Trade-offs are explicit.
|
|
1981
|
+
`;
|
|
1982
|
+
var BUSINESS_CONSOLIDATED = `---
|
|
1983
|
+
type: business
|
|
1984
|
+
status: draft
|
|
1985
|
+
---
|
|
1986
|
+
|
|
1987
|
+
# Business
|
|
1988
|
+
|
|
1989
|
+
> Created by \`kaddo bootstrap\`. The minimal **why** of the project. Refine with the
|
|
1990
|
+
> business-agent. As this matures it can split into problem.md, users.md, \u2026
|
|
1991
|
+
|
|
1992
|
+
## Problem
|
|
1993
|
+
|
|
1994
|
+
TBD
|
|
1995
|
+
|
|
1996
|
+
## Users
|
|
1997
|
+
|
|
1998
|
+
TBD
|
|
1999
|
+
|
|
2000
|
+
## Value Proposition
|
|
2001
|
+
|
|
2002
|
+
TBD
|
|
2003
|
+
|
|
2004
|
+
## Business Rules
|
|
2005
|
+
|
|
2006
|
+
- TBD
|
|
2007
|
+
|
|
2008
|
+
## Constraints
|
|
2009
|
+
|
|
2010
|
+
- TBD
|
|
2011
|
+
|
|
2012
|
+
## Assumptions
|
|
2013
|
+
|
|
2014
|
+
- ...
|
|
2015
|
+
|
|
2016
|
+
## Open Questions
|
|
2017
|
+
|
|
2018
|
+
- ...
|
|
2019
|
+
|
|
2020
|
+
${QUALITY}
|
|
2021
|
+
|
|
2022
|
+
- [ ] The problem is stated without assuming the solution.
|
|
2023
|
+
- [ ] Users have goals, not just labels.
|
|
2024
|
+
`;
|
|
2025
|
+
var PRODUCT_CONSOLIDATED = `---
|
|
2026
|
+
type: product
|
|
2027
|
+
status: draft
|
|
2028
|
+
---
|
|
2029
|
+
|
|
2030
|
+
# Product
|
|
2031
|
+
|
|
2032
|
+
> Created by \`kaddo bootstrap\`. The minimal **what** of the project. Refine with the
|
|
2033
|
+
> bootstrap-agent / capability-agent. As this matures it can split into product-brief.md
|
|
2034
|
+
> and capabilities.md.
|
|
2035
|
+
|
|
2036
|
+
## Product Brief
|
|
2037
|
+
|
|
2038
|
+
TBD
|
|
2039
|
+
|
|
2040
|
+
## Capabilities
|
|
2041
|
+
|
|
2042
|
+
- TBD
|
|
2043
|
+
|
|
2044
|
+
## Scope
|
|
2045
|
+
|
|
2046
|
+
- TBD
|
|
2047
|
+
|
|
2048
|
+
## Out of Scope
|
|
2049
|
+
|
|
2050
|
+
- TBD
|
|
2051
|
+
|
|
2052
|
+
## Success Criteria
|
|
2053
|
+
|
|
2054
|
+
- TBD
|
|
2055
|
+
|
|
2056
|
+
## Assumptions
|
|
2057
|
+
|
|
2058
|
+
- ...
|
|
2059
|
+
|
|
2060
|
+
## Open Questions
|
|
2061
|
+
|
|
2062
|
+
- ...
|
|
2063
|
+
|
|
2064
|
+
${QUALITY}
|
|
2065
|
+
|
|
2066
|
+
- [ ] The product fits in one page.
|
|
2067
|
+
- [ ] Scope and out-of-scope are explicit.
|
|
2068
|
+
`;
|
|
2069
|
+
var CODEBASE_FOUNDATION = `---
|
|
2070
|
+
type: codebase
|
|
2071
|
+
status: draft
|
|
2072
|
+
---
|
|
2073
|
+
|
|
2074
|
+
# Codebase
|
|
2075
|
+
|
|
2076
|
+
> Created by \`kaddo bootstrap\`. The minimal **how** of the project. Refine with the
|
|
2077
|
+
> codebase-agent. It describes the intended base \u2014 it does **not** generate code.
|
|
2078
|
+
|
|
2079
|
+
## Repository Structure
|
|
2080
|
+
|
|
2081
|
+
TBD
|
|
2082
|
+
|
|
2083
|
+
## Candidate Stack
|
|
2084
|
+
|
|
2085
|
+
- TBD
|
|
2086
|
+
|
|
2087
|
+
## Quality Attributes
|
|
697
2088
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
2089
|
+
- TBD
|
|
2090
|
+
|
|
2091
|
+
## Development Standards
|
|
2092
|
+
|
|
2093
|
+
- TBD
|
|
2094
|
+
|
|
2095
|
+
## Git Strategy
|
|
2096
|
+
|
|
2097
|
+
GitHub Flow + Conventional Commits + SemVer (default). See \`kaddo add git-strategy\`.
|
|
2098
|
+
|
|
2099
|
+
## Initial Modules
|
|
2100
|
+
|
|
2101
|
+
- TBD
|
|
2102
|
+
|
|
2103
|
+
## Assumptions
|
|
2104
|
+
|
|
2105
|
+
- ...
|
|
2106
|
+
|
|
2107
|
+
## Open Questions
|
|
2108
|
+
|
|
2109
|
+
- ...
|
|
2110
|
+
|
|
2111
|
+
${QUALITY}
|
|
2112
|
+
|
|
2113
|
+
- [ ] Structure follows business and product, not a framework default.
|
|
2114
|
+
- [ ] No production code is described here \u2014 only the foundation.
|
|
2115
|
+
`;
|
|
2116
|
+
var BOOTSTRAP_SUMMARY = `---
|
|
2117
|
+
type: bootstrap-summary
|
|
2118
|
+
status: draft
|
|
2119
|
+
---
|
|
2120
|
+
|
|
2121
|
+
# Bootstrap Summary
|
|
2122
|
+
|
|
2123
|
+
> Created by \`kaddo bootstrap\`. Index of the initial knowledge base and next steps.
|
|
2124
|
+
|
|
2125
|
+
## Layers
|
|
2126
|
+
|
|
2127
|
+
- **Business** \u2014 \`knowledge/business/\`
|
|
2128
|
+
- **Architecture** \u2014 capabilities, quality-attributes, stack, current-state, decisions
|
|
2129
|
+
- **Codebase** \u2014 codebase-foundation, standards, git-strategy
|
|
2130
|
+
- **Development** \u2014 roadmap, work-items
|
|
2131
|
+
|
|
2132
|
+
## Status
|
|
2133
|
+
|
|
2134
|
+
- [ ] Business defined
|
|
2135
|
+
- [ ] Initial architecture proposed
|
|
2136
|
+
- [ ] Codebase foundation drafted
|
|
2137
|
+
- [ ] Roadmap and first Work Items prepared
|
|
2138
|
+
|
|
2139
|
+
## Next steps
|
|
2140
|
+
|
|
2141
|
+
1. Run \`kaddo context\` and \`kaddo add agents\`.
|
|
2142
|
+
2. Refine the artifacts with the business-agent, bootstrap-agent and
|
|
2143
|
+
codebase-agent in your LLM.
|
|
2144
|
+
3. Run \`kaddo create --from roadmap\` to create the first Work Items.
|
|
2145
|
+
|
|
2146
|
+
## Open questions
|
|
2147
|
+
|
|
2148
|
+
- ...
|
|
2149
|
+
|
|
2150
|
+
${QUALITY}
|
|
2151
|
+
|
|
2152
|
+
- [ ] Every generated artifact is listed.
|
|
2153
|
+
- [ ] The next step is clear.
|
|
2154
|
+
`;
|
|
716
2155
|
|
|
717
2156
|
// ../cli/src/core/capsule.ts
|
|
718
|
-
var
|
|
2157
|
+
var KNOWLEDGE2 = "knowledge";
|
|
719
2158
|
function today() {
|
|
720
2159
|
return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
721
2160
|
}
|
|
@@ -732,16 +2171,16 @@ function readIf(dir, rel) {
|
|
|
732
2171
|
return exists(p) ? readFile(p) : null;
|
|
733
2172
|
}
|
|
734
2173
|
function headings(md) {
|
|
735
|
-
return md.split(/\r?\n/).map((
|
|
2174
|
+
return md.split(/\r?\n/).map((l2) => l2.match(/^#{2,3}\s+(.+?)\s*$/)).filter((m2) => Boolean(m2)).map((m2) => m2[1].trim()).filter((h2) => !/^(summary|resumen|overview|risks|owners|out of scope)$/i.test(h2));
|
|
736
2175
|
}
|
|
737
2176
|
function buildCapsule(dir, config) {
|
|
738
2177
|
const ownerMap = loadOwners(dir);
|
|
739
2178
|
const owners = [...new Set(Object.values(ownerMap).flat())];
|
|
740
2179
|
const all = discoverKnowledge(dir);
|
|
741
|
-
const purposeSrc = readIf(dir, `${
|
|
742
|
-
const capsMd = readIf(dir, `${
|
|
743
|
-
const risksMd = readIf(dir, `${
|
|
744
|
-
const adrs = all.filter((
|
|
2180
|
+
const purposeSrc = readIf(dir, `${KNOWLEDGE2}/business/business.md`) ?? readIf(dir, `${KNOWLEDGE2}/knowledge.md`) ?? "";
|
|
2181
|
+
const capsMd = readIf(dir, `${KNOWLEDGE2}/product/capabilities.md`);
|
|
2182
|
+
const risksMd = readIf(dir, `${KNOWLEDGE2}/legacy/risks.md`);
|
|
2183
|
+
const adrs = all.filter((a2) => a2.filePath.replace(/\\/g, "/").includes("/tech/decisions/") && Boolean(a2.type)).map((a2) => a2.title || a2.id).filter(Boolean);
|
|
745
2184
|
return {
|
|
746
2185
|
system: config.project.name,
|
|
747
2186
|
version: 1,
|
|
@@ -813,7 +2252,7 @@ function loadExternalRegistry(dir) {
|
|
|
813
2252
|
const p = join(dir, EXTERNAL_PATH);
|
|
814
2253
|
if (!exists(p)) return [];
|
|
815
2254
|
try {
|
|
816
|
-
const parsed =
|
|
2255
|
+
const parsed = parseYaml6(readFile(p));
|
|
817
2256
|
return Array.isArray(parsed?.external) ? parsed.external : [];
|
|
818
2257
|
} catch {
|
|
819
2258
|
return [];
|
|
@@ -822,20 +2261,20 @@ function loadExternalRegistry(dir) {
|
|
|
822
2261
|
function sectionList(md, title) {
|
|
823
2262
|
const re = new RegExp(`^##\\s+${title}\\s*$`, "im");
|
|
824
2263
|
const lines = md.split(/\r?\n/);
|
|
825
|
-
const start = lines.findIndex((
|
|
2264
|
+
const start = lines.findIndex((l2) => re.test(l2));
|
|
826
2265
|
if (start < 0) return [];
|
|
827
2266
|
const out = [];
|
|
828
2267
|
for (let i = start + 1; i < lines.length; i++) {
|
|
829
2268
|
if (/^##\s+/.test(lines[i])) break;
|
|
830
|
-
const
|
|
831
|
-
if (
|
|
2269
|
+
const m2 = lines[i].match(/^\s*-\s+(.+?)\s*$/);
|
|
2270
|
+
if (m2 && !/^_.*_$/.test(m2[1])) out.push(m2[1].trim());
|
|
832
2271
|
}
|
|
833
2272
|
return out;
|
|
834
2273
|
}
|
|
835
2274
|
function sectionParagraph2(md, title) {
|
|
836
2275
|
const re = new RegExp(`^##\\s+${title}\\s*$`, "im");
|
|
837
2276
|
const lines = md.split(/\r?\n/);
|
|
838
|
-
const start = lines.findIndex((
|
|
2277
|
+
const start = lines.findIndex((l2) => re.test(l2));
|
|
839
2278
|
if (start < 0) return "";
|
|
840
2279
|
for (let i = start + 1; i < lines.length; i++) {
|
|
841
2280
|
if (/^##\s+/.test(lines[i])) break;
|
|
@@ -849,8 +2288,8 @@ function parseCapsule(id, path3, md) {
|
|
|
849
2288
|
const updatedAt = data.updated_at ? String(data.updated_at) : void 0;
|
|
850
2289
|
let ageDays = null;
|
|
851
2290
|
if (updatedAt) {
|
|
852
|
-
const
|
|
853
|
-
if (!Number.isNaN(
|
|
2291
|
+
const d3 = Date.parse(updatedAt);
|
|
2292
|
+
if (!Number.isNaN(d3)) ageDays = Math.max(0, Math.floor((Date.now() - d3) / 864e5));
|
|
854
2293
|
}
|
|
855
2294
|
return {
|
|
856
2295
|
id,
|
|
@@ -879,7 +2318,7 @@ function loadExternalCapsules(dir) {
|
|
|
879
2318
|
}
|
|
880
2319
|
|
|
881
2320
|
// ../cli/src/core/graph.ts
|
|
882
|
-
var
|
|
2321
|
+
var KNOWLEDGE3 = "knowledge";
|
|
883
2322
|
var ACTIVE_STATUSES = ["draft", "ready", "in-progress", "blocked"];
|
|
884
2323
|
var ALL_STATUSES = ["draft", "ready", "in-progress", "blocked", "completed"];
|
|
885
2324
|
function scopeStatuses(scope) {
|
|
@@ -891,8 +2330,8 @@ function toPosix3(p) {
|
|
|
891
2330
|
function slug(s) {
|
|
892
2331
|
return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
893
2332
|
}
|
|
894
|
-
function isAdr(
|
|
895
|
-
return toPosix3(
|
|
2333
|
+
function isAdr(a2) {
|
|
2334
|
+
return toPosix3(a2.filePath).includes("/tech/decisions/") && Boolean(a2.type);
|
|
896
2335
|
}
|
|
897
2336
|
function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
898
2337
|
const scope = opts.scope ?? "active";
|
|
@@ -916,7 +2355,7 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
916
2355
|
];
|
|
917
2356
|
const presentLayers = [];
|
|
918
2357
|
for (const layer2 of layerDocs) {
|
|
919
|
-
const path3 = layer2.files.map((
|
|
2358
|
+
const path3 = layer2.files.map((f3) => `${KNOWLEDGE3}/${f3}`).find((rel) => exists(join(dir, rel)));
|
|
920
2359
|
if (path3) {
|
|
921
2360
|
addNode({ id: layer2.id, type: layer2.type, label: layer2.label, path: path3 });
|
|
922
2361
|
presentLayers.push(layer2.id);
|
|
@@ -926,11 +2365,11 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
926
2365
|
addEdge(presentLayers[i], presentLayers[i + 1], "informs");
|
|
927
2366
|
}
|
|
928
2367
|
const all = discoverKnowledge(dir);
|
|
929
|
-
const workItems = all.filter((
|
|
2368
|
+
const workItems = all.filter((a2) => a2.isWorkItem);
|
|
930
2369
|
const { included, excluded } = scopeStatuses(scope);
|
|
931
2370
|
const includedSet = new Set(included);
|
|
932
|
-
const activeWICount = workItems.filter((
|
|
933
|
-
const selectedWIs = workItems.filter((
|
|
2371
|
+
const activeWICount = workItems.filter((a2) => a2.lifecycle && isActiveState(a2.lifecycle)).length;
|
|
2372
|
+
const selectedWIs = workItems.filter((a2) => a2.lifecycle && includedSet.has(a2.lifecycle));
|
|
934
2373
|
for (const wi of selectedWIs) {
|
|
935
2374
|
const id = wi.id || wi.title;
|
|
936
2375
|
const wiNodeId = `wi:${id}`;
|
|
@@ -1076,20 +2515,20 @@ function loadGraphSummary(dir) {
|
|
|
1076
2515
|
}
|
|
1077
2516
|
|
|
1078
2517
|
// ../cli/src/core/graph-hints.ts
|
|
1079
|
-
var
|
|
2518
|
+
var KNOWLEDGE4 = "knowledge";
|
|
1080
2519
|
function toPosix4(p) {
|
|
1081
2520
|
return p.replace(/\\/g, "/");
|
|
1082
2521
|
}
|
|
1083
2522
|
function slug2(s) {
|
|
1084
2523
|
return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1085
2524
|
}
|
|
1086
|
-
function isAdr2(
|
|
1087
|
-
return toPosix4(
|
|
2525
|
+
function isAdr2(a2) {
|
|
2526
|
+
return toPosix4(a2.filePath).includes("/tech/decisions/") && Boolean(a2.type);
|
|
1088
2527
|
}
|
|
1089
2528
|
function capabilityHeadings(dir) {
|
|
1090
|
-
const p = join(dir,
|
|
2529
|
+
const p = join(dir, KNOWLEDGE4, "product", "capabilities.md");
|
|
1091
2530
|
if (!exists(p)) return [];
|
|
1092
|
-
return readFile(p).split(/\r?\n/).map((
|
|
2531
|
+
return readFile(p).split(/\r?\n/).map((l2) => l2.match(/^#{2,3}\s+(.+?)\s*$/)).filter((m2) => Boolean(m2)).map((m2) => m2[1].trim()).filter((h2) => !/^(summary|resumen|overview|capabilities|capacidades)$/i.test(h2));
|
|
1093
2532
|
}
|
|
1094
2533
|
function humanMissing(field) {
|
|
1095
2534
|
switch (field) {
|
|
@@ -1107,15 +2546,15 @@ function humanMissing(field) {
|
|
|
1107
2546
|
}
|
|
1108
2547
|
function buildGraphHints(dir, graph, now = /* @__PURE__ */ new Date()) {
|
|
1109
2548
|
const artifacts = discoverKnowledge(dir);
|
|
1110
|
-
const workItems = artifacts.filter((
|
|
1111
|
-
const activeWIs = workItems.filter((
|
|
2549
|
+
const workItems = artifacts.filter((a2) => a2.isWorkItem);
|
|
2550
|
+
const activeWIs = workItems.filter((a2) => a2.lifecycle && isActiveState(a2.lifecycle));
|
|
1112
2551
|
const adrs = artifacts.filter(isAdr2);
|
|
1113
2552
|
const capsules = loadExternalRegistry(dir);
|
|
1114
2553
|
const hints = [];
|
|
1115
2554
|
const referencedCapabilitySlugs = new Set(
|
|
1116
|
-
workItems.flatMap((
|
|
2555
|
+
workItems.flatMap((w3) => w3.capabilities.map((c) => slug2(c)))
|
|
1117
2556
|
);
|
|
1118
|
-
const referencedCapsuleIds = new Set(workItems.flatMap((
|
|
2557
|
+
const referencedCapsuleIds = new Set(workItems.flatMap((w3) => w3.capsules.map((c) => c)));
|
|
1119
2558
|
let activeWithoutCode = 0;
|
|
1120
2559
|
let activeWithoutCapabilities = 0;
|
|
1121
2560
|
let wisWithoutSource = 0;
|
|
@@ -1239,8 +2678,8 @@ var QUALITY_NOTE = {
|
|
|
1239
2678
|
};
|
|
1240
2679
|
function yamlBlock(fm) {
|
|
1241
2680
|
const lines = ["```yaml"];
|
|
1242
|
-
for (const [
|
|
1243
|
-
lines.push(`${
|
|
2681
|
+
for (const [k2, vals] of Object.entries(fm)) {
|
|
2682
|
+
lines.push(`${k2}:`);
|
|
1244
2683
|
for (const v of vals) lines.push(` - ${v}`);
|
|
1245
2684
|
}
|
|
1246
2685
|
lines.push("```");
|
|
@@ -1276,20 +2715,20 @@ function renderGraphHintsMarkdown(report) {
|
|
|
1276
2715
|
}
|
|
1277
2716
|
lines.push("## Hints");
|
|
1278
2717
|
lines.push("");
|
|
1279
|
-
for (const
|
|
1280
|
-
lines.push(`### ${
|
|
2718
|
+
for (const h2 of report.hints) {
|
|
2719
|
+
lines.push(`### ${h2.artifact_id}${h2.path ? ` \u2014 \`${h2.path}\`` : ""}`);
|
|
1281
2720
|
lines.push("");
|
|
1282
2721
|
lines.push("Missing metadata:");
|
|
1283
2722
|
lines.push("");
|
|
1284
|
-
for (const
|
|
2723
|
+
for (const m2 of h2.missing) lines.push(`- \`${m2}\``);
|
|
1285
2724
|
lines.push("");
|
|
1286
|
-
if (
|
|
2725
|
+
if (h2.suggested_front_matter) {
|
|
1287
2726
|
lines.push("Suggested front matter:");
|
|
1288
2727
|
lines.push("");
|
|
1289
|
-
lines.push(...yamlBlock(
|
|
2728
|
+
lines.push(...yamlBlock(h2.suggested_front_matter));
|
|
1290
2729
|
lines.push("");
|
|
1291
2730
|
}
|
|
1292
|
-
lines.push(`Reason: ${
|
|
2731
|
+
lines.push(`Reason: ${h2.reason}`);
|
|
1293
2732
|
lines.push("");
|
|
1294
2733
|
}
|
|
1295
2734
|
lines.push("> Use the `graph-agent` to turn these hints into precise front matter \u2014 you confirm and apply.");
|
|
@@ -1310,8 +2749,8 @@ function loadGraphHints(dir) {
|
|
|
1310
2749
|
scopeReason: String(report.scope_reason ?? ""),
|
|
1311
2750
|
quality: report.quality ?? "empty",
|
|
1312
2751
|
totalHints: hints.length,
|
|
1313
|
-
activeWorkItemHints: hints.filter((
|
|
1314
|
-
messages: hints.map((
|
|
2752
|
+
activeWorkItemHints: hints.filter((h2) => h2.artifact_type === "work-item").length,
|
|
2753
|
+
messages: hints.map((h2) => h2.message).filter(Boolean)
|
|
1315
2754
|
};
|
|
1316
2755
|
} catch {
|
|
1317
2756
|
return null;
|
|
@@ -1342,7 +2781,7 @@ function discoverInstalledSkills(dir) {
|
|
|
1342
2781
|
} catch {
|
|
1343
2782
|
}
|
|
1344
2783
|
}
|
|
1345
|
-
return out.sort((
|
|
2784
|
+
return out.sort((a2, b2) => a2.id.localeCompare(b2.id));
|
|
1346
2785
|
}
|
|
1347
2786
|
function skillGroupCounts(skills) {
|
|
1348
2787
|
const counts = {};
|
|
@@ -1350,67 +2789,8 @@ function skillGroupCounts(skills) {
|
|
|
1350
2789
|
return counts;
|
|
1351
2790
|
}
|
|
1352
2791
|
|
|
1353
|
-
// ../cli/src/services/mapped-modules.ts
|
|
1354
|
-
import { parse as parseYaml5 } from "yaml";
|
|
1355
|
-
var DESCRIPTOR_PATH = ".kaddo/modules.yml";
|
|
1356
|
-
function toStringArray(value) {
|
|
1357
|
-
return Array.isArray(value) ? value.map((v) => String(v)).filter(Boolean) : [];
|
|
1358
|
-
}
|
|
1359
|
-
function moduleArtifactCoverage(dir, id) {
|
|
1360
|
-
const base = join(dir, "knowledge", "tech", "modules", id);
|
|
1361
|
-
return {
|
|
1362
|
-
moduleDesign: exists(join(base, "module-design.md")),
|
|
1363
|
-
stack: exists(join(base, "stack.md")),
|
|
1364
|
-
security: exists(join(base, "security.md")),
|
|
1365
|
-
standards: exists(join(base, "standards.md")),
|
|
1366
|
-
diagrams: exists(join(base, "diagrams")),
|
|
1367
|
-
adrs: exists(join(base, "adrs"))
|
|
1368
|
-
};
|
|
1369
|
-
}
|
|
1370
|
-
function loadMappedModules(dir) {
|
|
1371
|
-
const path3 = join(dir, DESCRIPTOR_PATH);
|
|
1372
|
-
if (!exists(path3)) return [];
|
|
1373
|
-
let parsed;
|
|
1374
|
-
try {
|
|
1375
|
-
parsed = parseYaml5(readFile(path3));
|
|
1376
|
-
} catch {
|
|
1377
|
-
return [];
|
|
1378
|
-
}
|
|
1379
|
-
const raw = Array.isArray(parsed?.modules) ? parsed.modules : [];
|
|
1380
|
-
const modules = [];
|
|
1381
|
-
for (const entry of raw) {
|
|
1382
|
-
if (!entry || typeof entry !== "object") continue;
|
|
1383
|
-
const m = entry;
|
|
1384
|
-
const id = typeof m.id === "string" ? m.id : "";
|
|
1385
|
-
if (!id) continue;
|
|
1386
|
-
modules.push({
|
|
1387
|
-
id,
|
|
1388
|
-
name: typeof m.name === "string" ? m.name : void 0,
|
|
1389
|
-
repoPath: typeof m.repoPath === "string" ? m.repoPath : "",
|
|
1390
|
-
type: typeof m.type === "string" ? m.type : void 0,
|
|
1391
|
-
mainTechnology: typeof m.mainTechnology === "string" ? m.mainTechnology : void 0,
|
|
1392
|
-
owner: typeof m.owner === "string" ? m.owner : void 0,
|
|
1393
|
-
capabilities: toStringArray(m.capabilities),
|
|
1394
|
-
code: toStringArray(m.code),
|
|
1395
|
-
status: typeof m.status === "string" ? m.status : void 0,
|
|
1396
|
-
artifacts: moduleArtifactCoverage(dir, id)
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1399
|
-
return modules;
|
|
1400
|
-
}
|
|
1401
|
-
function presentArtifacts(coverage) {
|
|
1402
|
-
const present = [];
|
|
1403
|
-
if (coverage.moduleDesign) present.push("module-design");
|
|
1404
|
-
if (coverage.stack) present.push("stack");
|
|
1405
|
-
if (coverage.security) present.push("security");
|
|
1406
|
-
if (coverage.standards) present.push("standards");
|
|
1407
|
-
if (coverage.diagrams) present.push("diagrams");
|
|
1408
|
-
if (coverage.adrs) present.push("adrs");
|
|
1409
|
-
return present;
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
2792
|
// ../cli/src/core/knowledge-discovery.ts
|
|
1413
|
-
var
|
|
2793
|
+
var KNOWLEDGE5 = "knowledge";
|
|
1414
2794
|
var CONSOLIDATED_TYPE = {
|
|
1415
2795
|
Business: "business",
|
|
1416
2796
|
Product: "product",
|
|
@@ -1452,10 +2832,10 @@ function layerForType(type) {
|
|
|
1452
2832
|
}
|
|
1453
2833
|
function layerFromPath(filePath) {
|
|
1454
2834
|
const p = filePath.replace(/\\/g, "/");
|
|
1455
|
-
if (p.includes(`/${
|
|
1456
|
-
if (p.includes(`/${
|
|
1457
|
-
if (p.includes(`/${
|
|
1458
|
-
if (p.includes(`/${
|
|
2835
|
+
if (p.includes(`/${KNOWLEDGE5}/business/`)) return "Business";
|
|
2836
|
+
if (p.includes(`/${KNOWLEDGE5}/product/`)) return "Product";
|
|
2837
|
+
if (p.includes(`/${KNOWLEDGE5}/tech/`)) return "Tech";
|
|
2838
|
+
if (p.includes(`/${KNOWLEDGE5}/delivery/`)) return "Delivery";
|
|
1459
2839
|
return null;
|
|
1460
2840
|
}
|
|
1461
2841
|
function basename(p) {
|
|
@@ -1468,18 +2848,18 @@ function discoverLayers(dir) {
|
|
|
1468
2848
|
Tech: blank(),
|
|
1469
2849
|
Delivery: blank()
|
|
1470
2850
|
};
|
|
1471
|
-
const archDir = join(dir,
|
|
2851
|
+
const archDir = join(dir, KNOWLEDGE5);
|
|
1472
2852
|
const artifacts = exists(archDir) ? readArtifacts(archDir) : [];
|
|
1473
|
-
for (const
|
|
1474
|
-
const type =
|
|
1475
|
-
const layer2 = layerForType(type) ?? layerFromPath(
|
|
2853
|
+
for (const a2 of artifacts) {
|
|
2854
|
+
const type = a2.type;
|
|
2855
|
+
const layer2 = layerForType(type) ?? layerFromPath(a2.filePath);
|
|
1476
2856
|
if (!layer2) continue;
|
|
1477
2857
|
const slot = acc[layer2];
|
|
1478
|
-
slot.detected.add(basename(
|
|
2858
|
+
slot.detected.add(basename(a2.filePath));
|
|
1479
2859
|
if (layer2 === "Delivery") {
|
|
1480
|
-
if (type === "roadmap" || basename(
|
|
1481
|
-
if (WORK_ITEM_TYPES.has(type) ||
|
|
1482
|
-
if (
|
|
2860
|
+
if (type === "roadmap" || basename(a2.filePath) === "roadmap.md") slot.hasRoadmap = true;
|
|
2861
|
+
if (WORK_ITEM_TYPES.has(type) || a2.filePath.replace(/\\/g, "/").includes("/delivery/work-items/")) {
|
|
2862
|
+
if (a2.filePath.replace(/\\/g, "/").includes("/delivery/work-items/")) slot.hasWorkItem = true;
|
|
1483
2863
|
}
|
|
1484
2864
|
continue;
|
|
1485
2865
|
}
|
|
@@ -1490,7 +2870,7 @@ function discoverLayers(dir) {
|
|
|
1490
2870
|
}
|
|
1491
2871
|
if (type === "adr" || type === "decision") slot.hasDecision = true;
|
|
1492
2872
|
}
|
|
1493
|
-
if (existsDirWithMd(join(dir,
|
|
2873
|
+
if (existsDirWithMd(join(dir, KNOWLEDGE5, "tech", "decisions"))) acc.Tech.structured = true;
|
|
1494
2874
|
return ["Business", "Product", "Tech", "Delivery"].map((layer2) => ({
|
|
1495
2875
|
layer: layer2,
|
|
1496
2876
|
status: statusFor(layer2, acc[layer2]),
|
|
@@ -1507,22 +2887,22 @@ function blank() {
|
|
|
1507
2887
|
detected: /* @__PURE__ */ new Set()
|
|
1508
2888
|
};
|
|
1509
2889
|
}
|
|
1510
|
-
function existsDirWithMd(
|
|
1511
|
-
if (!exists(
|
|
2890
|
+
function existsDirWithMd(d3) {
|
|
2891
|
+
if (!exists(d3)) return false;
|
|
1512
2892
|
try {
|
|
1513
|
-
return readDir(
|
|
2893
|
+
return readDir(d3).some((e) => e.endsWith(".md") && isFile(join(d3, e)));
|
|
1514
2894
|
} catch {
|
|
1515
2895
|
return false;
|
|
1516
2896
|
}
|
|
1517
2897
|
}
|
|
1518
|
-
function statusFor(layer2,
|
|
2898
|
+
function statusFor(layer2, a2) {
|
|
1519
2899
|
if (layer2 === "Delivery") {
|
|
1520
|
-
if (
|
|
1521
|
-
if (
|
|
2900
|
+
if (a2.hasWorkItem) return "Traceable";
|
|
2901
|
+
if (a2.hasRoadmap) return "Partial";
|
|
1522
2902
|
return "Missing";
|
|
1523
2903
|
}
|
|
1524
|
-
if (
|
|
1525
|
-
if (
|
|
2904
|
+
if (a2.structured) return "Structured";
|
|
2905
|
+
if (a2.consolidated) return "Consolidated";
|
|
1526
2906
|
return "Missing";
|
|
1527
2907
|
}
|
|
1528
2908
|
|
|
@@ -1609,26 +2989,26 @@ function layerQuality(dir, layer2) {
|
|
|
1609
2989
|
const order = ["missing", "placeholder", "weak", "useful"];
|
|
1610
2990
|
let worst = null;
|
|
1611
2991
|
for (const rel of LAYER_BASELINE[layer2]) {
|
|
1612
|
-
const
|
|
1613
|
-
if (
|
|
1614
|
-
if (worst === null || order.indexOf(
|
|
2992
|
+
const q3 = analyzeKnowledgeArtifact(dir, rel);
|
|
2993
|
+
if (q3 === "missing") continue;
|
|
2994
|
+
if (worst === null || order.indexOf(q3) < order.indexOf(worst)) worst = q3;
|
|
1615
2995
|
}
|
|
1616
2996
|
return worst;
|
|
1617
2997
|
}
|
|
1618
2998
|
function knowledgeLayers(dir) {
|
|
1619
|
-
return discoverLayers(dir).map((
|
|
1620
|
-
if (
|
|
1621
|
-
const
|
|
1622
|
-
if (
|
|
1623
|
-
if (
|
|
1624
|
-
return
|
|
2999
|
+
return discoverLayers(dir).map((l2) => {
|
|
3000
|
+
if (l2.status !== "Consolidated" && l2.status !== "Structured") return l2;
|
|
3001
|
+
const q3 = layerQuality(dir, l2.layer);
|
|
3002
|
+
if (q3 === "placeholder") return { ...l2, status: "Placeholder" };
|
|
3003
|
+
if (q3 === "weak") return { ...l2, status: "Weak" };
|
|
3004
|
+
return l2;
|
|
1625
3005
|
});
|
|
1626
3006
|
}
|
|
1627
3007
|
function renderLayersMarkdown(layers) {
|
|
1628
3008
|
const lines = [];
|
|
1629
3009
|
for (const { layer: layer2, status, detected } of layers) {
|
|
1630
3010
|
lines.push(`### ${layer2} \u2014 ${status}`);
|
|
1631
|
-
if (detected.length > 0) for (const
|
|
3011
|
+
if (detected.length > 0) for (const d3 of detected) lines.push(`- \u2713 ${d3}`);
|
|
1632
3012
|
else lines.push("- \u2717 none");
|
|
1633
3013
|
lines.push("");
|
|
1634
3014
|
}
|
|
@@ -1648,10 +3028,10 @@ function splitInitiatives(markdown) {
|
|
|
1648
3028
|
const blocks = [];
|
|
1649
3029
|
let current = null;
|
|
1650
3030
|
for (const line of markdown.split(/\r?\n/)) {
|
|
1651
|
-
const
|
|
1652
|
-
if (
|
|
3031
|
+
const m2 = line.match(INITIATIVE_RE);
|
|
3032
|
+
if (m2) {
|
|
1653
3033
|
if (current) blocks.push(current);
|
|
1654
|
-
current = { initiative: { id:
|
|
3034
|
+
current = { initiative: { id: m2[1], title: m2[2].trim() || void 0 }, lines: [] };
|
|
1655
3035
|
continue;
|
|
1656
3036
|
}
|
|
1657
3037
|
if (current) current.lines.push(line);
|
|
@@ -1763,9 +3143,9 @@ function parseBlock(block) {
|
|
|
1763
3143
|
function decisionCandidatesFromSignals(signals) {
|
|
1764
3144
|
const out = [];
|
|
1765
3145
|
for (const sig of signals) {
|
|
1766
|
-
const
|
|
1767
|
-
if (!
|
|
1768
|
-
const rest =
|
|
3146
|
+
const m2 = sig.match(/decision candidate\s*:?\s*(.+)$/i);
|
|
3147
|
+
if (!m2) continue;
|
|
3148
|
+
const rest = m2[1].trim();
|
|
1769
3149
|
const token = rest.match(/\b[A-Z][A-Z0-9_]{2,}\b/);
|
|
1770
3150
|
const value = token ? token[0] : rest.replace(/[.。]+$/, "").trim();
|
|
1771
3151
|
if (value && !out.includes(value)) out.push(value);
|
|
@@ -1782,10 +3162,10 @@ function splitRow(line) {
|
|
|
1782
3162
|
function isSeparatorRow(cells) {
|
|
1783
3163
|
return cells.length > 0 && cells.every((c) => SEPARATOR_CELL_RE.test(c) || c === "");
|
|
1784
3164
|
}
|
|
1785
|
-
function initiativeFromHeading(
|
|
1786
|
-
const rm =
|
|
3165
|
+
function initiativeFromHeading(text3) {
|
|
3166
|
+
const rm = text3.match(/^(RM-[\w.-]+)\s*[:\-–]?\s*(.*)$/);
|
|
1787
3167
|
if (rm) return { id: rm[1], title: rm[2].trim() || void 0 };
|
|
1788
|
-
return { title:
|
|
3168
|
+
return { title: text3.trim() || void 0 };
|
|
1789
3169
|
}
|
|
1790
3170
|
function extractDeps(cell) {
|
|
1791
3171
|
if (!cell) return void 0;
|
|
@@ -1809,9 +3189,9 @@ function parseFlexible(markdown) {
|
|
|
1809
3189
|
});
|
|
1810
3190
|
};
|
|
1811
3191
|
for (const line of markdown.split(/\r?\n/)) {
|
|
1812
|
-
const
|
|
1813
|
-
if (
|
|
1814
|
-
initiative = initiativeFromHeading(
|
|
3192
|
+
const h2 = line.match(HEADING_RE);
|
|
3193
|
+
if (h2) {
|
|
3194
|
+
initiative = initiativeFromHeading(h2[1]);
|
|
1815
3195
|
cols = null;
|
|
1816
3196
|
continue;
|
|
1817
3197
|
}
|
|
@@ -1840,9 +3220,9 @@ function parseFlexible(markdown) {
|
|
|
1840
3220
|
}
|
|
1841
3221
|
continue;
|
|
1842
3222
|
}
|
|
1843
|
-
const
|
|
1844
|
-
if (
|
|
1845
|
-
push(
|
|
3223
|
+
const b2 = line.match(FLEX_BULLET_RE);
|
|
3224
|
+
if (b2) {
|
|
3225
|
+
push(b2[1], b2[2] ?? "", void 0, line);
|
|
1846
3226
|
continue;
|
|
1847
3227
|
}
|
|
1848
3228
|
}
|
|
@@ -1897,10 +3277,10 @@ var RESOLUTION_TOKENS = {
|
|
|
1897
3277
|
diferida: "deferred"
|
|
1898
3278
|
};
|
|
1899
3279
|
function parseResolution(line) {
|
|
1900
|
-
const
|
|
1901
|
-
if (
|
|
1902
|
-
const status = RESOLUTION_TOKENS[
|
|
1903
|
-
if (status) return { text:
|
|
3280
|
+
const m2 = line.match(/^\[([a-zA-Záéí]+)\]\s*(.*)$/);
|
|
3281
|
+
if (m2) {
|
|
3282
|
+
const status = RESOLUTION_TOKENS[m2[1].toLowerCase()];
|
|
3283
|
+
if (status) return { text: m2[2].trim(), resolution_status: status };
|
|
1904
3284
|
}
|
|
1905
3285
|
return { text: line.trim(), resolution_status: "open" };
|
|
1906
3286
|
}
|
|
@@ -1971,8 +3351,8 @@ var IMPORTANT = [
|
|
|
1971
3351
|
"permis",
|
|
1972
3352
|
"permission"
|
|
1973
3353
|
];
|
|
1974
|
-
function matchesAny(
|
|
1975
|
-
return keywords.some((
|
|
3354
|
+
function matchesAny(text3, keywords) {
|
|
3355
|
+
return keywords.some((k2) => text3.includes(k2));
|
|
1976
3356
|
}
|
|
1977
3357
|
function classifyQuestion(question) {
|
|
1978
3358
|
const t = question.toLowerCase();
|
|
@@ -1989,7 +3369,7 @@ function classifyQuestion(question) {
|
|
|
1989
3369
|
}
|
|
1990
3370
|
function extractFromMarkdown(md) {
|
|
1991
3371
|
const lines = md.split(/\r?\n/);
|
|
1992
|
-
const start = lines.findIndex((
|
|
3372
|
+
const start = lines.findIndex((l2) => /^#{1,6}\s+open questions\s*$/i.test(l2.trim()) || /^#{1,6}\s+preguntas abiertas\s*$/i.test(l2.trim()));
|
|
1993
3373
|
if (start < 0) return [];
|
|
1994
3374
|
const out = [];
|
|
1995
3375
|
for (let i = start + 1; i < lines.length; i++) {
|
|
@@ -2000,12 +3380,12 @@ function extractFromMarkdown(md) {
|
|
|
2000
3380
|
if (meta[1].toLowerCase() === "note") out[out.length - 1].resolution_note = meta[2].trim();
|
|
2001
3381
|
continue;
|
|
2002
3382
|
}
|
|
2003
|
-
const
|
|
2004
|
-
if (
|
|
2005
|
-
const bullet =
|
|
3383
|
+
const m2 = line.match(/^\s*(?:[-*]|\d+\.)\s+(.+?)\s*$/);
|
|
3384
|
+
if (m2) {
|
|
3385
|
+
const bullet = m2[1].trim();
|
|
2006
3386
|
if (!bullet || /^_.*_$/.test(bullet)) continue;
|
|
2007
|
-
const { text:
|
|
2008
|
-
if (
|
|
3387
|
+
const { text: text3, resolution_status } = parseResolution(bullet);
|
|
3388
|
+
if (text3) out.push({ text: text3, resolution_status, line: i + 1, raw: line.trim() });
|
|
2009
3389
|
}
|
|
2010
3390
|
}
|
|
2011
3391
|
return out;
|
|
@@ -2058,12 +3438,12 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2058
3438
|
});
|
|
2059
3439
|
}
|
|
2060
3440
|
}
|
|
2061
|
-
const blocking = questions.filter((
|
|
2062
|
-
const important = questions.filter((
|
|
2063
|
-
const deferred = questions.filter((
|
|
2064
|
-
const blockingOpen = blocking.filter((
|
|
2065
|
-
const importantOpen = important.filter((
|
|
2066
|
-
const byStatus = (s) => questions.filter((
|
|
3441
|
+
const blocking = questions.filter((q3) => q3.classification === "blocking");
|
|
3442
|
+
const important = questions.filter((q3) => q3.classification === "important");
|
|
3443
|
+
const deferred = questions.filter((q3) => q3.classification === "deferred");
|
|
3444
|
+
const blockingOpen = blocking.filter((q3) => q3.resolution_status === "open");
|
|
3445
|
+
const importantOpen = important.filter((q3) => q3.resolution_status === "open");
|
|
3446
|
+
const byStatus = (s) => questions.filter((q3) => q3.resolution_status === s);
|
|
2067
3447
|
const resolved = byStatus("resolved");
|
|
2068
3448
|
const assumed = byStatus("assumed");
|
|
2069
3449
|
const deferredStatus = byStatus("deferred");
|
|
@@ -2071,7 +3451,7 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2071
3451
|
if (questions.length === 0) readiness = "unknown";
|
|
2072
3452
|
else if (blockingOpen.length > 0) readiness = "needs_decisions";
|
|
2073
3453
|
else readiness = "ready";
|
|
2074
|
-
const suggested_assumptions = blockingOpen.map((
|
|
3454
|
+
const suggested_assumptions = blockingOpen.map((q3) => q3.suggested_assumption).filter(Boolean);
|
|
2075
3455
|
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.";
|
|
2076
3456
|
return {
|
|
2077
3457
|
generated_at: now.toISOString(),
|
|
@@ -2102,75 +3482,75 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2102
3482
|
recommended_next_step
|
|
2103
3483
|
};
|
|
2104
3484
|
}
|
|
2105
|
-
function renderOpenQuestionsMarkdown(
|
|
3485
|
+
function renderOpenQuestionsMarkdown(r2) {
|
|
2106
3486
|
const L = [];
|
|
2107
3487
|
L.push("# Kaddo Open Questions Readiness Report", "");
|
|
2108
|
-
L.push(`Generated at: ${
|
|
2109
|
-
L.push(`Project: ${
|
|
3488
|
+
L.push(`Generated at: ${r2.generated_at}`);
|
|
3489
|
+
L.push(`Project: ${r2.project}`);
|
|
2110
3490
|
L.push("");
|
|
2111
3491
|
L.push("## Summary", "");
|
|
2112
|
-
L.push(`- Open questions found: ${
|
|
2113
|
-
L.push(`- Roadmap readiness: ${
|
|
2114
|
-
L.push(`- By resolution \u2014 open: ${
|
|
2115
|
-
L.push(`- Blocking open: ${
|
|
3492
|
+
L.push(`- Open questions found: ${r2.summary.open_questions}`);
|
|
3493
|
+
L.push(`- Roadmap readiness: ${r2.summary.roadmap_readiness}`);
|
|
3494
|
+
L.push(`- By resolution \u2014 open: ${r2.summary.resolution.open}, resolved: ${r2.summary.resolution.resolved}, assumed: ${r2.summary.resolution.assumed}, deferred: ${r2.summary.resolution.deferred}`);
|
|
3495
|
+
L.push(`- Blocking open: ${r2.summary.blocking_open}, important open: ${r2.summary.important_open}`);
|
|
2116
3496
|
L.push("");
|
|
2117
|
-
if (
|
|
3497
|
+
if (r2.summary.open_questions === 0) {
|
|
2118
3498
|
L.push("No `## Open Questions` sections found in business / product / codebase / roadmap.", "");
|
|
2119
|
-
L.push("## Recommended Next Step", "",
|
|
3499
|
+
L.push("## Recommended Next Step", "", r2.recommended_next_step, "");
|
|
2120
3500
|
return L.join("\n");
|
|
2121
3501
|
}
|
|
2122
|
-
const blockingOpen =
|
|
3502
|
+
const blockingOpen = r2.blocking_questions.filter((q3) => q3.resolution_status === "open");
|
|
2123
3503
|
L.push("## Blocking Open Questions", "");
|
|
2124
3504
|
if (blockingOpen.length === 0) L.push("_None \u2014 nothing blocks readiness._", "");
|
|
2125
|
-
for (const
|
|
2126
|
-
L.push(`### ${
|
|
2127
|
-
L.push(`- Status: ${
|
|
2128
|
-
L.push(`- Severity: ${
|
|
2129
|
-
L.push(`- Source: \`${
|
|
2130
|
-
L.push(`- Reason: ${
|
|
3505
|
+
for (const q3 of blockingOpen) {
|
|
3506
|
+
L.push(`### ${q3.question}`, "");
|
|
3507
|
+
L.push(`- Status: ${q3.resolution_status}`);
|
|
3508
|
+
L.push(`- Severity: ${q3.classification}`);
|
|
3509
|
+
L.push(`- Source: \`${q3.sourcePath}:${q3.line}\``);
|
|
3510
|
+
L.push(`- Reason: ${q3.reason}`);
|
|
2131
3511
|
L.push("");
|
|
2132
3512
|
L.push("Suggested action:", "");
|
|
2133
3513
|
L.push("```md");
|
|
2134
|
-
L.push(`- [assumed] ${
|
|
2135
|
-
L.push(` - note: ${
|
|
3514
|
+
L.push(`- [assumed] ${q3.question}`);
|
|
3515
|
+
L.push(` - note: ${q3.suggested_assumption ?? "<editable assumption for the MVP>"}`);
|
|
2136
3516
|
L.push("```");
|
|
2137
3517
|
L.push("");
|
|
2138
3518
|
}
|
|
2139
3519
|
const renderStatusList = (title, items) => {
|
|
2140
3520
|
L.push(`## ${title}`, "");
|
|
2141
3521
|
if (items.length === 0) L.push("_None._");
|
|
2142
|
-
for (const
|
|
3522
|
+
for (const q3 of items) L.push(`- ${q3.question} \u2014 \`${q3.sourcePath}:${q3.line}\`${q3.note ? ` \u2014 _${q3.note}_` : ""}`);
|
|
2143
3523
|
L.push("");
|
|
2144
3524
|
};
|
|
2145
|
-
renderStatusList("Resolved",
|
|
2146
|
-
renderStatusList("Assumed (decisions to revisit)",
|
|
2147
|
-
renderStatusList("Deferred (out of current scope)",
|
|
3525
|
+
renderStatusList("Resolved", r2.resolved_questions);
|
|
3526
|
+
renderStatusList("Assumed (decisions to revisit)", r2.assumed_questions);
|
|
3527
|
+
renderStatusList("Deferred (out of current scope)", r2.deferred_status_questions);
|
|
2148
3528
|
L.push("## Important Questions", "");
|
|
2149
|
-
if (
|
|
2150
|
-
for (const
|
|
3529
|
+
if (r2.important_questions.length === 0) L.push("_None._");
|
|
3530
|
+
for (const q3 of r2.important_questions) L.push(`- [${q3.resolution_status}] ${q3.question}`);
|
|
2151
3531
|
L.push("");
|
|
2152
|
-
if (
|
|
3532
|
+
if (r2.suggested_assumptions.length > 0) {
|
|
2153
3533
|
L.push("## Suggested Assumptions", "");
|
|
2154
|
-
for (const
|
|
3534
|
+
for (const a2 of r2.suggested_assumptions) L.push(`- ${a2}`);
|
|
2155
3535
|
L.push("");
|
|
2156
3536
|
}
|
|
2157
|
-
L.push("## Recommended Next Step", "",
|
|
3537
|
+
L.push("## Recommended Next Step", "", r2.recommended_next_step, "");
|
|
2158
3538
|
return L.join("\n");
|
|
2159
3539
|
}
|
|
2160
|
-
function serializeOpenQuestionsJson(
|
|
2161
|
-
return JSON.stringify(
|
|
3540
|
+
function serializeOpenQuestionsJson(r2) {
|
|
3541
|
+
return JSON.stringify(r2, null, 2) + "\n";
|
|
2162
3542
|
}
|
|
2163
3543
|
function roadmapReadinessSummary(dir) {
|
|
2164
|
-
const
|
|
3544
|
+
const r2 = buildOpenQuestionsReport(dir);
|
|
2165
3545
|
return {
|
|
2166
|
-
roadmap_readiness:
|
|
2167
|
-
blocking_questions:
|
|
2168
|
-
blocking_open:
|
|
2169
|
-
important_questions:
|
|
2170
|
-
deferred_questions:
|
|
2171
|
-
resolution:
|
|
2172
|
-
suggested_assumptions:
|
|
2173
|
-
recommended_next_step:
|
|
3546
|
+
roadmap_readiness: r2.summary.roadmap_readiness,
|
|
3547
|
+
blocking_questions: r2.summary.blocking,
|
|
3548
|
+
blocking_open: r2.summary.blocking_open,
|
|
3549
|
+
important_questions: r2.summary.important,
|
|
3550
|
+
deferred_questions: r2.summary.deferred,
|
|
3551
|
+
resolution: r2.summary.resolution,
|
|
3552
|
+
suggested_assumptions: r2.suggested_assumptions,
|
|
3553
|
+
recommended_next_step: r2.summary.roadmap_readiness === "needs_decisions" ? "Resolve, assume, or defer blocking open questions before generating roadmap." : r2.recommended_next_step
|
|
2174
3554
|
};
|
|
2175
3555
|
}
|
|
2176
3556
|
|
|
@@ -2194,9 +3574,9 @@ function discoverAgents(dir) {
|
|
|
2194
3574
|
const base = join(dir, "knowledge", "agents");
|
|
2195
3575
|
if (!exists(base) || !isDir(base)) return [];
|
|
2196
3576
|
const out = /* @__PURE__ */ new Set();
|
|
2197
|
-
const walk = (
|
|
2198
|
-
for (const e of readDir(
|
|
2199
|
-
const full = join(
|
|
3577
|
+
const walk = (d3) => {
|
|
3578
|
+
for (const e of readDir(d3)) {
|
|
3579
|
+
const full = join(d3, e);
|
|
2200
3580
|
if (isDir(full)) walk(full);
|
|
2201
3581
|
else if (e.endsWith("-agent.md")) out.add(e.replace(/\.md$/, ""));
|
|
2202
3582
|
}
|
|
@@ -2230,8 +3610,8 @@ function detectPackageManager(dir) {
|
|
|
2230
3610
|
return void 0;
|
|
2231
3611
|
}
|
|
2232
3612
|
function detectMcpHint(dir) {
|
|
2233
|
-
for (const
|
|
2234
|
-
if (exists(join(dir,
|
|
3613
|
+
for (const f3 of [".mcp.json", "mcp.json", ".cursor/mcp.json"]) {
|
|
3614
|
+
if (exists(join(dir, f3))) return true;
|
|
2235
3615
|
}
|
|
2236
3616
|
return false;
|
|
2237
3617
|
}
|
|
@@ -2257,11 +3637,11 @@ var ADAPTERS = [
|
|
|
2257
3637
|
{ id: "kiro", label: "Kiro", file: "AGENTS.md", supportsInject: true }
|
|
2258
3638
|
];
|
|
2259
3639
|
function findAdapter(id) {
|
|
2260
|
-
return ADAPTERS.find((
|
|
3640
|
+
return ADAPTERS.find((a2) => a2.id === id);
|
|
2261
3641
|
}
|
|
2262
3642
|
function parseOriginAdapter(content) {
|
|
2263
|
-
const
|
|
2264
|
-
const id =
|
|
3643
|
+
const m2 = content.match(/Generated by `kaddo adapters install (\w+)`/);
|
|
3644
|
+
const id = m2?.[1];
|
|
2265
3645
|
return id && findAdapter(id) ? id : null;
|
|
2266
3646
|
}
|
|
2267
3647
|
function classifyAdapterState(content) {
|
|
@@ -2279,8 +3659,8 @@ function classifyAdapterState(content) {
|
|
|
2279
3659
|
return "team-owned";
|
|
2280
3660
|
}
|
|
2281
3661
|
}
|
|
2282
|
-
function recommendedAction(
|
|
2283
|
-
const cmd = `kaddo adapters install ${
|
|
3662
|
+
function recommendedAction(a2, state) {
|
|
3663
|
+
const cmd = `kaddo adapters install ${a2.id}`;
|
|
2284
3664
|
switch (state) {
|
|
2285
3665
|
case "missing":
|
|
2286
3666
|
return cmd;
|
|
@@ -2291,7 +3671,7 @@ function recommendedAction(a, state) {
|
|
|
2291
3671
|
case "legacy-injected":
|
|
2292
3672
|
return `${cmd} --inject (migrates legacy markers to neutral)`;
|
|
2293
3673
|
case "full-generated":
|
|
2294
|
-
return `No action needed. Use \`${cmd} --force\` only to regenerate for ${
|
|
3674
|
+
return `No action needed. Use \`${cmd} --force\` only to regenerate for ${a2.label}.`;
|
|
2295
3675
|
case "broken-markers":
|
|
2296
3676
|
return "Fix the incomplete Kaddo adapter markers before running --inject.";
|
|
2297
3677
|
}
|
|
@@ -2305,11 +3685,11 @@ function buildAdapterStatuses(dir) {
|
|
|
2305
3685
|
}
|
|
2306
3686
|
return cache.get(file);
|
|
2307
3687
|
};
|
|
2308
|
-
return ADAPTERS.map((
|
|
2309
|
-
const content = read(
|
|
3688
|
+
return ADAPTERS.map((a2) => {
|
|
3689
|
+
const content = read(a2.file);
|
|
2310
3690
|
const state = classifyAdapterState(content);
|
|
2311
3691
|
const originAdapter = content ? parseOriginAdapter(content) : null;
|
|
2312
|
-
return { ...
|
|
3692
|
+
return { ...a2, state, originAdapter, recommendedAction: recommendedAction(a2, state) };
|
|
2313
3693
|
});
|
|
2314
3694
|
}
|
|
2315
3695
|
|
|
@@ -2324,6 +3704,7 @@ var AGENT_GROUPS = {
|
|
|
2324
3704
|
"security-agent.md",
|
|
2325
3705
|
"standards-agent.md",
|
|
2326
3706
|
"module-design-agent.md",
|
|
3707
|
+
"module-context-agent.md",
|
|
2327
3708
|
"adr-agent.md",
|
|
2328
3709
|
"capsule-agent.md",
|
|
2329
3710
|
"graph-agent.md"
|
|
@@ -2369,9 +3750,9 @@ function slugify(s) {
|
|
|
2369
3750
|
function parseDecisionCandidates(md) {
|
|
2370
3751
|
const out = [];
|
|
2371
3752
|
for (const line of md.split(/\r?\n/)) {
|
|
2372
|
-
const
|
|
2373
|
-
if (
|
|
2374
|
-
const raw =
|
|
3753
|
+
const m2 = line.match(/^##\s+(.+?)\s*$/);
|
|
3754
|
+
if (m2) {
|
|
3755
|
+
const raw = m2[1].trim();
|
|
2375
3756
|
if (!raw || /^_.*_$/.test(raw)) continue;
|
|
2376
3757
|
const t = cleanCandidateTitle(raw);
|
|
2377
3758
|
if (t) out.push(t);
|
|
@@ -2438,9 +3819,9 @@ function buildTechDecisions(dir) {
|
|
|
2438
3819
|
// ../cli/src/core/next-step.ts
|
|
2439
3820
|
function buildDeliveryState(dir) {
|
|
2440
3821
|
const wis = discoverWorkItems(dir);
|
|
2441
|
-
const byState = (s) => wis.filter((
|
|
3822
|
+
const byState = (s) => wis.filter((w3) => w3.lifecycle === s).length;
|
|
2442
3823
|
const total = wis.length;
|
|
2443
|
-
const withOwnership = wis.filter((
|
|
3824
|
+
const withOwnership = wis.filter((w3) => w3.codeGlobs.length > 0).length;
|
|
2444
3825
|
const td = buildTechDecisions(dir);
|
|
2445
3826
|
const roadmapPath = join(dir, "knowledge/delivery/roadmap.md");
|
|
2446
3827
|
const roadmapMd = exists(roadmapPath) ? safeRead(roadmapPath) : null;
|
|
@@ -2449,9 +3830,10 @@ function buildDeliveryState(dir) {
|
|
|
2449
3830
|
return {
|
|
2450
3831
|
phase: "",
|
|
2451
3832
|
draft_work_items: byState("draft"),
|
|
2452
|
-
refined_draft_work_items: wis.filter((
|
|
2453
|
-
refined_draft_ids: wis.filter((
|
|
3833
|
+
refined_draft_work_items: wis.filter((w3) => w3.lifecycle === "draft" && w3.rawFrontmatter.refined_by).length,
|
|
3834
|
+
refined_draft_ids: wis.filter((w3) => w3.lifecycle === "draft" && w3.rawFrontmatter.refined_by).map((w3) => w3.id),
|
|
2454
3835
|
ready_work_items: byState("ready"),
|
|
3836
|
+
ready_work_item_ids: wis.filter((w3) => w3.lifecycle === "ready").map((w3) => w3.id),
|
|
2455
3837
|
in_progress_work_items: byState("in-progress"),
|
|
2456
3838
|
blocked_work_items: byState("blocked"),
|
|
2457
3839
|
total_work_items: total,
|
|
@@ -2481,17 +3863,17 @@ function roadmapSignal(dir) {
|
|
|
2481
3863
|
const lines = md.replace(/^---[\s\S]*?---/m, "").split(/\r?\n/);
|
|
2482
3864
|
let inOpenQuestions = false;
|
|
2483
3865
|
let candidates = 0;
|
|
2484
|
-
for (const
|
|
2485
|
-
if (/^#{1,6}\s/.test(
|
|
2486
|
-
else if (!inOpenQuestions && /^\s*(?:[-*]\s+|\|)/.test(
|
|
3866
|
+
for (const l2 of lines) {
|
|
3867
|
+
if (/^#{1,6}\s/.test(l2)) inOpenQuestions = /open questions|preguntas abiertas/i.test(l2);
|
|
3868
|
+
else if (!inOpenQuestions && /^\s*(?:[-*]\s+|\|)/.test(l2)) candidates += 1;
|
|
2487
3869
|
}
|
|
2488
3870
|
return candidates > 0 ? "has-candidates" : "empty";
|
|
2489
3871
|
}
|
|
2490
3872
|
function workItemsSignal(dir) {
|
|
2491
3873
|
const wis = discoverWorkItems(dir);
|
|
2492
3874
|
if (wis.length === 0) return "none";
|
|
2493
|
-
if (wis.some((
|
|
2494
|
-
if (wis.some((
|
|
3875
|
+
if (wis.some((w3) => w3.lifecycle === "in-progress")) return "in-progress";
|
|
3876
|
+
if (wis.some((w3) => w3.lifecycle === "ready")) return "ready";
|
|
2495
3877
|
return "none-ready";
|
|
2496
3878
|
}
|
|
2497
3879
|
function installedAdapters(dir) {
|
|
@@ -2499,8 +3881,8 @@ function installedAdapters(dir) {
|
|
|
2499
3881
|
(s) => s.state === "injected" || s.state === "legacy-injected" || s.state === "full-generated" && (s.originAdapter === s.id || s.originAdapter === null)
|
|
2500
3882
|
).map((s) => s.id);
|
|
2501
3883
|
}
|
|
2502
|
-
var
|
|
2503
|
-
var
|
|
3884
|
+
var B2 = "knowledge/business/business.md";
|
|
3885
|
+
var P2 = "knowledge/product/product.md";
|
|
2504
3886
|
var CAP = "knowledge/product/capabilities.md";
|
|
2505
3887
|
var CS = "knowledge/tech/current-state.md";
|
|
2506
3888
|
var CB = "knowledge/tech/codebase.md";
|
|
@@ -2510,8 +3892,61 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2510
3892
|
return { id: "init", phase: "Setup", label: "Run `kaddo init` to initialize Kaddo.", command: "kaddo init", reason: "Kaddo is not initialized in this project." };
|
|
2511
3893
|
}
|
|
2512
3894
|
const state = config.project.state;
|
|
2513
|
-
const
|
|
2514
|
-
const
|
|
3895
|
+
const q3 = (rel) => analyzeKnowledgeArtifact(dir, rel);
|
|
3896
|
+
const moduleRepo = isModule(config);
|
|
3897
|
+
const MC = "knowledge/module/module-context.md";
|
|
3898
|
+
if (moduleRepo) {
|
|
3899
|
+
const qMC = q3(MC);
|
|
3900
|
+
if (qMC === "missing") {
|
|
3901
|
+
return { id: "init-module-context", phase: "Setup", label: "Create `knowledge/module/module-context.md` for this module.", command: "kaddo init", reason: "Module context file is missing. Re-run `kaddo init` as a multirepo module." };
|
|
3902
|
+
}
|
|
3903
|
+
if ((state === "pre-ai" || state === "legacy") && !exists(join(dir, ".kaddo", "scan.json"))) {
|
|
3904
|
+
return { id: "scan", phase: "Discovery", label: "Run `kaddo scan` to capture deterministic signals from the existing code.", command: "kaddo scan", reason: "No scan baseline exists for this existing project yet." };
|
|
3905
|
+
}
|
|
3906
|
+
if (!exists(join(dir, ".kaddo", "context-pack.md"))) {
|
|
3907
|
+
return { id: "context", phase: "Discovery", label: "Run `kaddo context` to prepare the LLM context pack.", command: "kaddo context", reason: "No context pack has been generated yet." };
|
|
3908
|
+
}
|
|
3909
|
+
if (qMC !== "useful") {
|
|
3910
|
+
return {
|
|
3911
|
+
id: "refine-module-context",
|
|
3912
|
+
phase: "Knowledge Refinement",
|
|
3913
|
+
label: "Use module-context-agent to refine `knowledge/module/module-context.md`.",
|
|
3914
|
+
agent: "module-context-agent",
|
|
3915
|
+
skill: "module-context-refinement",
|
|
3916
|
+
target: MC,
|
|
3917
|
+
reason: "Module context is still a placeholder.",
|
|
3918
|
+
instructions: ["Refine the module context with real knowledge about this module.", "Do not create business.md or product.md.", "Do not write code."]
|
|
3919
|
+
};
|
|
3920
|
+
}
|
|
3921
|
+
const qCurrentState2 = q3(CS), qCodebase2 = q3(CB);
|
|
3922
|
+
if (qCurrentState2 !== "useful") {
|
|
3923
|
+
return {
|
|
3924
|
+
id: "refine-current-state",
|
|
3925
|
+
phase: "Knowledge Refinement",
|
|
3926
|
+
label: "Use architecture-agent to complete `knowledge/tech/current-state.md`.",
|
|
3927
|
+
agent: "architecture-agent",
|
|
3928
|
+
target: CS,
|
|
3929
|
+
reason: `${CS} is still a bootstrap placeholder or too thin.`,
|
|
3930
|
+
instructions: ["Describe the module's local architecture.", "Do not write code."]
|
|
3931
|
+
};
|
|
3932
|
+
}
|
|
3933
|
+
if (qCodebase2 !== "useful") {
|
|
3934
|
+
return {
|
|
3935
|
+
id: "refine-codebase",
|
|
3936
|
+
phase: "Knowledge Refinement",
|
|
3937
|
+
label: "Use architecture-agent to complete `knowledge/tech/codebase.md`.",
|
|
3938
|
+
agent: "architecture-agent",
|
|
3939
|
+
target: CB,
|
|
3940
|
+
reason: `${CB} is still a bootstrap placeholder or too thin.`,
|
|
3941
|
+
instructions: ["Map the module's local codebase structure.", "Do not write code."]
|
|
3942
|
+
};
|
|
3943
|
+
}
|
|
3944
|
+
if (!exists(join(dir, ".kaddo", "understand.md"))) {
|
|
3945
|
+
return { id: "understand", phase: "Discovery", label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand", reason: "No understand handoff has been generated yet." };
|
|
3946
|
+
}
|
|
3947
|
+
return { id: "module-ready", phase: "Active Delivery", label: "Module context is complete. Create and manage Work Items from the core repository.", reason: "This module's knowledge is ready. Work Items are created and tracked in the core." };
|
|
3948
|
+
}
|
|
3949
|
+
const qBusiness = q3(B2), qProduct = q3(P2), qCap = q3(CAP), qCurrentState = q3(CS), qCodebase = q3(CB);
|
|
2515
3950
|
if (qBusiness === "missing" || qProduct === "missing") {
|
|
2516
3951
|
return { id: "bootstrap", phase: "Setup", label: "Run `kaddo bootstrap` to create the project knowledge baseline.", command: "kaddo bootstrap", reason: "The knowledge baseline is incomplete." };
|
|
2517
3952
|
}
|
|
@@ -2555,12 +3990,12 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2555
3990
|
]
|
|
2556
3991
|
};
|
|
2557
3992
|
};
|
|
2558
|
-
if (qBusiness !== "useful") return refine("refine-business", "business-agent",
|
|
3993
|
+
if (qBusiness !== "useful") return refine("refine-business", "business-agent", B2, qBusiness);
|
|
2559
3994
|
if (qProduct !== "useful" || qCap !== "useful") {
|
|
2560
3995
|
if (qCap !== "useful") {
|
|
2561
3996
|
return refine("refine-product", "capability-agent", CAP, qCap, discovery ? "discover and document existing system capabilities grouped by functional domains in" : "complete");
|
|
2562
3997
|
}
|
|
2563
|
-
return refine("refine-product", "capability-agent",
|
|
3998
|
+
return refine("refine-product", "capability-agent", P2, qProduct);
|
|
2564
3999
|
}
|
|
2565
4000
|
if (qCurrentState !== "useful") return refine("refine-current-state", "architecture-agent", CS, qCurrentState);
|
|
2566
4001
|
if (qCodebase !== "useful") {
|
|
@@ -2577,63 +4012,42 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2577
4012
|
const st = buildDeliveryState(dir);
|
|
2578
4013
|
const secondary = buildSecondaryRecommendations(st);
|
|
2579
4014
|
const roadmap = roadmapSignal(dir);
|
|
2580
|
-
if (roadmap !== "has-candidates" && st.draft_work_items > 0) {
|
|
2581
|
-
if (st.refined_draft_work_items > 0) {
|
|
2582
|
-
const ids = st.refined_draft_ids;
|
|
2583
|
-
const single = ids.length === 1;
|
|
2584
|
-
return {
|
|
2585
|
-
id: "review-work-item",
|
|
2586
|
-
phase: "Active Delivery",
|
|
2587
|
-
label: single ? `Review ${ids[0]} and mark it ready for implementation.` : "Review refined draft Work Items and mark one ready for implementation.",
|
|
2588
|
-
command: single ? `kaddo ready ${ids[0]}` : "kaddo ready <WI-ID>",
|
|
2589
|
-
mcpAction: "kaddo_mark_work_item_ready",
|
|
2590
|
-
...single ? { target: ids[0], mcpArgs: { id: ids[0] } } : { targets: ids },
|
|
2591
|
-
reason: single ? `${ids[0]} is a refined draft Work Item awaiting human review.` : `There are ${ids.length} refined draft Work Items awaiting human review.`,
|
|
2592
|
-
...secondary.length ? { secondary } : {}
|
|
2593
|
-
};
|
|
2594
|
-
}
|
|
2595
|
-
return {
|
|
2596
|
-
id: "refine-work-item",
|
|
2597
|
-
phase: "Active Delivery",
|
|
2598
|
-
label: "Refine the existing draft Work Item with the work-item-agent.",
|
|
2599
|
-
agent: "work-item-agent",
|
|
2600
|
-
skill: "work-item-refinement",
|
|
2601
|
-
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.`,
|
|
2602
|
-
...secondary.length ? { secondary } : {}
|
|
2603
|
-
};
|
|
2604
|
-
}
|
|
2605
|
-
if (roadmap !== "has-candidates") {
|
|
2606
|
-
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." };
|
|
2607
|
-
}
|
|
2608
|
-
if (st.total_work_items === 0) {
|
|
2609
|
-
return {
|
|
2610
|
-
id: "create-work-item",
|
|
2611
|
-
phase: "Delivery Preparation",
|
|
2612
|
-
label: "Run `kaddo create --from roadmap` to materialize the first Work Item.",
|
|
2613
|
-
command: "kaddo create --from roadmap",
|
|
2614
|
-
reason: "The roadmap has candidates but no Work Item exists yet.",
|
|
2615
|
-
...secondary.length ? { secondary } : {}
|
|
2616
|
-
};
|
|
2617
|
-
}
|
|
2618
4015
|
const adapters = st.adapters_installed;
|
|
2619
4016
|
if (st.ready_work_items > 0) {
|
|
4017
|
+
const ids = st.ready_work_item_ids;
|
|
4018
|
+
const single = ids.length === 1;
|
|
4019
|
+
const sec = [...secondary];
|
|
4020
|
+
if (roadmap !== "has-candidates" && st.remaining_work_item_candidates === 0) {
|
|
4021
|
+
sec.push({
|
|
4022
|
+
id: "roadmap",
|
|
4023
|
+
label: "Roadmap has no candidates. Consider running `kaddo roadmap` after handling ready Work Items.",
|
|
4024
|
+
command: "kaddo roadmap",
|
|
4025
|
+
agent: "roadmap-agent",
|
|
4026
|
+
reason: "The roadmap has no candidates yet, but ready Work Items exist."
|
|
4027
|
+
});
|
|
4028
|
+
}
|
|
2620
4029
|
if (adapters === 0) {
|
|
2621
4030
|
return {
|
|
2622
|
-
id: "
|
|
4031
|
+
id: "prepare-implementation",
|
|
2623
4032
|
phase: "Active Delivery",
|
|
2624
|
-
label:
|
|
4033
|
+
label: single ? `Prepare implementation for ${ids[0]}.` : "Prepare implementation for ready Work Items.",
|
|
2625
4034
|
command: "kaddo adapters list",
|
|
2626
|
-
|
|
2627
|
-
|
|
4035
|
+
agent: "implementation-agent",
|
|
4036
|
+
skill: "implementation-planning",
|
|
4037
|
+
...single ? { target: ids[0] } : { targets: ids },
|
|
4038
|
+
reason: single ? `${ids[0]} is ready for implementation but no adapter is installed.` : `There are ${ids.length} ready Work Items awaiting implementation but no adapter is installed.`,
|
|
4039
|
+
...sec.length ? { secondary: sec } : {}
|
|
2628
4040
|
};
|
|
2629
4041
|
}
|
|
2630
4042
|
return {
|
|
2631
|
-
id: "implement",
|
|
4043
|
+
id: "implement-work-item",
|
|
2632
4044
|
phase: "Active Delivery",
|
|
2633
|
-
label:
|
|
4045
|
+
label: single ? `Use implementation-agent to implement ${ids[0]}.` : "Use implementation-agent to implement ready Work Items.",
|
|
2634
4046
|
agent: "implementation-agent",
|
|
2635
|
-
|
|
2636
|
-
...
|
|
4047
|
+
skill: "implementation-planning",
|
|
4048
|
+
...single ? { target: ids[0] } : { targets: ids },
|
|
4049
|
+
reason: single ? `${ids[0]} is ready for implementation.` : `There are ${ids.length} ready Work Items awaiting implementation.`,
|
|
4050
|
+
...sec.length ? { secondary: sec } : {}
|
|
2637
4051
|
};
|
|
2638
4052
|
}
|
|
2639
4053
|
if (st.in_progress_work_items > 0) {
|
|
@@ -2646,6 +4060,20 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2646
4060
|
...secondary.length ? { secondary } : {}
|
|
2647
4061
|
};
|
|
2648
4062
|
}
|
|
4063
|
+
if (st.refined_draft_work_items > 0) {
|
|
4064
|
+
const ids = st.refined_draft_ids;
|
|
4065
|
+
const single = ids.length === 1;
|
|
4066
|
+
return {
|
|
4067
|
+
id: "review-work-item",
|
|
4068
|
+
phase: "Active Delivery",
|
|
4069
|
+
label: single ? `Review ${ids[0]} and mark it ready for implementation.` : "Review refined draft Work Items and mark one ready for implementation.",
|
|
4070
|
+
command: single ? `kaddo ready ${ids[0]}` : "kaddo ready <WI-ID>",
|
|
4071
|
+
mcpAction: "kaddo_mark_work_item_ready",
|
|
4072
|
+
...single ? { target: ids[0], mcpArgs: { id: ids[0] } } : { targets: ids },
|
|
4073
|
+
reason: single ? `${ids[0]} is a refined draft Work Item awaiting human review.` : `There are ${ids.length} refined draft Work Items awaiting human review.`,
|
|
4074
|
+
...secondary.length ? { secondary } : {}
|
|
4075
|
+
};
|
|
4076
|
+
}
|
|
2649
4077
|
if (st.draft_work_items > 0) {
|
|
2650
4078
|
return {
|
|
2651
4079
|
id: "refine-work-item",
|
|
@@ -2653,7 +4081,7 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2653
4081
|
label: "Refine the existing draft Work Item with the work-item-agent.",
|
|
2654
4082
|
agent: "work-item-agent",
|
|
2655
4083
|
skill: "work-item-refinement",
|
|
2656
|
-
reason: `There ${st.draft_work_items === 1 ? "is" : "are"} ${st.draft_work_items} draft Work Item${st.draft_work_items === 1 ? "" : "s"}
|
|
4084
|
+
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.`,
|
|
2657
4085
|
...secondary.length ? { secondary } : {}
|
|
2658
4086
|
};
|
|
2659
4087
|
}
|
|
@@ -2667,6 +4095,19 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2667
4095
|
...secondary.length ? { secondary } : {}
|
|
2668
4096
|
};
|
|
2669
4097
|
}
|
|
4098
|
+
if (roadmap !== "has-candidates") {
|
|
4099
|
+
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." };
|
|
4100
|
+
}
|
|
4101
|
+
if (st.total_work_items === 0) {
|
|
4102
|
+
return {
|
|
4103
|
+
id: "create-work-item",
|
|
4104
|
+
phase: "Delivery Preparation",
|
|
4105
|
+
label: "Run `kaddo create --from roadmap` to materialize the first Work Item.",
|
|
4106
|
+
command: "kaddo create --from roadmap",
|
|
4107
|
+
reason: "The roadmap has candidates but no Work Item exists yet.",
|
|
4108
|
+
...secondary.length ? { secondary } : {}
|
|
4109
|
+
};
|
|
4110
|
+
}
|
|
2670
4111
|
if (st.remaining_work_item_candidates > 0) {
|
|
2671
4112
|
return {
|
|
2672
4113
|
id: "materialize-more-work-items",
|
|
@@ -2758,7 +4199,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2758
4199
|
if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
|
|
2759
4200
|
const scan = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
|
|
2760
4201
|
const understand = exists(join(dir, ".kaddo", "understand.md")) ? "available" : "missing";
|
|
2761
|
-
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((
|
|
4202
|
+
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f3) => [f3.key, analyzeKnowledgeArtifact(dir, f3.path)]));
|
|
2762
4203
|
const ctx = buildCodexAdapterContext(dir);
|
|
2763
4204
|
const agents = ctx.hasAgents ? "present" : "missing";
|
|
2764
4205
|
const skills = ctx.hasSkills ? "present" : "missing";
|
|
@@ -2786,7 +4227,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2786
4227
|
resolved_questions: oq.summary.resolution.resolved,
|
|
2787
4228
|
deferred_questions: oq.summary.resolution.deferred
|
|
2788
4229
|
};
|
|
2789
|
-
const firstWeak = KNOWLEDGE_FILES.find((
|
|
4230
|
+
const firstWeak = KNOWLEDGE_FILES.find((f3) => presence[f3.key] !== "useful");
|
|
2790
4231
|
let overall;
|
|
2791
4232
|
if (scan === "missing") overall = "initialized";
|
|
2792
4233
|
else if (bootstrapBaseline2 === "incomplete") overall = "bootstrap-incomplete";
|
|
@@ -2845,7 +4286,7 @@ function skill(id, title, group, appliesTo, body) {
|
|
|
2845
4286
|
`version: ${KADDO_VERSION}`,
|
|
2846
4287
|
`group: ${group}`,
|
|
2847
4288
|
"applies_to:",
|
|
2848
|
-
...appliesTo.map((
|
|
4289
|
+
...appliesTo.map((a2) => ` - ${a2}`),
|
|
2849
4290
|
"---",
|
|
2850
4291
|
""
|
|
2851
4292
|
].join("\n");
|
|
@@ -3200,6 +4641,58 @@ steps, and stop criteria (when to pause and ask).
|
|
|
3200
4641
|
A numbered plan covering the sections above, ending with a request to confirm before coding.
|
|
3201
4642
|
`
|
|
3202
4643
|
);
|
|
4644
|
+
var MODULE_CONTEXT_REFINEMENT = skill(
|
|
4645
|
+
"module-context-refinement",
|
|
4646
|
+
"Module Context Refinement Skill",
|
|
4647
|
+
"tech",
|
|
4648
|
+
["module-context-agent", "architecture-agent"],
|
|
4649
|
+
`
|
|
4650
|
+
# Module Context Refinement Skill
|
|
4651
|
+
|
|
4652
|
+
## Purpose
|
|
4653
|
+
|
|
4654
|
+
Standardize how a multirepo module's context is refined without duplicating global knowledge.
|
|
4655
|
+
|
|
4656
|
+
## When to use
|
|
4657
|
+
|
|
4658
|
+
When refining \`knowledge/module/module-context.md\` in a multirepo module repository.
|
|
4659
|
+
|
|
4660
|
+
## Inputs
|
|
4661
|
+
|
|
4662
|
+
The module's \`module-context.md\`, local tech knowledge (\`current-state.md\`, \`codebase.md\`),
|
|
4663
|
+
and \u2014 optionally \u2014 the core system's context pack.
|
|
4664
|
+
|
|
4665
|
+
## Output
|
|
4666
|
+
|
|
4667
|
+
A refined \`module-context.md\` with real, project-specific content in all sections.
|
|
4668
|
+
|
|
4669
|
+
## Rules
|
|
4670
|
+
|
|
4671
|
+
- Use module responsibility, not full product strategy.
|
|
4672
|
+
- Identify boundaries and dependencies from the local code.
|
|
4673
|
+
- Keep business/product context in the core/system repository.
|
|
4674
|
+
- Document local risks and exposed interfaces.
|
|
4675
|
+
- Preserve frontmatter (\`type\`, \`module_id\`, \`parent_system\`).
|
|
4676
|
+
- Mark unknowns as open questions.
|
|
4677
|
+
- Do not create \`business.md\` or \`product.md\` in the module.
|
|
4678
|
+
- Do not install agents or skills in the module.
|
|
4679
|
+
- Do not create Work Items in the module.
|
|
4680
|
+
|
|
4681
|
+
## Quality checklist
|
|
4682
|
+
|
|
4683
|
+
- Module identity and purpose are clear.
|
|
4684
|
+
- Responsibility and boundaries are non-overlapping with other modules.
|
|
4685
|
+
- Exposed interfaces are real, not invented.
|
|
4686
|
+
- Dependencies and consumers are listed.
|
|
4687
|
+
- Local rules are documented.
|
|
4688
|
+
- Risks are honest and specific.
|
|
4689
|
+
- Open questions are surfaced.
|
|
4690
|
+
|
|
4691
|
+
## Example output
|
|
4692
|
+
|
|
4693
|
+
A \`module-context.md\` with all placeholder sections filled in.
|
|
4694
|
+
`
|
|
4695
|
+
);
|
|
3203
4696
|
var SKILLS = [
|
|
3204
4697
|
ADR_WRITING,
|
|
3205
4698
|
WORK_ITEM_REFINEMENT,
|
|
@@ -3207,11 +4700,12 @@ var SKILLS = [
|
|
|
3207
4700
|
GRAPH_METADATA_REVIEW,
|
|
3208
4701
|
CAPSULE_WRITING,
|
|
3209
4702
|
LEARNING_CAPTURE,
|
|
3210
|
-
IMPLEMENTATION_PLANNING
|
|
4703
|
+
IMPLEMENTATION_PLANNING,
|
|
4704
|
+
MODULE_CONTEXT_REFINEMENT
|
|
3211
4705
|
];
|
|
3212
4706
|
var SKILL_GROUPS = {
|
|
3213
4707
|
delivery: ["work-item-refinement", "implementation-planning", "learning-capture"],
|
|
3214
|
-
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review"],
|
|
4708
|
+
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review", "module-context-refinement"],
|
|
3215
4709
|
integration: ["capsule-writing"]
|
|
3216
4710
|
};
|
|
3217
4711
|
var SKILL_GROUP_NAMES = Object.keys(SKILL_GROUPS);
|
|
@@ -3298,6 +4792,14 @@ var RESPONSIBILITY_MATRIX = {
|
|
|
3298
4792
|
cannotSuggest: ["Git", "branches", "code"],
|
|
3299
4793
|
next: ["architecture-agent"]
|
|
3300
4794
|
},
|
|
4795
|
+
"module-context-agent": {
|
|
4796
|
+
agent: "module-context-agent",
|
|
4797
|
+
responsibleFor: ["Module context", "Responsibility", "Boundaries", "Interfaces", "Dependencies"],
|
|
4798
|
+
produces: ["knowledge/module/module-context.md"],
|
|
4799
|
+
canSuggest: ["architecture-agent"],
|
|
4800
|
+
cannotSuggest: ["Git", "branches", "code", "business.md", "product.md", "Work Items"],
|
|
4801
|
+
next: ["architecture-agent"]
|
|
4802
|
+
},
|
|
3301
4803
|
"architecture-agent": {
|
|
3302
4804
|
agent: "architecture-agent",
|
|
3303
4805
|
responsibleFor: ["Architecture", "Technical state", "Risks"],
|
|
@@ -3441,25 +4943,25 @@ function list(items) {
|
|
|
3441
4943
|
return items.length > 0 ? items.join(", ") : "\u2014";
|
|
3442
4944
|
}
|
|
3443
4945
|
function renderAgentBoundaries(agent) {
|
|
3444
|
-
const
|
|
3445
|
-
if (!
|
|
4946
|
+
const r2 = RESPONSIBILITY_MATRIX[agent];
|
|
4947
|
+
if (!r2) return "";
|
|
3446
4948
|
return [
|
|
3447
4949
|
"## Responsibility & Boundaries",
|
|
3448
4950
|
"",
|
|
3449
|
-
`**Responsible for:** ${list(
|
|
3450
|
-
`**Produces:** ${list(
|
|
3451
|
-
`**May suggest:** ${list(
|
|
3452
|
-
`**Must NOT suggest:** ${list(
|
|
4951
|
+
`**Responsible for:** ${list(r2.responsibleFor)}`,
|
|
4952
|
+
`**Produces:** ${list(r2.produces)}`,
|
|
4953
|
+
`**May suggest:** ${list(r2.canSuggest)}`,
|
|
4954
|
+
`**Must NOT suggest:** ${list(r2.cannotSuggest)}`,
|
|
3453
4955
|
"",
|
|
3454
4956
|
"This agent produces **knowledge only**. It never runs Git, never runs code and never runs commands. It may only suggest actions inside its own responsibility.",
|
|
3455
4957
|
""
|
|
3456
4958
|
].join("\n");
|
|
3457
4959
|
}
|
|
3458
4960
|
function renderAgentTrace(agent) {
|
|
3459
|
-
const
|
|
3460
|
-
if (!
|
|
3461
|
-
const produced =
|
|
3462
|
-
const next =
|
|
4961
|
+
const r2 = RESPONSIBILITY_MATRIX[agent];
|
|
4962
|
+
if (!r2) return "";
|
|
4963
|
+
const produced = r2.produces.length > 0 ? r2.produces.join("\n") : "(none)";
|
|
4964
|
+
const next = r2.next.length > 0 ? r2.next.join("\n") : "(end of flow)";
|
|
3463
4965
|
return [
|
|
3464
4966
|
"## Agent Trace",
|
|
3465
4967
|
"",
|
|
@@ -3467,7 +4969,7 @@ function renderAgentTrace(agent) {
|
|
|
3467
4969
|
"",
|
|
3468
4970
|
"```text",
|
|
3469
4971
|
"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
3470
|
-
`Agent: ${
|
|
4972
|
+
`Agent: ${r2.agent}`,
|
|
3471
4973
|
"",
|
|
3472
4974
|
"Produced:",
|
|
3473
4975
|
produced,
|
|
@@ -3515,7 +5017,8 @@ var KNOWLEDGE_REFINING_AGENTS = {
|
|
|
3515
5017
|
"work-item-agent": "work-item-agent",
|
|
3516
5018
|
"backlog-agent": "backlog-agent",
|
|
3517
5019
|
"adr-agent": "adr-agent",
|
|
3518
|
-
"implementation-agent": "implementation-agent"
|
|
5020
|
+
"implementation-agent": "implementation-agent",
|
|
5021
|
+
"module-context-agent": "module-context-agent"
|
|
3519
5022
|
};
|
|
3520
5023
|
function renderFrontmatterRules(agent) {
|
|
3521
5024
|
if (!KNOWLEDGE_REFINING_AGENTS[agent]) return "";
|
|
@@ -4735,6 +6238,92 @@ Save as \`knowledge/tech/modules/<module-name>/module-design.md\`.
|
|
|
4735
6238
|
- Diagrams are suggested, not generated.
|
|
4736
6239
|
- Assumptions and risks are explicit.
|
|
4737
6240
|
`;
|
|
6241
|
+
var MODULE_CONTEXT_AGENT = `# Module Context Agent
|
|
6242
|
+
|
|
6243
|
+
## Role
|
|
6244
|
+
|
|
6245
|
+
You are the Kaddo Module Context Agent. Your job is to refine the \`module-context.md\` file
|
|
6246
|
+
of a multirepo module from the available code and system context.
|
|
6247
|
+
|
|
6248
|
+
You do not write code. You describe the module's responsibility, boundaries, interfaces,
|
|
6249
|
+
dependencies, consumers, risks, and local rules. You never generate \`business.md\` or
|
|
6250
|
+
\`product.md\` \u2014 those belong to the core repository.
|
|
6251
|
+
|
|
6252
|
+
## When to Use
|
|
6253
|
+
|
|
6254
|
+
Use this agent inside a multirepo **module** repository, after \`kaddo init\` has created the
|
|
6255
|
+
placeholder \`knowledge/module/module-context.md\`.
|
|
6256
|
+
|
|
6257
|
+
## Input Required
|
|
6258
|
+
|
|
6259
|
+
Provide the module's \`knowledge/module/module-context.md\`, the local codebase context
|
|
6260
|
+
(\`knowledge/tech/current-state.md\`, \`knowledge/tech/codebase.md\`), and \u2014 if available \u2014
|
|
6261
|
+
the core system's \`.kaddo/context-pack.md\`.
|
|
6262
|
+
|
|
6263
|
+
## Expected Output
|
|
6264
|
+
|
|
6265
|
+
A refined \`knowledge/module/module-context.md\` with all placeholder sections replaced by
|
|
6266
|
+
real, project-specific knowledge.
|
|
6267
|
+
|
|
6268
|
+
## Instructions
|
|
6269
|
+
|
|
6270
|
+
1. Describe the module's identity: name, purpose, and role inside the parent system.
|
|
6271
|
+
2. Define responsibility: what this module owns.
|
|
6272
|
+
3. Define boundaries: what belongs here and what does not.
|
|
6273
|
+
4. List exposed interfaces: APIs, routes, events, tables, packages, contracts.
|
|
6274
|
+
5. List dependencies: other modules, services, databases, queues, providers.
|
|
6275
|
+
6. List consumers: who uses this module.
|
|
6276
|
+
7. Document local rules: module-specific constraints agents must respect.
|
|
6277
|
+
8. Document risks: what can go wrong when changing this module.
|
|
6278
|
+
9. Surface open questions: what still needs confirmation.
|
|
6279
|
+
|
|
6280
|
+
## Constraints
|
|
6281
|
+
|
|
6282
|
+
- Do not write code.
|
|
6283
|
+
- Do not generate \`business.md\` or \`product.md\` \u2014 those live in the core.
|
|
6284
|
+
- Do not install agents or skills \u2014 those live in the core.
|
|
6285
|
+
- Do not create Work Items \u2014 those live in the core.
|
|
6286
|
+
- Mark assumptions and unknowns clearly.
|
|
6287
|
+
- Preserve the existing frontmatter (\`type\`, \`module_id\`, \`parent_system\`).
|
|
6288
|
+
|
|
6289
|
+
## Output Format
|
|
6290
|
+
|
|
6291
|
+
\`\`\`markdown
|
|
6292
|
+
# Module Context
|
|
6293
|
+
|
|
6294
|
+
## Module identity
|
|
6295
|
+
|
|
6296
|
+
## Responsibility
|
|
6297
|
+
|
|
6298
|
+
## Boundaries
|
|
6299
|
+
|
|
6300
|
+
## Exposed interfaces
|
|
6301
|
+
|
|
6302
|
+
## Dependencies
|
|
6303
|
+
|
|
6304
|
+
## Consumers
|
|
6305
|
+
|
|
6306
|
+
## Local rules
|
|
6307
|
+
|
|
6308
|
+
## Risks
|
|
6309
|
+
|
|
6310
|
+
## Open questions
|
|
6311
|
+
\`\`\`
|
|
6312
|
+
|
|
6313
|
+
## Where to Save the Result
|
|
6314
|
+
|
|
6315
|
+
Save as \`knowledge/module/module-context.md\`.
|
|
6316
|
+
|
|
6317
|
+
## Quality Checklist
|
|
6318
|
+
|
|
6319
|
+
- Module identity and purpose are clear.
|
|
6320
|
+
- Responsibility and boundaries are explicit and non-overlapping.
|
|
6321
|
+
- Exposed interfaces are real, not invented.
|
|
6322
|
+
- Dependencies and consumers are listed.
|
|
6323
|
+
- Local rules are documented.
|
|
6324
|
+
- Risks are honest and specific.
|
|
6325
|
+
- Open questions are surfaced, not hidden.
|
|
6326
|
+
`;
|
|
4738
6327
|
var BUSINESS_AGENT = `# Business Agent
|
|
4739
6328
|
|
|
4740
6329
|
## Role
|
|
@@ -5332,6 +6921,7 @@ var AGENT_PROMPTS = [
|
|
|
5332
6921
|
{ fileName: "standards-agent.md", content: STANDARDS_AGENT },
|
|
5333
6922
|
{ fileName: "stack-agent.md", content: STACK_AGENT },
|
|
5334
6923
|
{ fileName: "module-design-agent.md", content: MODULE_DESIGN_AGENT },
|
|
6924
|
+
{ fileName: "module-context-agent.md", content: MODULE_CONTEXT_AGENT },
|
|
5335
6925
|
// Bootstrap agents (new projects)
|
|
5336
6926
|
{ fileName: "business-agent.md", content: BUSINESS_AGENT },
|
|
5337
6927
|
{ fileName: "bootstrap-agent.md", content: BOOTSTRAP_AGENT },
|
|
@@ -5432,9 +7022,9 @@ var agentReadme = {
|
|
|
5432
7022
|
"- `graph-agent.md` \u2014 review `kaddo graph export` hints and propose precise relationship front matter."
|
|
5433
7023
|
].join("\n")
|
|
5434
7024
|
};
|
|
5435
|
-
var agentFiles = AGENT_PROMPTS.map((
|
|
5436
|
-
path: agentInstallPath(
|
|
5437
|
-
content: withAgentFrontMatter(
|
|
7025
|
+
var agentFiles = AGENT_PROMPTS.map((a2) => ({
|
|
7026
|
+
path: agentInstallPath(a2.fileName),
|
|
7027
|
+
content: withAgentFrontMatter(a2.fileName, a2.content)
|
|
5438
7028
|
}));
|
|
5439
7029
|
var agentsModule = {
|
|
5440
7030
|
name: "agents",
|
|
@@ -5486,10 +7076,10 @@ var agentsModule = {
|
|
|
5486
7076
|
|
|
5487
7077
|
// ../cli/src/core/assets.ts
|
|
5488
7078
|
function canonicalAgents() {
|
|
5489
|
-
return AGENT_PROMPTS.map((
|
|
5490
|
-
name:
|
|
5491
|
-
path: agentInstallPath(
|
|
5492
|
-
content: withAgentFrontMatter(
|
|
7079
|
+
return AGENT_PROMPTS.map((a2) => ({
|
|
7080
|
+
name: a2.fileName.replace(/\.md$/, ""),
|
|
7081
|
+
path: agentInstallPath(a2.fileName),
|
|
7082
|
+
content: withAgentFrontMatter(a2.fileName, a2.content)
|
|
5493
7083
|
}));
|
|
5494
7084
|
}
|
|
5495
7085
|
function canonicalSkills() {
|
|
@@ -5503,12 +7093,12 @@ function versionOf(content) {
|
|
|
5503
7093
|
return null;
|
|
5504
7094
|
}
|
|
5505
7095
|
}
|
|
5506
|
-
function cmpVersion(
|
|
5507
|
-
const pa =
|
|
5508
|
-
const pb =
|
|
7096
|
+
function cmpVersion(a2, b2) {
|
|
7097
|
+
const pa = a2.split(".").map((n) => parseInt(n, 10) || 0);
|
|
7098
|
+
const pb = b2.split(".").map((n) => parseInt(n, 10) || 0);
|
|
5509
7099
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
5510
|
-
const
|
|
5511
|
-
if (
|
|
7100
|
+
const d3 = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
7101
|
+
if (d3 !== 0) return d3 < 0 ? -1 : 1;
|
|
5512
7102
|
}
|
|
5513
7103
|
return 0;
|
|
5514
7104
|
}
|
|
@@ -5543,7 +7133,7 @@ function summarize(items) {
|
|
|
5543
7133
|
}
|
|
5544
7134
|
function assetStatus(dir, kind) {
|
|
5545
7135
|
const catalog = kind === "agent" ? canonicalAgents() : canonicalSkills();
|
|
5546
|
-
return summarize(catalog.map((
|
|
7136
|
+
return summarize(catalog.map((a2) => classify(dir, a2)));
|
|
5547
7137
|
}
|
|
5548
7138
|
function installedAssetsSummary(dir) {
|
|
5549
7139
|
return { version: KADDO_VERSION, agents: assetStatus(dir, "agent"), skills: assetStatus(dir, "skill") };
|
|
@@ -5554,14 +7144,14 @@ var ROADMAP_PATH = "knowledge/delivery/roadmap.md";
|
|
|
5554
7144
|
var INITIATIVE_RE2 = /^#{2,4}\s+(RM-[\w.-]+)\s*[:\-–]?\s*(.*)$/;
|
|
5555
7145
|
function fieldPresent(lines, label) {
|
|
5556
7146
|
for (let i = 0; i < lines.length; i++) {
|
|
5557
|
-
const
|
|
5558
|
-
if (!
|
|
5559
|
-
const inline =
|
|
7147
|
+
const m2 = lines[i].match(new RegExp(`^\\s*[-*]?\\s*(?:\\*\\*)?\\s*(${label.source})\\s*(?:\\*\\*)?\\s*:\\s*(.*)$`, "i"));
|
|
7148
|
+
if (!m2) continue;
|
|
7149
|
+
const inline = m2[2].trim();
|
|
5560
7150
|
if (inline) return true;
|
|
5561
|
-
for (let
|
|
5562
|
-
if (/^\s{2,}[-*]\s+\S/.test(lines[
|
|
5563
|
-
if (/^\S/.test(lines[
|
|
5564
|
-
if (/^\s*[-*]\s+\S/.test(lines[
|
|
7151
|
+
for (let j2 = i + 1; j2 < lines.length; j2++) {
|
|
7152
|
+
if (/^\s{2,}[-*]\s+\S/.test(lines[j2])) return true;
|
|
7153
|
+
if (/^\S/.test(lines[j2]) || /^#{2,4}\s/.test(lines[j2])) break;
|
|
7154
|
+
if (/^\s*[-*]\s+\S/.test(lines[j2]) && !/^\s{2,}/.test(lines[j2])) break;
|
|
5565
7155
|
}
|
|
5566
7156
|
}
|
|
5567
7157
|
return false;
|
|
@@ -5586,10 +7176,10 @@ function parseRoadmapCandidateQuality(md) {
|
|
|
5586
7176
|
cur = null;
|
|
5587
7177
|
};
|
|
5588
7178
|
for (const line of lines) {
|
|
5589
|
-
const
|
|
5590
|
-
if (
|
|
7179
|
+
const m2 = line.match(INITIATIVE_RE2);
|
|
7180
|
+
if (m2) {
|
|
5591
7181
|
flush();
|
|
5592
|
-
cur = { id:
|
|
7182
|
+
cur = { id: m2[1], title: m2[2].trim(), lines: [] };
|
|
5593
7183
|
continue;
|
|
5594
7184
|
}
|
|
5595
7185
|
if (cur) cur.lines.push(line);
|
|
@@ -5765,8 +7355,8 @@ function optStr(v) {
|
|
|
5765
7355
|
}
|
|
5766
7356
|
|
|
5767
7357
|
// ../cli/src/core/project-route.ts
|
|
5768
|
-
function isUseful(
|
|
5769
|
-
return
|
|
7358
|
+
function isUseful(q3) {
|
|
7359
|
+
return q3 === "useful";
|
|
5770
7360
|
}
|
|
5771
7361
|
var enableKaddo = {
|
|
5772
7362
|
id: "enable-kaddo",
|
|
@@ -6051,9 +7641,9 @@ function buildRouteContext(dir) {
|
|
|
6051
7641
|
}
|
|
6052
7642
|
}
|
|
6053
7643
|
const stats = roadmapStats(roadmapMd, wis.length);
|
|
6054
|
-
const byState = (s) => wis.filter((
|
|
7644
|
+
const byState = (s) => wis.filter((w3) => w3.lifecycle === s).length;
|
|
6055
7645
|
const total = wis.length;
|
|
6056
|
-
const withOwnership = wis.filter((
|
|
7646
|
+
const withOwnership = wis.filter((w3) => w3.codeGlobs.length > 0).length;
|
|
6057
7647
|
const adapters = installedAdapters(dir);
|
|
6058
7648
|
const nextStep = resolveNextStep(dir);
|
|
6059
7649
|
return {
|
|
@@ -6082,8 +7672,8 @@ function buildRouteContext(dir) {
|
|
|
6082
7672
|
adaptersInstalled: adapters.length,
|
|
6083
7673
|
hasGuardHistory: exists(join(dir, ".kaddo", "history", "guard-runs.jsonl")),
|
|
6084
7674
|
hasScanWarnings: hasScan ? loadScanWarnings(dir) : false,
|
|
6085
|
-
hasUnknownSources: wis.some((
|
|
6086
|
-
const src = parseWorkItemSource(
|
|
7675
|
+
hasUnknownSources: wis.some((w3) => {
|
|
7676
|
+
const src = parseWorkItemSource(w3.rawFrontmatter);
|
|
6087
7677
|
return src.type === "unknown" && src.inferred;
|
|
6088
7678
|
}),
|
|
6089
7679
|
nextStepId: mapNextStepId(nextStep.id)
|
|
@@ -6110,7 +7700,12 @@ function mapNextStepId(id) {
|
|
|
6110
7700
|
"refine-capabilities": "discover-capabilities",
|
|
6111
7701
|
"refine-current-state": "describe-architecture",
|
|
6112
7702
|
"refine-codebase": "describe-architecture",
|
|
6113
|
-
"review-work-item": "refine-work-item"
|
|
7703
|
+
"review-work-item": "refine-work-item",
|
|
7704
|
+
"prepare-implementation": "prepare-implementation",
|
|
7705
|
+
"implement-work-item": "prepare-implementation",
|
|
7706
|
+
"refine-module-context": "refine-work-item",
|
|
7707
|
+
"init-module-context": "enable-kaddo",
|
|
7708
|
+
"module-ready": "prepare-implementation"
|
|
6114
7709
|
};
|
|
6115
7710
|
return MAP[id] ?? id;
|
|
6116
7711
|
}
|
|
@@ -6119,9 +7714,9 @@ function buildProjectRoute(dir) {
|
|
|
6119
7714
|
const state = config?.project.state ?? "pre-ai";
|
|
6120
7715
|
const defs = stepsForState(state);
|
|
6121
7716
|
const ctx = buildRouteContext(dir);
|
|
6122
|
-
const steps = defs.map((
|
|
6123
|
-
const result =
|
|
6124
|
-
return { id:
|
|
7717
|
+
const steps = defs.map((d3) => {
|
|
7718
|
+
const result = d3.evaluate(ctx);
|
|
7719
|
+
return { id: d3.id, label: d3.label, ...result };
|
|
6125
7720
|
});
|
|
6126
7721
|
for (const s of steps) {
|
|
6127
7722
|
if (s.id === ctx.nextStepId && s.status !== "done") {
|
|
@@ -6185,8 +7780,8 @@ function renderRouteCompact(route) {
|
|
|
6185
7780
|
const warnings = route.steps.filter((s) => s.status === "warning");
|
|
6186
7781
|
if (warnings.length > 0) {
|
|
6187
7782
|
lines.push("Warnings:");
|
|
6188
|
-
for (const
|
|
6189
|
-
lines.push(`- ${
|
|
7783
|
+
for (const w3 of warnings) {
|
|
7784
|
+
lines.push(`- ${w3.label}${w3.reason ? ` \u2014 ${w3.reason}` : ""}`);
|
|
6190
7785
|
}
|
|
6191
7786
|
lines.push("");
|
|
6192
7787
|
}
|
|
@@ -6252,10 +7847,10 @@ function findDuplicateWorkItems(items) {
|
|
|
6252
7847
|
const bucket = (key, reason, pred) => {
|
|
6253
7848
|
const matched = items.filter(pred);
|
|
6254
7849
|
if (matched.length > 1) {
|
|
6255
|
-
const id = `${reason}:${key}:${matched.map((
|
|
7850
|
+
const id = `${reason}:${key}:${matched.map((m2) => m2.id).sort().join(",")}`;
|
|
6256
7851
|
if (!seen.has(id)) {
|
|
6257
7852
|
seen.add(id);
|
|
6258
|
-
groups.push({ reason, items: matched.map((
|
|
7853
|
+
groups.push({ reason, items: matched.map((m2) => ({ id: m2.id, title: m2.title })) });
|
|
6259
7854
|
}
|
|
6260
7855
|
}
|
|
6261
7856
|
};
|
|
@@ -6269,7 +7864,7 @@ function findDuplicateWorkItems(items) {
|
|
|
6269
7864
|
}
|
|
6270
7865
|
function first(values) {
|
|
6271
7866
|
if (Array.isArray(values)) {
|
|
6272
|
-
const v = values.find((
|
|
7867
|
+
const v = values.find((x2) => typeof x2 === "string" && x2);
|
|
6273
7868
|
return v ? String(v) : void 0;
|
|
6274
7869
|
}
|
|
6275
7870
|
return typeof values === "string" && values ? values : void 0;
|
|
@@ -6309,9 +7904,9 @@ function loadScanSignals(dir) {
|
|
|
6309
7904
|
function hasAgents(dir) {
|
|
6310
7905
|
const agentsDir = join(dir, ARCH_DIR2, "agents");
|
|
6311
7906
|
if (!exists(agentsDir)) return false;
|
|
6312
|
-
function hasAgentMd(
|
|
6313
|
-
for (const e of readDir(
|
|
6314
|
-
const full = join(
|
|
7907
|
+
function hasAgentMd(d3) {
|
|
7908
|
+
for (const e of readDir(d3)) {
|
|
7909
|
+
const full = join(d3, e);
|
|
6315
7910
|
if (isFile(full)) {
|
|
6316
7911
|
if (e.endsWith("-agent.md")) return true;
|
|
6317
7912
|
} else if (hasAgentMd(full)) {
|
|
@@ -6351,7 +7946,7 @@ function buildProjectExplanation(dir) {
|
|
|
6351
7946
|
infrastructureFiles: scan.infrastructureFiles
|
|
6352
7947
|
} : null;
|
|
6353
7948
|
const layers = knowledgeLayers(dir);
|
|
6354
|
-
const layerStatus = (name) => layers.find((
|
|
7949
|
+
const layerStatus = (name) => layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
6355
7950
|
const knowledge = {
|
|
6356
7951
|
hasScan: scan !== null,
|
|
6357
7952
|
hasInventory: exists(join(dir, ARCH_DIR2, "inventory.md")),
|
|
@@ -6366,18 +7961,18 @@ function buildProjectExplanation(dir) {
|
|
|
6366
7961
|
hasSkills: hasSkills(dir)
|
|
6367
7962
|
};
|
|
6368
7963
|
const workItemArtifacts = discoverWorkItems(dir);
|
|
6369
|
-
const items = workItemArtifacts.map((
|
|
6370
|
-
const src = parseWorkItemSource(
|
|
7964
|
+
const items = workItemArtifacts.map((a2) => {
|
|
7965
|
+
const src = parseWorkItemSource(a2.rawFrontmatter);
|
|
6371
7966
|
return {
|
|
6372
|
-
id:
|
|
6373
|
-
title:
|
|
6374
|
-
type:
|
|
6375
|
-
status:
|
|
6376
|
-
lifecycle: lifecycleStateOf({ status:
|
|
6377
|
-
initiative:
|
|
6378
|
-
knowledgeLevel:
|
|
6379
|
-
hasOwnership:
|
|
6380
|
-
domains:
|
|
7967
|
+
id: a2.id || a2.title,
|
|
7968
|
+
title: a2.title,
|
|
7969
|
+
type: a2.type,
|
|
7970
|
+
status: a2.status,
|
|
7971
|
+
lifecycle: lifecycleStateOf({ status: a2.status, filePath: a2.filePath }),
|
|
7972
|
+
initiative: a2.initiative,
|
|
7973
|
+
knowledgeLevel: a2.knowledgeLevel,
|
|
7974
|
+
hasOwnership: a2.codeGlobs.length > 0,
|
|
7975
|
+
domains: a2.domains,
|
|
6381
7976
|
source: { type: src.type, ...src.id ? { id: src.id } : {}, inferred: src.inferred }
|
|
6382
7977
|
};
|
|
6383
7978
|
});
|
|
@@ -6393,7 +7988,7 @@ function buildProjectExplanation(dir) {
|
|
|
6393
7988
|
if (!initiativeMap.has(name)) initiativeMap.set(name, emptyLifecycleCounts());
|
|
6394
7989
|
initiativeMap.get(name)[i.lifecycle]++;
|
|
6395
7990
|
}
|
|
6396
|
-
const initiatives = [...initiativeMap.entries()].map(([name, states]) => ({ name, states })).sort((
|
|
7991
|
+
const initiatives = [...initiativeMap.entries()].map(([name, states]) => ({ name, states })).sort((a2, b2) => a2.name.localeCompare(b2.name));
|
|
6397
7992
|
const workItems = {
|
|
6398
7993
|
total: items.length,
|
|
6399
7994
|
inProgress: items.filter((i) => i.lifecycle === "in-progress").length,
|
|
@@ -6410,9 +8005,9 @@ function buildProjectExplanation(dir) {
|
|
|
6410
8005
|
workItemsWithOwnership: withOwnership,
|
|
6411
8006
|
workItemsMissingOwnership: items.length - withOwnership
|
|
6412
8007
|
};
|
|
6413
|
-
const domains = [...new Set(workItemArtifacts.flatMap((
|
|
8008
|
+
const domains = [...new Set(workItemArtifacts.flatMap((a2) => a2.domains))].filter(Boolean);
|
|
6414
8009
|
const duplicateWorkItems = findDuplicateWorkItems(
|
|
6415
|
-
workItemArtifacts.map((
|
|
8010
|
+
workItemArtifacts.map((a2) => ({ id: a2.id || a2.title, title: a2.title, sourceId: a2.sourceId }))
|
|
6416
8011
|
);
|
|
6417
8012
|
const roadmapPath = join(dir, ARCH_DIR2, "delivery", "roadmap.md");
|
|
6418
8013
|
const roadmapMd = exists(roadmapPath) ? readFile(roadmapPath) : null;
|
|
@@ -6553,7 +8148,7 @@ function renderExplanationHuman(exp) {
|
|
|
6553
8148
|
lines.push("## Scan Signals");
|
|
6554
8149
|
lines.push(renderSignalsCompact(exp.scanSignals));
|
|
6555
8150
|
}
|
|
6556
|
-
const ls = (name) => exp.layers.find((
|
|
8151
|
+
const ls = (name) => exp.layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
6557
8152
|
lines.push("## Knowledge Status");
|
|
6558
8153
|
lines.push(`- Inventory: ${exp.knowledge.hasInventory ? "available" : "missing"}`);
|
|
6559
8154
|
lines.push(`- Context pack: ${exp.knowledge.hasContextPack ? "available" : "missing"}`);
|
|
@@ -6581,7 +8176,7 @@ function renderExplanationHuman(exp) {
|
|
|
6581
8176
|
lines.push(`- ${LIFECYCLE_LABEL[s2]}: ${exp.workItems.byState[s2]}`);
|
|
6582
8177
|
}
|
|
6583
8178
|
lines.push("");
|
|
6584
|
-
const typeEntries = Object.entries(exp.workItems.byType).sort((
|
|
8179
|
+
const typeEntries = Object.entries(exp.workItems.byType).sort((a2, b2) => b2[1] - a2[1]);
|
|
6585
8180
|
if (typeEntries.length > 0) {
|
|
6586
8181
|
lines.push("## Work Items by Type");
|
|
6587
8182
|
for (const [t, n] of typeEntries) lines.push(`- ${typeLabel(t)}: ${n}`);
|
|
@@ -6629,15 +8224,15 @@ function renderExplanationHuman(exp) {
|
|
|
6629
8224
|
}
|
|
6630
8225
|
lines.push("## Mapped Modules");
|
|
6631
8226
|
if (exp.mappedModules.length > 0) {
|
|
6632
|
-
for (const
|
|
6633
|
-
const owner =
|
|
6634
|
-
lines.push(`- ${
|
|
8227
|
+
for (const m2 of exp.mappedModules) {
|
|
8228
|
+
const owner = m2.owner ? ` \u2014 owner: ${m2.owner}` : "";
|
|
8229
|
+
lines.push(`- ${m2.id} \u2014 ${m2.type ?? "unknown"} \u2014 ${m2.repoPath || "\u2014"}${owner}`);
|
|
6635
8230
|
}
|
|
6636
8231
|
lines.push("");
|
|
6637
8232
|
lines.push("## Module Artifact Coverage");
|
|
6638
|
-
for (const
|
|
6639
|
-
const present = presentArtifacts(
|
|
6640
|
-
lines.push(`- ${
|
|
8233
|
+
for (const m2 of exp.mappedModules) {
|
|
8234
|
+
const present = presentArtifacts(m2.artifacts);
|
|
8235
|
+
lines.push(`- ${m2.id}: ${present.length > 0 ? present.join(", ") : "none"}`);
|
|
6641
8236
|
}
|
|
6642
8237
|
lines.push("");
|
|
6643
8238
|
} else {
|
|
@@ -6673,7 +8268,7 @@ function renderExplanationHuman(exp) {
|
|
|
6673
8268
|
}
|
|
6674
8269
|
if (exp.skills.total > 0) {
|
|
6675
8270
|
lines.push(`## Skills installed: ${exp.skills.total}`);
|
|
6676
|
-
const groups = Object.entries(exp.skills.byGroup).sort((
|
|
8271
|
+
const groups = Object.entries(exp.skills.byGroup).sort((a2, b2) => a2[0].localeCompare(b2[0]));
|
|
6677
8272
|
if (groups.length > 0) {
|
|
6678
8273
|
lines.push("Groups:");
|
|
6679
8274
|
for (const [g, n] of groups) lines.push(`- ${g}: ${n}`);
|
|
@@ -6682,7 +8277,7 @@ function renderExplanationHuman(exp) {
|
|
|
6682
8277
|
}
|
|
6683
8278
|
if (exp.missingKnowledge.length > 0) {
|
|
6684
8279
|
lines.push("## Missing Knowledge");
|
|
6685
|
-
for (const
|
|
8280
|
+
for (const m2 of exp.missingKnowledge) lines.push(`- ${m2}`);
|
|
6686
8281
|
lines.push("");
|
|
6687
8282
|
}
|
|
6688
8283
|
if (exp.duplicateWorkItems.length > 0) {
|
|
@@ -6700,7 +8295,7 @@ function renderExplanationHuman(exp) {
|
|
|
6700
8295
|
lines.push(`- Phase: ${assessment.phase}`);
|
|
6701
8296
|
if (assessment.reasons.length > 0) {
|
|
6702
8297
|
lines.push("- Reason:");
|
|
6703
|
-
for (const
|
|
8298
|
+
for (const r3 of assessment.reasons) lines.push(` - ${r3}`);
|
|
6704
8299
|
}
|
|
6705
8300
|
lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
|
|
6706
8301
|
lines.push("");
|
|
@@ -6712,11 +8307,11 @@ function renderExplanationHuman(exp) {
|
|
|
6712
8307
|
steps.forEach((s2, i) => lines.push(`${i + 1}. ${s2}`));
|
|
6713
8308
|
lines.push("");
|
|
6714
8309
|
}
|
|
6715
|
-
const
|
|
6716
|
-
const s =
|
|
8310
|
+
const r2 = exp.readiness;
|
|
8311
|
+
const s = r2.signals;
|
|
6717
8312
|
lines.push("## Project Readiness");
|
|
6718
|
-
lines.push(`- overall: ${
|
|
6719
|
-
if (
|
|
8313
|
+
lines.push(`- overall: ${r2.overall}`);
|
|
8314
|
+
if (r2.overall !== "not-initialized" && r2.overall !== "not-applicable" && r2.overall !== "legacy-project") {
|
|
6720
8315
|
lines.push(`- bootstrap baseline: ${s.bootstrap_baseline}`);
|
|
6721
8316
|
lines.push(`- scan: ${s.scan}`);
|
|
6722
8317
|
lines.push(`- understand: ${s.understand}`);
|
|
@@ -6736,11 +8331,11 @@ function renderExplanationHuman(exp) {
|
|
|
6736
8331
|
}
|
|
6737
8332
|
lines.push("");
|
|
6738
8333
|
lines.push("### Recommended next step");
|
|
6739
|
-
lines.push(
|
|
8334
|
+
lines.push(r2.recommended_next_step.label);
|
|
6740
8335
|
lines.push("");
|
|
6741
8336
|
const td = exp.techDecisions;
|
|
6742
8337
|
const tk = exp.techKnowledge;
|
|
6743
|
-
const mark = (
|
|
8338
|
+
const mark = (b2) => b2 ? "\u2713" : "\u2717";
|
|
6744
8339
|
lines.push("## Tech Knowledge");
|
|
6745
8340
|
lines.push("Core:");
|
|
6746
8341
|
lines.push(`- ${mark(tk.core.currentState)} current-state.md`);
|
|
@@ -6815,8 +8410,8 @@ function renderExplanationHuman(exp) {
|
|
|
6815
8410
|
}
|
|
6816
8411
|
if (exp.metadataHealth.findings.length > 0) {
|
|
6817
8412
|
lines.push("## Metadata Health");
|
|
6818
|
-
for (const
|
|
6819
|
-
lines.push(`- \`${
|
|
8413
|
+
for (const f3 of exp.metadataHealth.findings) {
|
|
8414
|
+
lines.push(`- \`${f3.file}\`: ${f3.detail}`);
|
|
6820
8415
|
}
|
|
6821
8416
|
lines.push("");
|
|
6822
8417
|
}
|
|
@@ -6849,30 +8444,30 @@ function loadGuardRuns(dir) {
|
|
|
6849
8444
|
return out;
|
|
6850
8445
|
}
|
|
6851
8446
|
function resolveDriftThreads(runs) {
|
|
6852
|
-
const sorted = [...runs].sort((
|
|
8447
|
+
const sorted = [...runs].sort((a2, b2) => a2.generated_at.localeCompare(b2.generated_at));
|
|
6853
8448
|
const paths = /* @__PURE__ */ new Set();
|
|
6854
|
-
for (const
|
|
8449
|
+
for (const r2 of sorted) for (const w3 of r2.warnings) paths.add(w3.code_path);
|
|
6855
8450
|
const threads = [];
|
|
6856
8451
|
for (const codePath of paths) {
|
|
6857
8452
|
const related = /* @__PURE__ */ new Set();
|
|
6858
8453
|
let firstDetected = "";
|
|
6859
8454
|
let lastWarn = "";
|
|
6860
|
-
for (const
|
|
6861
|
-
const
|
|
6862
|
-
if (
|
|
6863
|
-
if (!firstDetected) firstDetected =
|
|
6864
|
-
lastWarn =
|
|
6865
|
-
for (const
|
|
8455
|
+
for (const r2 of sorted) {
|
|
8456
|
+
const w3 = r2.warnings.find((x2) => x2.code_path === codePath);
|
|
8457
|
+
if (w3) {
|
|
8458
|
+
if (!firstDetected) firstDetected = r2.generated_at;
|
|
8459
|
+
lastWarn = r2.generated_at;
|
|
8460
|
+
for (const a2 of w3.related_artifacts) related.add(a2);
|
|
6866
8461
|
}
|
|
6867
8462
|
}
|
|
6868
8463
|
let resolvedAt;
|
|
6869
|
-
for (const
|
|
6870
|
-
if (
|
|
6871
|
-
const touched =
|
|
6872
|
-
const warnedHere =
|
|
6873
|
-
const updatedRelated =
|
|
8464
|
+
for (const r2 of sorted) {
|
|
8465
|
+
if (r2.generated_at <= lastWarn) continue;
|
|
8466
|
+
const touched = r2.touched_files.some((f3) => toPosix5(f3) === codePath);
|
|
8467
|
+
const warnedHere = r2.warnings.some((x2) => x2.code_path === codePath);
|
|
8468
|
+
const updatedRelated = r2.updated_artifacts.some((a2) => related.has(a2));
|
|
6874
8469
|
if (touched && updatedRelated && !warnedHere) {
|
|
6875
|
-
resolvedAt =
|
|
8470
|
+
resolvedAt = r2.generated_at;
|
|
6876
8471
|
break;
|
|
6877
8472
|
}
|
|
6878
8473
|
}
|
|
@@ -6893,9 +8488,9 @@ function hotspotDir(codePath) {
|
|
|
6893
8488
|
}
|
|
6894
8489
|
function computeTrend(runs) {
|
|
6895
8490
|
if (runs.length < 2) return { direction: "unknown", reason: "Not enough recorded runs to detect a trend." };
|
|
6896
|
-
const sorted = [...runs].sort((
|
|
8491
|
+
const sorted = [...runs].sort((a2, b2) => a2.generated_at.localeCompare(b2.generated_at));
|
|
6897
8492
|
const mid = Math.floor(sorted.length / 2);
|
|
6898
|
-
const avg = (arr) => arr.length ? arr.reduce((s,
|
|
8493
|
+
const avg = (arr) => arr.length ? arr.reduce((s, r2) => s + r2.warnings.length, 0) / arr.length : 0;
|
|
6899
8494
|
const earlier = avg(sorted.slice(0, mid));
|
|
6900
8495
|
const recent = avg(sorted.slice(mid));
|
|
6901
8496
|
if (recent < earlier) return { direction: "improving", reason: "Fewer warnings in the last recorded runs." };
|
|
@@ -6921,18 +8516,18 @@ function buildGuardHistory(dir) {
|
|
|
6921
8516
|
trend: { direction: "unknown", reason: "No guard history recorded yet." }
|
|
6922
8517
|
};
|
|
6923
8518
|
}
|
|
6924
|
-
const sorted = [...runs].sort((
|
|
8519
|
+
const sorted = [...runs].sort((a2, b2) => a2.generated_at.localeCompare(b2.generated_at));
|
|
6925
8520
|
const threads = resolveDriftThreads(sorted);
|
|
6926
8521
|
const open = threads.filter((t) => t.status === "open").length;
|
|
6927
8522
|
const resolved = threads.filter((t) => t.status === "resolved").length;
|
|
6928
8523
|
const detected = threads.length;
|
|
6929
|
-
const runsWithWarnings = sorted.filter((
|
|
8524
|
+
const runsWithWarnings = sorted.filter((r2) => r2.warnings.length > 0).length;
|
|
6930
8525
|
const hotspotMap = /* @__PURE__ */ new Map();
|
|
6931
8526
|
for (const t of threads) {
|
|
6932
|
-
const
|
|
6933
|
-
hotspotMap.set(
|
|
8527
|
+
const d3 = hotspotDir(t.code_path);
|
|
8528
|
+
hotspotMap.set(d3, (hotspotMap.get(d3) ?? 0) + 1);
|
|
6934
8529
|
}
|
|
6935
|
-
const hotspots = [...hotspotMap.entries()].map(([path3, warnings]) => ({ path: path3, warnings })).sort((
|
|
8530
|
+
const hotspots = [...hotspotMap.entries()].map(([path3, warnings]) => ({ path: path3, warnings })).sort((a2, b2) => b2.warnings - a2.warnings);
|
|
6936
8531
|
return {
|
|
6937
8532
|
available: true,
|
|
6938
8533
|
total_runs: sorted.length,
|
|
@@ -6956,14 +8551,14 @@ function isBroadGlob(glob) {
|
|
|
6956
8551
|
const prefix = glob.slice(0, -3);
|
|
6957
8552
|
return prefix.length > 0 && prefix.split("/").length <= 2;
|
|
6958
8553
|
}
|
|
6959
|
-
function levelFromRatio(
|
|
6960
|
-
if (
|
|
6961
|
-
if (
|
|
6962
|
-
if (
|
|
8554
|
+
function levelFromRatio(r2) {
|
|
8555
|
+
if (r2 >= 0.9) return "Very High";
|
|
8556
|
+
if (r2 >= 0.7) return "High";
|
|
8557
|
+
if (r2 >= 0.4) return "Medium";
|
|
6963
8558
|
return "Low";
|
|
6964
8559
|
}
|
|
6965
8560
|
function hasSection(body, re) {
|
|
6966
|
-
return body.split(/\r?\n/).some((
|
|
8561
|
+
return body.split(/\r?\n/).some((l2) => /^#{1,6}\s+/.test(l2) && re.test(l2));
|
|
6967
8562
|
}
|
|
6968
8563
|
function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
6969
8564
|
const resolvedScope = opts.scope ?? "all";
|
|
@@ -7029,7 +8624,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7029
8624
|
} catch {
|
|
7030
8625
|
}
|
|
7031
8626
|
}
|
|
7032
|
-
const ownedCodePaths = [...globCounts.values()].reduce((
|
|
8627
|
+
const ownedCodePaths = [...globCounts.values()].reduce((a2, b2) => a2 + b2, 0);
|
|
7033
8628
|
const broadGlobs = [...globCounts.keys()].filter((g2) => isBroadGlob(g2)).length;
|
|
7034
8629
|
for (const [glob, owners] of globOwners) {
|
|
7035
8630
|
if (owners.length > 1) {
|
|
@@ -7046,7 +8641,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7046
8641
|
} else {
|
|
7047
8642
|
g = { available: false, scope: resolvedScope, scopeReason: "", nodes: 0, edges: 0, quality: "unknown", hints: 0, generatedAt: "" };
|
|
7048
8643
|
}
|
|
7049
|
-
const layerStatus = (name) => exp.layers.find((
|
|
8644
|
+
const layerStatus = (name) => exp.layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
7050
8645
|
const byState = exp.workItems.byState;
|
|
7051
8646
|
const skills = discoverInstalledSkills(dir);
|
|
7052
8647
|
const knowledge_health = {
|
|
@@ -7116,7 +8711,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7116
8711
|
let score_breakdown = null;
|
|
7117
8712
|
if (total > 0) {
|
|
7118
8713
|
const healthPts = [layerStatus("Business"), layerStatus("Product"), layerStatus("Tech"), layerStatus("Delivery")].filter((s) => s !== "Missing").length / 4 * 20;
|
|
7119
|
-
const covAvg = knowledge_coverage.reduce((
|
|
8714
|
+
const covAvg = knowledge_coverage.reduce((a2, c) => a2 + coverageRatio(c.have), 0) / knowledge_coverage.length;
|
|
7120
8715
|
const coveragePts = covAvg * 20;
|
|
7121
8716
|
const ownPts = coverageRatio(withOwnership) * 15;
|
|
7122
8717
|
const traceBlend = (exp.roadmap.candidates > 0 ? exp.roadmap.materialized / exp.roadmap.candidates : 1) * 0.5 + coverageRatio(withOwnership) * 0.5;
|
|
@@ -7144,14 +8739,14 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7144
8739
|
if (!g.available) actions.push("Run `kaddo graph export --scope all` to inspect full traceability.");
|
|
7145
8740
|
else if (g.scope === "active" && g.quality === "empty") actions.push("Run `kaddo impact --scope all` to measure accumulated knowledge impact.");
|
|
7146
8741
|
if (exp.roadmap.remaining > 0) actions.push(`Materialize the ${exp.roadmap.remaining} remaining roadmap candidate(s) with \`kaddo create --from roadmap\`.`);
|
|
7147
|
-
for (const
|
|
8742
|
+
for (const a2 of [
|
|
7148
8743
|
groupedAction(gaps.missing_code_ownership, "Add `code:` ownership to"),
|
|
7149
8744
|
groupedAction(gaps.missing_source, "Add `source`/`source_id` to"),
|
|
7150
8745
|
groupedAction(gaps.missing_initiative, "Add an `initiative` to"),
|
|
7151
8746
|
groupedAction(gaps.missing_acceptance_criteria, "Add Acceptance Criteria to"),
|
|
7152
8747
|
groupedAction(gaps.missing_definition_of_done, "Add a Definition of Done to"),
|
|
7153
8748
|
groupedAction(gaps.missing_validation, "Add a validation (How to test it) section to")
|
|
7154
|
-
]) if (
|
|
8749
|
+
]) if (a2) actions.push(a2);
|
|
7155
8750
|
if (gaps.broad_ownership_globs.length > 0) actions.push(`Narrow ${gaps.broad_ownership_globs.length} broad ownership glob(s) into specific paths.`);
|
|
7156
8751
|
if (g.available && g.hints > 0) actions.push("Review graph hints (`kaddo://graph-hints` or `.kaddo/graph-hints.md`).");
|
|
7157
8752
|
if (skills.length === 0) actions.push("Install reusable skills with `kaddo add skills`.");
|
|
@@ -7215,38 +8810,38 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7215
8810
|
function ratio(have, total) {
|
|
7216
8811
|
return `${have}/${total}`;
|
|
7217
8812
|
}
|
|
7218
|
-
function renderImpactMarkdown(
|
|
8813
|
+
function renderImpactMarkdown(r2) {
|
|
7219
8814
|
const L = [];
|
|
7220
8815
|
L.push("# Kaddo Knowledge Impact Report", "");
|
|
7221
|
-
L.push(`Generated at: ${
|
|
7222
|
-
L.push(`Project: ${
|
|
7223
|
-
L.push(`Scope: ${
|
|
7224
|
-
if (
|
|
8816
|
+
L.push(`Generated at: ${r2.generated_at}`);
|
|
8817
|
+
L.push(`Project: ${r2.project}`);
|
|
8818
|
+
L.push(`Scope: ${r2.scope}`);
|
|
8819
|
+
if (r2.score !== null) L.push(`Knowledge Impact Score: ${r2.score}/100`);
|
|
7225
8820
|
else L.push("Knowledge Impact Score: not available");
|
|
7226
|
-
if (
|
|
8821
|
+
if (r2.scope_source === "default") {
|
|
7227
8822
|
L.push("Scope note: Impact reports use `all` by default to measure accumulated knowledge impact.");
|
|
7228
|
-
} else if (
|
|
8823
|
+
} else if (r2.scope === "active" && r2.graph_quality.available === false) {
|
|
7229
8824
|
L.push("Tip: Run `kaddo impact --scope all` to inspect accumulated knowledge impact.");
|
|
7230
8825
|
}
|
|
7231
8826
|
L.push("");
|
|
7232
8827
|
L.push("## Executive Summary", "");
|
|
7233
|
-
for (const s2 of
|
|
8828
|
+
for (const s2 of r2.executive_summary) L.push(`- ${s2}`);
|
|
7234
8829
|
L.push("");
|
|
7235
8830
|
L.push("## Knowledge Health", "");
|
|
7236
|
-
for (const [
|
|
8831
|
+
for (const [k2, v] of Object.entries(r2.knowledge_health)) L.push(`- ${k2}: ${v}`);
|
|
7237
8832
|
L.push("");
|
|
7238
8833
|
L.push("## Knowledge Coverage", "");
|
|
7239
|
-
for (const c of
|
|
8834
|
+
for (const c of r2.knowledge_coverage) L.push(`- ${c.label}: ${ratio(c.have, c.total)}`);
|
|
7240
8835
|
L.push("");
|
|
7241
8836
|
L.push("## Ownership Coverage", "");
|
|
7242
|
-
L.push(`- Coverage: ${
|
|
7243
|
-
L.push(`- Work Items with code ownership: ${
|
|
7244
|
-
L.push(`- Owned code paths: ${
|
|
7245
|
-
L.push(`- Broad globs detected: ${
|
|
7246
|
-
L.push(`- Ownership overlaps: ${
|
|
8837
|
+
L.push(`- Coverage: ${r2.ownership_coverage.coverage_percent}%`);
|
|
8838
|
+
L.push(`- Work Items with code ownership: ${r2.ownership_coverage.work_items_with_ownership}`);
|
|
8839
|
+
L.push(`- Owned code paths: ${r2.ownership_coverage.owned_code_paths}`);
|
|
8840
|
+
L.push(`- Broad globs detected: ${r2.ownership_coverage.broad_globs}`);
|
|
8841
|
+
L.push(`- Ownership overlaps: ${r2.ownership_coverage.ownership_overlaps}`);
|
|
7247
8842
|
L.push("");
|
|
7248
8843
|
L.push("## Traceability", "");
|
|
7249
|
-
const t =
|
|
8844
|
+
const t = r2.traceability;
|
|
7250
8845
|
L.push(`- Roadmap candidates: ${t.roadmap_candidates}`);
|
|
7251
8846
|
L.push(`- Materialized Work Items: ${t.materialized_work_items}`);
|
|
7252
8847
|
L.push(`- Remaining candidates: ${t.remaining_candidates}`);
|
|
@@ -7259,24 +8854,24 @@ function renderImpactMarkdown(r) {
|
|
|
7259
8854
|
if (t.graph_hints !== null) L.push(`- Graph hints: ${t.graph_hints}`);
|
|
7260
8855
|
L.push("");
|
|
7261
8856
|
L.push("## Context Readiness", "");
|
|
7262
|
-
L.push(`Context Readiness: ${
|
|
7263
|
-
if (
|
|
8857
|
+
L.push(`Context Readiness: ${r2.context_readiness.level}`);
|
|
8858
|
+
if (r2.context_readiness.reasons.length > 0) {
|
|
7264
8859
|
L.push("", "Reason:");
|
|
7265
|
-
for (const reason of
|
|
8860
|
+
for (const reason of r2.context_readiness.reasons) L.push(`- ${reason}`);
|
|
7266
8861
|
}
|
|
7267
8862
|
L.push("");
|
|
7268
8863
|
L.push("## Work Item Readiness", "");
|
|
7269
|
-
const
|
|
7270
|
-
L.push(`- Draft: ${
|
|
7271
|
-
L.push(`- Ready: ${
|
|
7272
|
-
L.push(`- In Progress: ${
|
|
7273
|
-
L.push(`- Blocked: ${
|
|
7274
|
-
L.push(`- Completed: ${
|
|
7275
|
-
L.push(`- Ready quality: ${
|
|
8864
|
+
const w3 = r2.work_item_readiness;
|
|
8865
|
+
L.push(`- Draft: ${w3.draft}`);
|
|
8866
|
+
L.push(`- Ready: ${w3.ready}`);
|
|
8867
|
+
L.push(`- In Progress: ${w3.in_progress}`);
|
|
8868
|
+
L.push(`- Blocked: ${w3.blocked}`);
|
|
8869
|
+
L.push(`- Completed: ${w3.completed}`);
|
|
8870
|
+
L.push(`- Ready quality: ${w3.ready_quality}`);
|
|
7276
8871
|
L.push("");
|
|
7277
8872
|
L.push("## Graph Quality", "");
|
|
7278
|
-
if (
|
|
7279
|
-
const gq =
|
|
8873
|
+
if (r2.graph_quality.available) {
|
|
8874
|
+
const gq = r2.graph_quality;
|
|
7280
8875
|
L.push(`- Scope: ${gq.scope}`);
|
|
7281
8876
|
L.push(`- Quality: ${gq.quality}`);
|
|
7282
8877
|
L.push(`- Nodes: ${gq.nodes}`);
|
|
@@ -7289,12 +8884,12 @@ function renderImpactMarkdown(r) {
|
|
|
7289
8884
|
}
|
|
7290
8885
|
} else {
|
|
7291
8886
|
L.push("- Graph data not available.");
|
|
7292
|
-
L.push(`- Tip: ${
|
|
8887
|
+
L.push(`- Tip: ${r2.graph_quality.suggestion}`);
|
|
7293
8888
|
}
|
|
7294
8889
|
L.push("");
|
|
7295
8890
|
L.push("## Guard Activity", "");
|
|
7296
|
-
if (
|
|
7297
|
-
const ga =
|
|
8891
|
+
if (r2.guard_activity.available) {
|
|
8892
|
+
const ga = r2.guard_activity;
|
|
7298
8893
|
L.push("- Guard history: available");
|
|
7299
8894
|
L.push(`- Guard runs recorded: ${ga.runs_recorded}`);
|
|
7300
8895
|
L.push(`- Drift warnings detected: ${ga.detected}`);
|
|
@@ -7303,11 +8898,11 @@ function renderImpactMarkdown(r) {
|
|
|
7303
8898
|
L.push(`- Resolution rate: ${ga.resolution_rate}%`);
|
|
7304
8899
|
} else {
|
|
7305
8900
|
L.push("- Guard history: not available");
|
|
7306
|
-
L.push(`- Note: ${
|
|
8901
|
+
L.push(`- Note: ${r2.guard_activity.note}`);
|
|
7307
8902
|
}
|
|
7308
8903
|
L.push("");
|
|
7309
8904
|
L.push("## Impact Signals", "");
|
|
7310
|
-
const s =
|
|
8905
|
+
const s = r2.impact_signals;
|
|
7311
8906
|
L.push(`- Ambiguity reduction: ${s.ambiguity_reduction}`);
|
|
7312
8907
|
L.push(`- Drift prevention: ${s.drift_prevention}`);
|
|
7313
8908
|
L.push(`- Onboarding support: ${s.onboarding_support}`);
|
|
@@ -7316,7 +8911,7 @@ function renderImpactMarkdown(r) {
|
|
|
7316
8911
|
L.push(`- Maintenance readiness: ${s.maintenance_readiness}`);
|
|
7317
8912
|
L.push("");
|
|
7318
8913
|
L.push("## Actionable Gaps", "");
|
|
7319
|
-
const gp =
|
|
8914
|
+
const gp = r2.actionable_gaps;
|
|
7320
8915
|
const gapSection = (title, items) => {
|
|
7321
8916
|
if (items.length === 0) return;
|
|
7322
8917
|
L.push(`### ${title}`, "");
|
|
@@ -7336,19 +8931,19 @@ function renderImpactMarkdown(r) {
|
|
|
7336
8931
|
gapSection("Work Items missing validation", gp.missing_validation);
|
|
7337
8932
|
if (gp.broad_ownership_globs.length > 0) {
|
|
7338
8933
|
L.push("### Broad ownership globs", "");
|
|
7339
|
-
for (const
|
|
7340
|
-
L.push(`- ${
|
|
7341
|
-
L.push(` - Glob: \`${
|
|
7342
|
-
L.push(` - Suggested action: ${
|
|
8934
|
+
for (const b2 of gp.broad_ownership_globs) {
|
|
8935
|
+
L.push(`- ${b2.id} \u2014 ${b2.title}`);
|
|
8936
|
+
L.push(` - Glob: \`${b2.glob}\``);
|
|
8937
|
+
L.push(` - Suggested action: ${b2.suggested_action}`);
|
|
7343
8938
|
}
|
|
7344
8939
|
L.push("");
|
|
7345
8940
|
}
|
|
7346
8941
|
if (gp.ownership_overlaps.length > 0) {
|
|
7347
8942
|
L.push("### Ownership overlaps", "");
|
|
7348
|
-
for (const
|
|
7349
|
-
L.push(`- \`${
|
|
7350
|
-
L.push(` - Owned by: ${
|
|
7351
|
-
L.push(` - Suggested action: ${
|
|
8943
|
+
for (const o2 of gp.ownership_overlaps) {
|
|
8944
|
+
L.push(`- \`${o2.code_path}\``);
|
|
8945
|
+
L.push(` - Owned by: ${o2.work_items.join(", ")}`);
|
|
8946
|
+
L.push(` - Suggested action: ${o2.suggested_action}`);
|
|
7352
8947
|
}
|
|
7353
8948
|
L.push("");
|
|
7354
8949
|
}
|
|
@@ -7356,28 +8951,28 @@ function renderImpactMarkdown(r) {
|
|
|
7356
8951
|
if (anyGaps === 0) {
|
|
7357
8952
|
L.push("No actionable knowledge gaps detected. \u{1F389}", "");
|
|
7358
8953
|
}
|
|
7359
|
-
if (
|
|
8954
|
+
if (r2.score_breakdown) {
|
|
7360
8955
|
L.push("## Score Breakdown", "");
|
|
7361
|
-
const
|
|
7362
|
-
L.push(`- Knowledge Health: ${
|
|
7363
|
-
L.push(`- Knowledge Coverage: ${
|
|
7364
|
-
L.push(`- Ownership Coverage: ${
|
|
7365
|
-
L.push(`- Traceability: ${
|
|
7366
|
-
L.push(`- Graph Quality: ${
|
|
7367
|
-
L.push(`- Context Readiness: ${
|
|
8956
|
+
const b2 = r2.score_breakdown;
|
|
8957
|
+
L.push(`- Knowledge Health: ${b2.knowledge_health.points}/${b2.knowledge_health.max}`);
|
|
8958
|
+
L.push(`- Knowledge Coverage: ${b2.knowledge_coverage.points}/${b2.knowledge_coverage.max}`);
|
|
8959
|
+
L.push(`- Ownership Coverage: ${b2.ownership_coverage.points}/${b2.ownership_coverage.max}`);
|
|
8960
|
+
L.push(`- Traceability: ${b2.traceability.points}/${b2.traceability.max}`);
|
|
8961
|
+
L.push(`- Graph Quality: ${b2.graph_quality.points}/${b2.graph_quality.max}`);
|
|
8962
|
+
L.push(`- Context Readiness: ${b2.context_readiness.points}/${b2.context_readiness.max}`);
|
|
7368
8963
|
L.push("");
|
|
7369
8964
|
}
|
|
7370
8965
|
L.push("## Suggested Actions", "");
|
|
7371
|
-
|
|
8966
|
+
r2.suggested_actions.forEach((a2, i) => L.push(`${i + 1}. ${a2}`));
|
|
7372
8967
|
L.push("");
|
|
7373
8968
|
return L.join("\n");
|
|
7374
8969
|
}
|
|
7375
|
-
function serializeImpactJson(
|
|
7376
|
-
return JSON.stringify(
|
|
8970
|
+
function serializeImpactJson(r2) {
|
|
8971
|
+
return JSON.stringify(r2, null, 2) + "\n";
|
|
7377
8972
|
}
|
|
7378
8973
|
|
|
7379
8974
|
// ../cli/src/core/savings.ts
|
|
7380
|
-
import { parse as
|
|
8975
|
+
import { parse as parseYaml7 } from "yaml";
|
|
7381
8976
|
var DEFAULT_ASSUMPTIONS = {
|
|
7382
8977
|
currency: "USD",
|
|
7383
8978
|
hourly_cost: 40,
|
|
@@ -7395,21 +8990,21 @@ function loadAssumptions(dir) {
|
|
|
7395
8990
|
const p = join(dir, SAVINGS_PATH);
|
|
7396
8991
|
if (!exists(p)) return { assumptions: { ...DEFAULT_ASSUMPTIONS }, source: "default" };
|
|
7397
8992
|
try {
|
|
7398
|
-
const raw =
|
|
7399
|
-
const
|
|
8993
|
+
const raw = parseYaml7(readFile(p));
|
|
8994
|
+
const a2 = raw?.assumptions ?? {};
|
|
7400
8995
|
const t = raw?.team ?? {};
|
|
7401
|
-
const num = (v,
|
|
8996
|
+
const num = (v, d3) => typeof v === "number" && Number.isFinite(v) ? v : d3;
|
|
7402
8997
|
return {
|
|
7403
8998
|
source: "file",
|
|
7404
8999
|
assumptions: {
|
|
7405
9000
|
currency: raw?.currency ?? DEFAULT_ASSUMPTIONS.currency,
|
|
7406
9001
|
hourly_cost: num(raw?.hourly_cost, DEFAULT_ASSUMPTIONS.hourly_cost),
|
|
7407
|
-
context_preparation_minutes_saved_per_work_item: num(
|
|
7408
|
-
rework_hours_avoided_per_resolved_drift: num(
|
|
7409
|
-
onboarding_hours_saved_per_new_contributor: num(
|
|
7410
|
-
review_minutes_saved_per_work_item_with_ownership: num(
|
|
7411
|
-
clarification_minutes_saved_per_ready_work_item: num(
|
|
7412
|
-
architecture_discovery_hours_saved_when_graph_good: num(
|
|
9002
|
+
context_preparation_minutes_saved_per_work_item: num(a2.context_preparation_minutes_saved_per_work_item, DEFAULT_ASSUMPTIONS.context_preparation_minutes_saved_per_work_item),
|
|
9003
|
+
rework_hours_avoided_per_resolved_drift: num(a2.rework_hours_avoided_per_resolved_drift, DEFAULT_ASSUMPTIONS.rework_hours_avoided_per_resolved_drift),
|
|
9004
|
+
onboarding_hours_saved_per_new_contributor: num(a2.onboarding_hours_saved_per_new_contributor, DEFAULT_ASSUMPTIONS.onboarding_hours_saved_per_new_contributor),
|
|
9005
|
+
review_minutes_saved_per_work_item_with_ownership: num(a2.review_minutes_saved_per_work_item_with_ownership, DEFAULT_ASSUMPTIONS.review_minutes_saved_per_work_item_with_ownership),
|
|
9006
|
+
clarification_minutes_saved_per_ready_work_item: num(a2.clarification_minutes_saved_per_ready_work_item, DEFAULT_ASSUMPTIONS.clarification_minutes_saved_per_ready_work_item),
|
|
9007
|
+
architecture_discovery_hours_saved_when_graph_good: num(a2.architecture_discovery_hours_saved_when_graph_good, DEFAULT_ASSUMPTIONS.architecture_discovery_hours_saved_when_graph_good),
|
|
7413
9008
|
expected_new_contributors_per_month: num(t.expected_new_contributors_per_month, DEFAULT_ASSUMPTIONS.expected_new_contributors_per_month),
|
|
7414
9009
|
expected_work_items_per_month: num(t.expected_work_items_per_month, DEFAULT_ASSUMPTIONS.expected_work_items_per_month)
|
|
7415
9010
|
}
|
|
@@ -7422,12 +9017,12 @@ var READINESS_MULT = { Low: 0.25, Medium: 0.5, High: 0.75, "Very High": 1 };
|
|
|
7422
9017
|
var GRAPH_MULT = { empty: 0, sparse: 0.25, partial: 0.6, good: 1, unknown: 0 };
|
|
7423
9018
|
var round2 = (n) => Math.round(n * 100) / 100;
|
|
7424
9019
|
function parseRatioNumerator(s) {
|
|
7425
|
-
const
|
|
7426
|
-
return
|
|
9020
|
+
const m2 = s.match(/^(\d+)/);
|
|
9021
|
+
return m2 ? Number(m2[1]) : 0;
|
|
7427
9022
|
}
|
|
7428
9023
|
var SAVINGS_DISCLAIMER = "These are evidence-based estimates, not exact ROI. Adjust assumptions with real team data.";
|
|
7429
9024
|
function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
7430
|
-
const { assumptions:
|
|
9025
|
+
const { assumptions: a2, source } = loadAssumptions(dir);
|
|
7431
9026
|
const impact = buildImpactReport(dir, { scope: opts.scope, scopeSource: opts.scopeSource }, now);
|
|
7432
9027
|
const completed = impact.traceability.completed_work_items;
|
|
7433
9028
|
const wiWithOwnership = parseRatioNumerator(impact.traceability.work_items_connected_to_code);
|
|
@@ -7435,13 +9030,13 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7435
9030
|
const wiWithAcceptance = acceptanceCov?.have ?? 0;
|
|
7436
9031
|
const graphQuality = impact.graph_quality.available ? impact.graph_quality.quality : "unknown";
|
|
7437
9032
|
const readiness = impact.context_readiness.level;
|
|
7438
|
-
const ctxPrepH = round2(completed *
|
|
7439
|
-
const reviewH = round2(wiWithOwnership *
|
|
7440
|
-
const clarH = round2(wiWithAcceptance *
|
|
9033
|
+
const ctxPrepH = round2(completed * a2.context_preparation_minutes_saved_per_work_item / 60);
|
|
9034
|
+
const reviewH = round2(wiWithOwnership * a2.review_minutes_saved_per_work_item_with_ownership / 60);
|
|
9035
|
+
const clarH = round2(wiWithAcceptance * a2.clarification_minutes_saved_per_ready_work_item / 60);
|
|
7441
9036
|
const readinessMult = READINESS_MULT[readiness] ?? 0.5;
|
|
7442
|
-
const onboardH = round2(
|
|
9037
|
+
const onboardH = round2(a2.expected_new_contributors_per_month * a2.onboarding_hours_saved_per_new_contributor * readinessMult);
|
|
7443
9038
|
const graphMult = GRAPH_MULT[graphQuality] ?? 0;
|
|
7444
|
-
const archH = round2(
|
|
9039
|
+
const archH = round2(a2.architecture_discovery_hours_saved_when_graph_good * graphMult);
|
|
7445
9040
|
const guard = buildGuardHistory(dir);
|
|
7446
9041
|
let driftSavings;
|
|
7447
9042
|
if (!guard.available) {
|
|
@@ -7449,19 +9044,19 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7449
9044
|
} else if (guard.resolved > 0) {
|
|
7450
9045
|
driftSavings = {
|
|
7451
9046
|
available: true,
|
|
7452
|
-
hours: round2(guard.resolved *
|
|
7453
|
-
formula: `${guard.resolved} resolved drift warnings \xD7 ${
|
|
9047
|
+
hours: round2(guard.resolved * a2.rework_hours_avoided_per_resolved_drift),
|
|
9048
|
+
formula: `${guard.resolved} resolved drift warnings \xD7 ${a2.rework_hours_avoided_per_resolved_drift} h`
|
|
7454
9049
|
};
|
|
7455
9050
|
} else {
|
|
7456
9051
|
driftSavings = {
|
|
7457
9052
|
available: true,
|
|
7458
9053
|
hours: 0,
|
|
7459
|
-
formula: `0 resolved drift warnings \xD7 ${
|
|
9054
|
+
formula: `0 resolved drift warnings \xD7 ${a2.rework_hours_avoided_per_resolved_drift} h`,
|
|
7460
9055
|
reason: "Guard history exists, but no resolved drift warnings have been recorded yet."
|
|
7461
9056
|
};
|
|
7462
9057
|
}
|
|
7463
9058
|
const totalHours = round2(ctxPrepH + reviewH + clarH + onboardH + archH + driftSavings.hours);
|
|
7464
|
-
const totalValue = Math.round(totalHours *
|
|
9059
|
+
const totalValue = Math.round(totalHours * a2.hourly_cost);
|
|
7465
9060
|
const reasons = [];
|
|
7466
9061
|
let level;
|
|
7467
9062
|
if (impact.score === null || impact.score < 60 || graphQuality === "empty") {
|
|
@@ -7499,17 +9094,17 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7499
9094
|
generated_at: now.toISOString(),
|
|
7500
9095
|
project: impact.project,
|
|
7501
9096
|
scope: impact.scope,
|
|
7502
|
-
currency:
|
|
9097
|
+
currency: a2.currency,
|
|
7503
9098
|
disclaimer: SAVINGS_DISCLAIMER,
|
|
7504
9099
|
assumptions_source: source,
|
|
7505
9100
|
assumptions: {
|
|
7506
|
-
hourly_cost:
|
|
7507
|
-
context_preparation_minutes_saved_per_work_item:
|
|
7508
|
-
review_minutes_saved_per_work_item_with_ownership:
|
|
7509
|
-
clarification_minutes_saved_per_ready_work_item:
|
|
7510
|
-
onboarding_hours_saved_per_new_contributor:
|
|
7511
|
-
expected_new_contributors_per_month:
|
|
7512
|
-
architecture_discovery_hours_saved_when_graph_good:
|
|
9101
|
+
hourly_cost: a2.hourly_cost,
|
|
9102
|
+
context_preparation_minutes_saved_per_work_item: a2.context_preparation_minutes_saved_per_work_item,
|
|
9103
|
+
review_minutes_saved_per_work_item_with_ownership: a2.review_minutes_saved_per_work_item_with_ownership,
|
|
9104
|
+
clarification_minutes_saved_per_ready_work_item: a2.clarification_minutes_saved_per_ready_work_item,
|
|
9105
|
+
onboarding_hours_saved_per_new_contributor: a2.onboarding_hours_saved_per_new_contributor,
|
|
9106
|
+
expected_new_contributors_per_month: a2.expected_new_contributors_per_month,
|
|
9107
|
+
architecture_discovery_hours_saved_when_graph_good: a2.architecture_discovery_hours_saved_when_graph_good
|
|
7513
9108
|
},
|
|
7514
9109
|
evidence: {
|
|
7515
9110
|
knowledge_impact_score: impact.score,
|
|
@@ -7525,45 +9120,45 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7525
9120
|
resolved_drift_warnings: guard.resolved
|
|
7526
9121
|
},
|
|
7527
9122
|
estimated_savings: {
|
|
7528
|
-
context_preparation: { hours: ctxPrepH, formula: `${completed} Work Items \xD7 ${
|
|
7529
|
-
review_effort: { hours: reviewH, formula: `${wiWithOwnership} Work Items with ownership \xD7 ${
|
|
7530
|
-
clarification_reduction: { hours: clarH, formula: `${wiWithAcceptance} Work Items with Acceptance Criteria \xD7 ${
|
|
7531
|
-
onboarding: { hours: onboardH, formula: `${
|
|
7532
|
-
architecture_discovery: { hours: archH, formula: `${
|
|
9123
|
+
context_preparation: { hours: ctxPrepH, formula: `${completed} Work Items \xD7 ${a2.context_preparation_minutes_saved_per_work_item} min` },
|
|
9124
|
+
review_effort: { hours: reviewH, formula: `${wiWithOwnership} Work Items with ownership \xD7 ${a2.review_minutes_saved_per_work_item_with_ownership} min` },
|
|
9125
|
+
clarification_reduction: { hours: clarH, formula: `${wiWithAcceptance} Work Items with Acceptance Criteria \xD7 ${a2.clarification_minutes_saved_per_ready_work_item} min` },
|
|
9126
|
+
onboarding: { hours: onboardH, formula: `${a2.expected_new_contributors_per_month} contributor \xD7 ${a2.onboarding_hours_saved_per_new_contributor} h \xD7 ${readinessMult.toFixed(2)} readiness multiplier` },
|
|
9127
|
+
architecture_discovery: { hours: archH, formula: `${a2.architecture_discovery_hours_saved_when_graph_good} h \xD7 ${graphMult.toFixed(2)} graph multiplier` },
|
|
7533
9128
|
drift_prevention: driftSavings
|
|
7534
9129
|
},
|
|
7535
|
-
total: { estimated_hours_saved: totalHours, estimated_value: totalValue, currency:
|
|
9130
|
+
total: { estimated_hours_saved: totalHours, estimated_value: totalValue, currency: a2.currency },
|
|
7536
9131
|
confidence: { level, reasons },
|
|
7537
9132
|
suggested_actions: actions
|
|
7538
9133
|
};
|
|
7539
9134
|
}
|
|
7540
|
-
function renderSavingsMarkdown(
|
|
9135
|
+
function renderSavingsMarkdown(r2) {
|
|
7541
9136
|
const L = [];
|
|
7542
9137
|
L.push("# Kaddo Estimated Savings Report", "");
|
|
7543
|
-
L.push(`Generated at: ${
|
|
7544
|
-
L.push(`Project: ${
|
|
7545
|
-
L.push(`Scope: ${
|
|
7546
|
-
L.push(`Currency: ${
|
|
9138
|
+
L.push(`Generated at: ${r2.generated_at}`);
|
|
9139
|
+
L.push(`Project: ${r2.project}`);
|
|
9140
|
+
L.push(`Scope: ${r2.scope}`);
|
|
9141
|
+
L.push(`Currency: ${r2.currency}`);
|
|
7547
9142
|
L.push("");
|
|
7548
9143
|
L.push("## Disclaimer", "");
|
|
7549
|
-
L.push(
|
|
9144
|
+
L.push(r2.disclaimer, "");
|
|
7550
9145
|
L.push("## Executive Summary", "");
|
|
7551
|
-
L.push(`- Estimated time saved: ${
|
|
7552
|
-
L.push(`- Estimated value: ${
|
|
7553
|
-
L.push(`- Confidence: ${
|
|
7554
|
-
if (
|
|
9146
|
+
L.push(`- Estimated time saved: ${r2.total.estimated_hours_saved} hours`);
|
|
9147
|
+
L.push(`- Estimated value: ${r2.total.estimated_value} ${r2.currency}`);
|
|
9148
|
+
L.push(`- Confidence: ${r2.confidence.level}`);
|
|
9149
|
+
if (r2.assumptions_source === "default") L.push("- Using default assumptions. Run `kaddo savings init` to customize them.");
|
|
7555
9150
|
L.push("");
|
|
7556
9151
|
L.push("## Assumptions", "");
|
|
7557
|
-
L.push(`- Hourly cost: ${
|
|
7558
|
-
L.push(`- Context preparation saved per Work Item: ${
|
|
7559
|
-
L.push(`- Review saved per Work Item with ownership: ${
|
|
7560
|
-
L.push(`- Clarification saved per Work Item with acceptance criteria: ${
|
|
7561
|
-
L.push(`- Onboarding saved per new contributor: ${
|
|
7562
|
-
L.push(`- Expected new contributors per month: ${
|
|
7563
|
-
L.push(`- Architecture discovery saved when graph is good: ${
|
|
9152
|
+
L.push(`- Hourly cost: ${r2.assumptions.hourly_cost} ${r2.currency}`);
|
|
9153
|
+
L.push(`- Context preparation saved per Work Item: ${r2.assumptions.context_preparation_minutes_saved_per_work_item} min`);
|
|
9154
|
+
L.push(`- Review saved per Work Item with ownership: ${r2.assumptions.review_minutes_saved_per_work_item_with_ownership} min`);
|
|
9155
|
+
L.push(`- Clarification saved per Work Item with acceptance criteria: ${r2.assumptions.clarification_minutes_saved_per_ready_work_item} min`);
|
|
9156
|
+
L.push(`- Onboarding saved per new contributor: ${r2.assumptions.onboarding_hours_saved_per_new_contributor} h`);
|
|
9157
|
+
L.push(`- Expected new contributors per month: ${r2.assumptions.expected_new_contributors_per_month}`);
|
|
9158
|
+
L.push(`- Architecture discovery saved when graph is good: ${r2.assumptions.architecture_discovery_hours_saved_when_graph_good} h`);
|
|
7564
9159
|
L.push("");
|
|
7565
9160
|
L.push("## Evidence Used", "");
|
|
7566
|
-
const e =
|
|
9161
|
+
const e = r2.evidence;
|
|
7567
9162
|
L.push(`- Knowledge Impact Score: ${e.knowledge_impact_score ?? "not available"}${e.knowledge_impact_score !== null ? "/100" : ""}`);
|
|
7568
9163
|
L.push(`- Completed Work Items: ${e.completed_work_items}`);
|
|
7569
9164
|
L.push(`- Ownership coverage: ${e.ownership_coverage_percent}%`);
|
|
@@ -7581,11 +9176,11 @@ function renderSavingsMarkdown(r) {
|
|
|
7581
9176
|
}
|
|
7582
9177
|
L.push("");
|
|
7583
9178
|
L.push("## Estimated Savings", "");
|
|
7584
|
-
const s =
|
|
7585
|
-
const line = (title,
|
|
9179
|
+
const s = r2.estimated_savings;
|
|
9180
|
+
const line = (title, l2) => {
|
|
7586
9181
|
L.push(`### ${title}`, "");
|
|
7587
|
-
L.push(`- Formula: ${
|
|
7588
|
-
L.push(`- Estimated: ${
|
|
9182
|
+
L.push(`- Formula: ${l2.formula}`);
|
|
9183
|
+
L.push(`- Estimated: ${l2.hours} h`, "");
|
|
7589
9184
|
};
|
|
7590
9185
|
line("Context Preparation", s.context_preparation);
|
|
7591
9186
|
line("Review Effort", s.review_effort);
|
|
@@ -7603,31 +9198,31 @@ function renderSavingsMarkdown(r) {
|
|
|
7603
9198
|
L.push(`- Reason: ${s.drift_prevention.reason}`, "");
|
|
7604
9199
|
}
|
|
7605
9200
|
L.push("## Total", "");
|
|
7606
|
-
L.push(`- Estimated time saved: ${
|
|
7607
|
-
L.push(`- Estimated value: ${
|
|
9201
|
+
L.push(`- Estimated time saved: ${r2.total.estimated_hours_saved} h`);
|
|
9202
|
+
L.push(`- Estimated value: ${r2.total.estimated_value} ${r2.currency}`);
|
|
7608
9203
|
L.push("");
|
|
7609
9204
|
L.push("## Confidence", "");
|
|
7610
|
-
L.push(`Confidence: ${
|
|
7611
|
-
for (const reason of
|
|
9205
|
+
L.push(`Confidence: ${r2.confidence.level}`, "", "Reason:");
|
|
9206
|
+
for (const reason of r2.confidence.reasons) L.push(`- ${reason}`);
|
|
7612
9207
|
L.push("");
|
|
7613
9208
|
L.push("## Suggested Actions", "");
|
|
7614
|
-
|
|
9209
|
+
r2.suggested_actions.forEach((act, i) => L.push(`${i + 1}. ${act}`));
|
|
7615
9210
|
L.push("");
|
|
7616
9211
|
return L.join("\n");
|
|
7617
9212
|
}
|
|
7618
|
-
function serializeSavingsJson(
|
|
7619
|
-
return JSON.stringify(
|
|
9213
|
+
function serializeSavingsJson(r2) {
|
|
9214
|
+
return JSON.stringify(r2, null, 2) + "\n";
|
|
7620
9215
|
}
|
|
7621
9216
|
|
|
7622
9217
|
// ../cli/src/core/drift-report.ts
|
|
7623
9218
|
function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
7624
|
-
const
|
|
9219
|
+
const h2 = buildGuardHistory(dir);
|
|
7625
9220
|
const project = loadConfig(dir)?.project.name ?? "unknown";
|
|
7626
9221
|
const actions = [];
|
|
7627
|
-
if (!
|
|
9222
|
+
if (!h2.available) {
|
|
7628
9223
|
actions.push("Run `kaddo guard --record` to start recording guard history.");
|
|
7629
9224
|
} else {
|
|
7630
|
-
if (
|
|
9225
|
+
if (h2.open > 0) actions.push("Review open drift warnings and update related Work Items or ownership.");
|
|
7631
9226
|
actions.push("Run `kaddo guard --record` before important commits.");
|
|
7632
9227
|
actions.push("Use this report to calibrate estimated drift-prevention savings.");
|
|
7633
9228
|
}
|
|
@@ -7635,55 +9230,55 @@ function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
7635
9230
|
generated_at: now.toISOString(),
|
|
7636
9231
|
project,
|
|
7637
9232
|
guard_history: {
|
|
7638
|
-
available:
|
|
7639
|
-
total_runs:
|
|
7640
|
-
first_run:
|
|
7641
|
-
last_run:
|
|
7642
|
-
runs_with_warnings:
|
|
7643
|
-
runs_clean:
|
|
9233
|
+
available: h2.available,
|
|
9234
|
+
total_runs: h2.total_runs,
|
|
9235
|
+
first_run: h2.first_run,
|
|
9236
|
+
last_run: h2.last_run,
|
|
9237
|
+
runs_with_warnings: h2.runs_with_warnings,
|
|
9238
|
+
runs_clean: h2.runs_clean
|
|
7644
9239
|
},
|
|
7645
|
-
drift_warnings: { detected:
|
|
7646
|
-
hotspots:
|
|
7647
|
-
trend:
|
|
7648
|
-
threads:
|
|
9240
|
+
drift_warnings: { detected: h2.detected, open: h2.open, resolved: h2.resolved, resolution_rate: h2.resolution_rate },
|
|
9241
|
+
hotspots: h2.hotspots,
|
|
9242
|
+
trend: h2.trend,
|
|
9243
|
+
threads: h2.threads,
|
|
7649
9244
|
suggested_actions: actions
|
|
7650
9245
|
};
|
|
7651
9246
|
}
|
|
7652
|
-
function renderDriftMarkdown(
|
|
9247
|
+
function renderDriftMarkdown(r2) {
|
|
7653
9248
|
const L = [];
|
|
7654
9249
|
L.push("# Kaddo Drift Trend Report", "");
|
|
7655
|
-
L.push(`Generated at: ${
|
|
7656
|
-
L.push(`Project: ${
|
|
9250
|
+
L.push(`Generated at: ${r2.generated_at}`);
|
|
9251
|
+
L.push(`Project: ${r2.project}`);
|
|
7657
9252
|
L.push("");
|
|
7658
|
-
if (!
|
|
9253
|
+
if (!r2.guard_history.available) {
|
|
7659
9254
|
L.push("## Guard History", "");
|
|
7660
9255
|
L.push("No guard history recorded yet.");
|
|
7661
9256
|
L.push("");
|
|
7662
9257
|
L.push("Run `kaddo guard --record` to start recording drift evidence.");
|
|
7663
9258
|
L.push("");
|
|
7664
9259
|
L.push("## Suggested Actions", "");
|
|
7665
|
-
|
|
9260
|
+
r2.suggested_actions.forEach((a2, i) => L.push(`${i + 1}. ${a2}`));
|
|
7666
9261
|
L.push("");
|
|
7667
9262
|
return L.join("\n");
|
|
7668
9263
|
}
|
|
7669
|
-
const
|
|
9264
|
+
const w3 = r2.drift_warnings;
|
|
7670
9265
|
L.push("## Executive Summary", "");
|
|
7671
|
-
L.push(`- Guard runs recorded: ${
|
|
7672
|
-
L.push(`- Drift warnings detected: ${
|
|
7673
|
-
L.push(`- Open warnings: ${
|
|
7674
|
-
L.push(`- Resolved warnings: ${
|
|
7675
|
-
L.push(`- Resolution rate: ${
|
|
7676
|
-
if (
|
|
9266
|
+
L.push(`- Guard runs recorded: ${r2.guard_history.total_runs}`);
|
|
9267
|
+
L.push(`- Drift warnings detected: ${w3.detected}`);
|
|
9268
|
+
L.push(`- Open warnings: ${w3.open}`);
|
|
9269
|
+
L.push(`- Resolved warnings: ${w3.resolved}`);
|
|
9270
|
+
L.push(`- Resolution rate: ${w3.resolution_rate}%`);
|
|
9271
|
+
if (r2.hotspots.length > 0) L.push(`- Most affected area: ${r2.hotspots[0].path}`);
|
|
7677
9272
|
L.push("");
|
|
7678
9273
|
L.push("## Guard History", "");
|
|
7679
|
-
L.push(`- First run: ${
|
|
7680
|
-
L.push(`- Last run: ${
|
|
7681
|
-
L.push(`- Runs with warnings: ${
|
|
7682
|
-
L.push(`- Runs clean: ${
|
|
9274
|
+
L.push(`- First run: ${r2.guard_history.first_run}`);
|
|
9275
|
+
L.push(`- Last run: ${r2.guard_history.last_run}`);
|
|
9276
|
+
L.push(`- Runs with warnings: ${r2.guard_history.runs_with_warnings}/${r2.guard_history.total_runs}`);
|
|
9277
|
+
L.push(`- Runs clean: ${r2.guard_history.runs_clean}/${r2.guard_history.total_runs}`);
|
|
7683
9278
|
L.push("");
|
|
7684
9279
|
L.push("## Drift Warnings", "");
|
|
7685
|
-
const open =
|
|
7686
|
-
const resolved =
|
|
9280
|
+
const open = r2.threads.filter((t) => t.status === "open");
|
|
9281
|
+
const resolved = r2.threads.filter((t) => t.status === "resolved");
|
|
7687
9282
|
L.push("### Open", "");
|
|
7688
9283
|
if (open.length === 0) L.push("_None._", "");
|
|
7689
9284
|
for (const t of open) {
|
|
@@ -7705,28 +9300,28 @@ function renderDriftMarkdown(r) {
|
|
|
7705
9300
|
}
|
|
7706
9301
|
L.push("");
|
|
7707
9302
|
L.push("## Hotspots", "");
|
|
7708
|
-
if (
|
|
7709
|
-
for (const
|
|
9303
|
+
if (r2.hotspots.length === 0) L.push("_None._");
|
|
9304
|
+
for (const h2 of r2.hotspots) L.push(`- ${h2.path}: ${h2.warnings} warning(s)`);
|
|
7710
9305
|
L.push("");
|
|
7711
9306
|
L.push("## Trend", "");
|
|
7712
|
-
L.push(`- Recent direction: ${
|
|
7713
|
-
L.push(`- Reason: ${
|
|
9307
|
+
L.push(`- Recent direction: ${r2.trend.direction}`);
|
|
9308
|
+
L.push(`- Reason: ${r2.trend.reason}`);
|
|
7714
9309
|
L.push("");
|
|
7715
9310
|
L.push("## Suggested Actions", "");
|
|
7716
|
-
|
|
9311
|
+
r2.suggested_actions.forEach((a2, i) => L.push(`${i + 1}. ${a2}`));
|
|
7717
9312
|
L.push("");
|
|
7718
9313
|
return L.join("\n");
|
|
7719
9314
|
}
|
|
7720
|
-
function serializeDriftJson(
|
|
9315
|
+
function serializeDriftJson(r2) {
|
|
7721
9316
|
const out = {
|
|
7722
|
-
generated_at:
|
|
7723
|
-
project:
|
|
7724
|
-
guard_history:
|
|
7725
|
-
drift_warnings:
|
|
7726
|
-
hotspots:
|
|
7727
|
-
trend:
|
|
7728
|
-
threads:
|
|
7729
|
-
suggested_actions:
|
|
9317
|
+
generated_at: r2.generated_at,
|
|
9318
|
+
project: r2.project,
|
|
9319
|
+
guard_history: r2.guard_history,
|
|
9320
|
+
drift_warnings: r2.drift_warnings,
|
|
9321
|
+
hotspots: r2.hotspots,
|
|
9322
|
+
trend: r2.trend,
|
|
9323
|
+
threads: r2.threads,
|
|
9324
|
+
suggested_actions: r2.suggested_actions
|
|
7730
9325
|
};
|
|
7731
9326
|
return JSON.stringify(out, null, 2) + "\n";
|
|
7732
9327
|
}
|
|
@@ -7756,7 +9351,7 @@ function parseSource(data) {
|
|
|
7756
9351
|
}
|
|
7757
9352
|
var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["draft", "ready", "in-progress", "blocked"]);
|
|
7758
9353
|
function strArray(v) {
|
|
7759
|
-
return Array.isArray(v) ? v.map((
|
|
9354
|
+
return Array.isArray(v) ? v.map((x2) => String(x2)).filter(Boolean) : [];
|
|
7760
9355
|
}
|
|
7761
9356
|
function lifecycleOf(data, relPath) {
|
|
7762
9357
|
const status = String(data.status ?? "").trim();
|
|
@@ -7808,7 +9403,7 @@ function listWorkItems(root) {
|
|
|
7808
9403
|
readiness
|
|
7809
9404
|
});
|
|
7810
9405
|
}
|
|
7811
|
-
return items.sort((
|
|
9406
|
+
return items.sort((a2, b2) => a2.id.localeCompare(b2.id));
|
|
7812
9407
|
}
|
|
7813
9408
|
function assessReadiness(data, content, code, domains, source) {
|
|
7814
9409
|
const body = content.trim();
|
|
@@ -7835,12 +9430,12 @@ function assessReadiness(data, content, code, domains, source) {
|
|
|
7835
9430
|
}
|
|
7836
9431
|
|
|
7837
9432
|
// src/resources.ts
|
|
7838
|
-
function
|
|
9433
|
+
function text2(uri, body, mimeType = "text/markdown") {
|
|
7839
9434
|
return [{ uri, text: body, mimeType }];
|
|
7840
9435
|
}
|
|
7841
9436
|
function fileOrHint(root, uri, rel, hint, mimeType = "text/markdown") {
|
|
7842
9437
|
const body = readText(root, rel);
|
|
7843
|
-
return
|
|
9438
|
+
return text2(uri, body ?? hint, body ? mimeType : "text/plain");
|
|
7844
9439
|
}
|
|
7845
9440
|
var RESOURCES = [
|
|
7846
9441
|
{
|
|
@@ -7888,7 +9483,7 @@ var RESOURCES = [
|
|
|
7888
9483
|
const json = readText(root, ".kaddo/graph.json");
|
|
7889
9484
|
const mmd = readText(root, ".kaddo/graph.mmd");
|
|
7890
9485
|
if (!json && !mmd) {
|
|
7891
|
-
return
|
|
9486
|
+
return text2("kaddo://graph", "Knowledge graph not found. Run `kaddo graph export` first.", "text/plain");
|
|
7892
9487
|
}
|
|
7893
9488
|
const parts = [];
|
|
7894
9489
|
if (json) parts.push({ uri: "kaddo://graph", text: json, mimeType: "application/json" });
|
|
@@ -7905,7 +9500,7 @@ var RESOURCES = [
|
|
|
7905
9500
|
const md = readText(root, ".kaddo/graph-hints.md");
|
|
7906
9501
|
const json = readText(root, ".kaddo/graph-hints.json");
|
|
7907
9502
|
if (!md && !json) {
|
|
7908
|
-
return
|
|
9503
|
+
return text2("kaddo://graph-hints", "Graph hints not found. Run `kaddo graph export` first.", "text/plain");
|
|
7909
9504
|
}
|
|
7910
9505
|
const parts = [];
|
|
7911
9506
|
if (md) parts.push({ uri: "kaddo://graph-hints", text: md, mimeType: "text/markdown" });
|
|
@@ -7920,7 +9515,7 @@ var RESOURCES = [
|
|
|
7920
9515
|
mimeType: "application/json",
|
|
7921
9516
|
read: (root) => {
|
|
7922
9517
|
if (!hasKnowledge(root)) {
|
|
7923
|
-
return
|
|
9518
|
+
return text2("kaddo://work-items", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
7924
9519
|
}
|
|
7925
9520
|
return [
|
|
7926
9521
|
{
|
|
@@ -7991,7 +9586,7 @@ var RESOURCES = [
|
|
|
7991
9586
|
const saved = readText(root, ".kaddo/reports/impact-report.md");
|
|
7992
9587
|
if (saved) return [{ uri: "kaddo://impact-report", text: saved, mimeType: "text/markdown" }];
|
|
7993
9588
|
if (!hasKnowledge(root)) {
|
|
7994
|
-
return
|
|
9589
|
+
return text2("kaddo://impact-report", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
7995
9590
|
}
|
|
7996
9591
|
return [{ uri: "kaddo://impact-report", text: renderImpactMarkdown(buildImpactReport(root, { scope: "all", scopeSource: "default" })), mimeType: "text/markdown" }];
|
|
7997
9592
|
}
|
|
@@ -8005,7 +9600,7 @@ var RESOURCES = [
|
|
|
8005
9600
|
const saved = readText(root, ".kaddo/reports/savings-report.md");
|
|
8006
9601
|
if (saved) return [{ uri: "kaddo://savings-report", text: saved, mimeType: "text/markdown" }];
|
|
8007
9602
|
if (!hasKnowledge(root)) {
|
|
8008
|
-
return
|
|
9603
|
+
return text2("kaddo://savings-report", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8009
9604
|
}
|
|
8010
9605
|
return [{ uri: "kaddo://savings-report", text: renderSavingsMarkdown(buildSavingsReport(root, { scope: "all", scopeSource: "default" })), mimeType: "text/markdown" }];
|
|
8011
9606
|
}
|
|
@@ -8029,7 +9624,7 @@ var RESOURCES = [
|
|
|
8029
9624
|
read: (root) => {
|
|
8030
9625
|
const runs = readText(root, ".kaddo/history/guard-runs.jsonl");
|
|
8031
9626
|
if (runs === null) {
|
|
8032
|
-
return
|
|
9627
|
+
return text2("kaddo://guard-history", "No guard history recorded yet. Run `kaddo guard --record`.", "text/plain");
|
|
8033
9628
|
}
|
|
8034
9629
|
return [{ uri: "kaddo://guard-history", text: runs, mimeType: "application/jsonl" }];
|
|
8035
9630
|
}
|
|
@@ -8041,10 +9636,10 @@ var RESOURCES = [
|
|
|
8041
9636
|
mimeType: "application/json",
|
|
8042
9637
|
read: (root) => {
|
|
8043
9638
|
if (!hasKnowledge(root)) {
|
|
8044
|
-
return
|
|
9639
|
+
return text2("kaddo://open-questions", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8045
9640
|
}
|
|
8046
|
-
const
|
|
8047
|
-
return [{ uri: "kaddo://open-questions", text: JSON.stringify({ questions:
|
|
9641
|
+
const r2 = buildOpenQuestionsReport(root);
|
|
9642
|
+
return [{ uri: "kaddo://open-questions", text: JSON.stringify({ questions: r2.questions }, null, 2), mimeType: "application/json" }];
|
|
8048
9643
|
}
|
|
8049
9644
|
},
|
|
8050
9645
|
{
|
|
@@ -8054,7 +9649,7 @@ var RESOURCES = [
|
|
|
8054
9649
|
mimeType: "application/json",
|
|
8055
9650
|
read: (root) => {
|
|
8056
9651
|
if (!hasKnowledge(root)) {
|
|
8057
|
-
return
|
|
9652
|
+
return text2("kaddo://roadmap-readiness", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8058
9653
|
}
|
|
8059
9654
|
return [{ uri: "kaddo://roadmap-readiness", text: JSON.stringify(roadmapReadinessSummary(root), null, 2), mimeType: "application/json" }];
|
|
8060
9655
|
}
|
|
@@ -8066,7 +9661,7 @@ var RESOURCES = [
|
|
|
8066
9661
|
mimeType: "application/json",
|
|
8067
9662
|
read: (root) => {
|
|
8068
9663
|
if (!hasKnowledge(root)) {
|
|
8069
|
-
return
|
|
9664
|
+
return text2("kaddo://tech-decisions", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8070
9665
|
}
|
|
8071
9666
|
return [{ uri: "kaddo://tech-decisions", text: JSON.stringify(buildTechDecisions(root), null, 2), mimeType: "application/json" }];
|
|
8072
9667
|
}
|
|
@@ -8078,7 +9673,7 @@ var RESOURCES = [
|
|
|
8078
9673
|
mimeType: "application/json",
|
|
8079
9674
|
read: (root) => {
|
|
8080
9675
|
if (!hasKnowledge(root)) {
|
|
8081
|
-
return
|
|
9676
|
+
return text2("kaddo://installed-assets", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8082
9677
|
}
|
|
8083
9678
|
return [{ uri: "kaddo://installed-assets", text: JSON.stringify(installedAssetsSummary(root), null, 2), mimeType: "application/json" }];
|
|
8084
9679
|
}
|
|
@@ -8090,7 +9685,7 @@ var RESOURCES = [
|
|
|
8090
9685
|
mimeType: "application/json",
|
|
8091
9686
|
read: (root) => {
|
|
8092
9687
|
if (!hasKnowledge(root)) {
|
|
8093
|
-
return
|
|
9688
|
+
return text2("kaddo://roadmap-quality", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8094
9689
|
}
|
|
8095
9690
|
return [{ uri: "kaddo://roadmap-quality", text: JSON.stringify(buildRoadmapQuality(root), null, 2), mimeType: "application/json" }];
|
|
8096
9691
|
}
|
|
@@ -8102,7 +9697,7 @@ var RESOURCES = [
|
|
|
8102
9697
|
mimeType: "application/json",
|
|
8103
9698
|
read: (root) => {
|
|
8104
9699
|
if (!hasKnowledge(root)) {
|
|
8105
|
-
return
|
|
9700
|
+
return text2("kaddo://work-item-candidates", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8106
9701
|
}
|
|
8107
9702
|
const md = readText(root, "knowledge/delivery/roadmap.md");
|
|
8108
9703
|
const candidates = md ? parseRoadmapCandidates(md) : [];
|
|
@@ -8116,7 +9711,7 @@ var RESOURCES = [
|
|
|
8116
9711
|
mimeType: "application/json",
|
|
8117
9712
|
read: (root) => {
|
|
8118
9713
|
if (!hasKnowledge(root)) {
|
|
8119
|
-
return
|
|
9714
|
+
return text2("kaddo://next-step", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8120
9715
|
}
|
|
8121
9716
|
const nextStepRecommendation = resolveNextStep(root);
|
|
8122
9717
|
const deliveryState = { ...buildDeliveryState(root), phase: nextStepRecommendation.phase };
|
|
@@ -8130,7 +9725,7 @@ var RESOURCES = [
|
|
|
8130
9725
|
mimeType: "application/json",
|
|
8131
9726
|
read: (root) => {
|
|
8132
9727
|
if (!hasKnowledge(root)) {
|
|
8133
|
-
return
|
|
9728
|
+
return text2("kaddo://project-route", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8134
9729
|
}
|
|
8135
9730
|
return [{ uri: "kaddo://project-route", text: JSON.stringify(buildProjectRoute(root), null, 2), mimeType: "application/json" }];
|
|
8136
9731
|
}
|
|
@@ -8151,7 +9746,7 @@ var RESOURCES = [
|
|
|
8151
9746
|
} catch {
|
|
8152
9747
|
}
|
|
8153
9748
|
}
|
|
8154
|
-
return
|
|
9749
|
+
return text2("kaddo://scan-signals", "Scan signals not found. Run `kaddo scan` first.", "text/plain");
|
|
8155
9750
|
}
|
|
8156
9751
|
}
|
|
8157
9752
|
];
|
|
@@ -8168,11 +9763,11 @@ function recommendedInputs(name) {
|
|
|
8168
9763
|
return [".kaddo/context-pack.md", ...EXTRA_INPUTS[name] ?? []];
|
|
8169
9764
|
}
|
|
8170
9765
|
function listPrompts(root) {
|
|
8171
|
-
return listAgents(root).map((
|
|
8172
|
-
name:
|
|
8173
|
-
description:
|
|
9766
|
+
return listAgents(root).map((a2) => ({
|
|
9767
|
+
name: a2.name,
|
|
9768
|
+
description: a2.description || `Kaddo ${a2.name}`,
|
|
8174
9769
|
content: "",
|
|
8175
|
-
recommended_inputs: recommendedInputs(
|
|
9770
|
+
recommended_inputs: recommendedInputs(a2.name)
|
|
8176
9771
|
}));
|
|
8177
9772
|
}
|
|
8178
9773
|
function getPrompt(root, name) {
|
|
@@ -8197,7 +9792,7 @@ function projectStatus(root) {
|
|
|
8197
9792
|
if (!explain) {
|
|
8198
9793
|
return fail("Project status needs `.kaddo/explain.json`. Run `kaddo explain` first.");
|
|
8199
9794
|
}
|
|
8200
|
-
const maturity = (explain.layers ?? []).map((
|
|
9795
|
+
const maturity = (explain.layers ?? []).map((l2) => `${l2.layer}: ${l2.status}`);
|
|
8201
9796
|
return ok({
|
|
8202
9797
|
project: explain.project?.name ?? "unknown",
|
|
8203
9798
|
state: explain.project?.state ?? "unknown",
|
|
@@ -8222,19 +9817,19 @@ function projectStatus(root) {
|
|
|
8222
9817
|
}
|
|
8223
9818
|
function listWorkItemsTool(root, filter = {}) {
|
|
8224
9819
|
let items = listWorkItems(root);
|
|
8225
|
-
if (filter.status) items = items.filter((
|
|
8226
|
-
if (filter.type) items = items.filter((
|
|
8227
|
-
if (filter.knowledge_level) items = items.filter((
|
|
9820
|
+
if (filter.status) items = items.filter((w3) => w3.status === filter.status);
|
|
9821
|
+
if (filter.type) items = items.filter((w3) => w3.type === filter.type);
|
|
9822
|
+
if (filter.knowledge_level) items = items.filter((w3) => w3.knowledge_level === filter.knowledge_level);
|
|
8228
9823
|
return ok(items);
|
|
8229
9824
|
}
|
|
8230
9825
|
function getWorkItem(root, id) {
|
|
8231
|
-
const item = listWorkItems(root).find((
|
|
9826
|
+
const item = listWorkItems(root).find((w3) => w3.id === id);
|
|
8232
9827
|
if (!item) return fail(`Work Item "${id}" not found.`);
|
|
8233
9828
|
const content = readText(root, item.path);
|
|
8234
9829
|
return ok({ ...item, content: content ?? "" });
|
|
8235
9830
|
}
|
|
8236
9831
|
function markWorkItemReady(root, id, confirm) {
|
|
8237
|
-
const item = listWorkItems(root).find((
|
|
9832
|
+
const item = listWorkItems(root).find((w3) => w3.id === id);
|
|
8238
9833
|
if (!item) return fail(`Work Item "${id}" not found.`);
|
|
8239
9834
|
if (item.status === "ready") {
|
|
8240
9835
|
return ok({ status: "already_ready", id: item.id, message: `Work Item ${item.id} is already ready.` });
|
|
@@ -8317,9 +9912,9 @@ function listGraphHints(root, filter = {}) {
|
|
|
8317
9912
|
const report = readJson(root, ".kaddo/graph-hints.json");
|
|
8318
9913
|
if (!report) return fail("Graph hints not found. Run `kaddo graph export` first.");
|
|
8319
9914
|
let hints = Array.isArray(report.hints) ? report.hints : [];
|
|
8320
|
-
if (filter.artifact_type) hints = hints.filter((
|
|
8321
|
-
if (filter.severity) hints = hints.filter((
|
|
8322
|
-
if (filter.active_only) hints = hints.filter((
|
|
9915
|
+
if (filter.artifact_type) hints = hints.filter((h2) => h2.artifact_type === filter.artifact_type);
|
|
9916
|
+
if (filter.severity) hints = hints.filter((h2) => h2.severity === filter.severity);
|
|
9917
|
+
if (filter.active_only) hints = hints.filter((h2) => h2.artifact_type === "work-item");
|
|
8323
9918
|
return ok({
|
|
8324
9919
|
scope: report.scope ?? "active",
|
|
8325
9920
|
scope_reason: report.scope_reason ?? "",
|
|
@@ -8380,23 +9975,23 @@ var OPERATING_RULES = [
|
|
|
8380
9975
|
"After significant changes run `kaddo scan`, `kaddo owners suggest` and `kaddo guard`, and update the affected knowledge (ADR / capabilities / current-state).",
|
|
8381
9976
|
"Kaddo itself never calls an LLM and never runs git \u2014 every git action is the human\u2019s."
|
|
8382
9977
|
];
|
|
8383
|
-
function toContextWorkItem(
|
|
9978
|
+
function toContextWorkItem(a2) {
|
|
8384
9979
|
return {
|
|
8385
|
-
id:
|
|
8386
|
-
type:
|
|
8387
|
-
title:
|
|
8388
|
-
status:
|
|
8389
|
-
lifecycle: lifecycleStateOf({ status:
|
|
8390
|
-
knowledgeLevel:
|
|
8391
|
-
domains:
|
|
8392
|
-
source: parseWorkItemSource(
|
|
9980
|
+
id: a2.id,
|
|
9981
|
+
type: a2.type,
|
|
9982
|
+
title: a2.title,
|
|
9983
|
+
status: a2.status,
|
|
9984
|
+
lifecycle: lifecycleStateOf({ status: a2.status, filePath: a2.filePath }),
|
|
9985
|
+
knowledgeLevel: a2.knowledgeLevel,
|
|
9986
|
+
domains: a2.domains,
|
|
9987
|
+
source: parseWorkItemSource(a2.rawFrontmatter)
|
|
8393
9988
|
};
|
|
8394
9989
|
}
|
|
8395
|
-
function toContextArtifact(
|
|
8396
|
-
return { id:
|
|
9990
|
+
function toContextArtifact(a2) {
|
|
9991
|
+
return { id: a2.id, type: a2.type, title: a2.title, summary: a2.summary, codeGlobs: a2.codeGlobs };
|
|
8397
9992
|
}
|
|
8398
|
-
function isDeliveryWorkItem(
|
|
8399
|
-
return
|
|
9993
|
+
function isDeliveryWorkItem(a2) {
|
|
9994
|
+
return a2.filePath.replace(/\\/g, "/").includes("/delivery/work-items/") && Boolean(a2.type);
|
|
8400
9995
|
}
|
|
8401
9996
|
function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
8402
9997
|
const missing = [];
|
|
@@ -8419,7 +10014,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8419
10014
|
}
|
|
8420
10015
|
const allArtifacts = discoverKnowledge(dir);
|
|
8421
10016
|
const workItems = allArtifacts.filter(
|
|
8422
|
-
(
|
|
10017
|
+
(a2) => isDeliveryWorkItem(a2) && isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
|
|
8423
10018
|
);
|
|
8424
10019
|
if (workItems.length === 0) {
|
|
8425
10020
|
missing.push("No work items found.");
|
|
@@ -8427,15 +10022,15 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8427
10022
|
const state = config.project.state;
|
|
8428
10023
|
const roadmapPath = join(dir, ARCH_DIR3, "delivery", "roadmap.md");
|
|
8429
10024
|
const materialized = allArtifacts.filter(
|
|
8430
|
-
(
|
|
10025
|
+
(a2) => a2.filePath.replace(/\\/g, "/").includes("/delivery/work-items/") && Boolean(a2.type)
|
|
8431
10026
|
).length;
|
|
8432
10027
|
const roadmap = roadmapStats(exists(roadmapPath) ? readFile(roadmapPath) : null, materialized);
|
|
8433
10028
|
const deliveryMix = {};
|
|
8434
|
-
for (const
|
|
8435
|
-
const p =
|
|
8436
|
-
if (!
|
|
8437
|
-
if (!isActiveState(lifecycleStateOf({ status:
|
|
8438
|
-
deliveryMix[
|
|
10029
|
+
for (const a2 of allArtifacts) {
|
|
10030
|
+
const p = a2.filePath.replace(/\\/g, "/");
|
|
10031
|
+
if (!a2.type || !p.includes("/delivery/work-items/")) continue;
|
|
10032
|
+
if (!isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))) continue;
|
|
10033
|
+
deliveryMix[a2.type] = (deliveryMix[a2.type] ?? 0) + 1;
|
|
8439
10034
|
}
|
|
8440
10035
|
const mappedModules = loadMappedModules(dir);
|
|
8441
10036
|
const layers = knowledgeLayers(dir);
|
|
@@ -8446,7 +10041,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8446
10041
|
const qCodebase = qa("knowledge/tech/codebase.md");
|
|
8447
10042
|
const qCurrentState = qa("knowledge/tech/current-state.md");
|
|
8448
10043
|
const qRoadmap = qa("knowledge/delivery/roadmap.md");
|
|
8449
|
-
const layerStatusOf = (name) => layers.find((
|
|
10044
|
+
const layerStatusOf = (name) => layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
8450
10045
|
const knowledgeQuality = {
|
|
8451
10046
|
business: { status: layerStatusOf("Business"), artifacts: { "knowledge/business/business.md": qBusiness } },
|
|
8452
10047
|
product: { status: layerStatusOf("Product"), artifacts: { "knowledge/product/product.md": qProduct, "knowledge/product/capabilities.md": qCapabilities } },
|
|
@@ -8457,20 +10052,20 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8457
10052
|
if (qProduct === "placeholder" || qCapabilities === "placeholder") missing.push("Product capabilities exist but still look like a bootstrap placeholder.");
|
|
8458
10053
|
if (qCurrentState === "placeholder") missing.push("Current state exists but still looks like a bootstrap placeholder.");
|
|
8459
10054
|
if (qCodebase === "placeholder") missing.push("Codebase map exists but still looks like a bootstrap placeholder.");
|
|
8460
|
-
const allWorkItems = allArtifacts.filter((
|
|
8461
|
-
const wiWithOwnership = allWorkItems.filter((
|
|
10055
|
+
const allWorkItems = allArtifacts.filter((a2) => a2.isWorkItem);
|
|
10056
|
+
const wiWithOwnership = allWorkItems.filter((a2) => a2.codeGlobs.length > 0).length;
|
|
8462
10057
|
const phase = assessPhase({
|
|
8463
10058
|
layers,
|
|
8464
10059
|
roadmap,
|
|
8465
10060
|
workItems: {
|
|
8466
10061
|
total: allWorkItems.length,
|
|
8467
10062
|
byState: lifecycleCounts(
|
|
8468
|
-
allWorkItems.map((
|
|
10063
|
+
allWorkItems.map((a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
|
|
8469
10064
|
),
|
|
8470
|
-
items: allWorkItems.map((
|
|
8471
|
-
id:
|
|
8472
|
-
title:
|
|
8473
|
-
lifecycle: lifecycleStateOf({ status:
|
|
10065
|
+
items: allWorkItems.map((a2) => ({
|
|
10066
|
+
id: a2.id || a2.title,
|
|
10067
|
+
title: a2.title,
|
|
10068
|
+
lifecycle: lifecycleStateOf({ status: a2.status, filePath: a2.filePath })
|
|
8474
10069
|
}))
|
|
8475
10070
|
},
|
|
8476
10071
|
ownership: {
|
|
@@ -8535,7 +10130,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8535
10130
|
roadmapSummary,
|
|
8536
10131
|
inventoryAvailable,
|
|
8537
10132
|
workItems: workItems.map(toContextWorkItem),
|
|
8538
|
-
artifacts: allArtifacts.filter((
|
|
10133
|
+
artifacts: allArtifacts.filter((a2) => a2.codeGlobs.length > 0).map(toContextArtifact)
|
|
8539
10134
|
},
|
|
8540
10135
|
layers,
|
|
8541
10136
|
knowledgeQuality,
|
|
@@ -8548,7 +10143,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8548
10143
|
roadmapQuality: buildRoadmapQuality(dir),
|
|
8549
10144
|
installedAssets: (() => {
|
|
8550
10145
|
const s = installedAssetsSummary(dir);
|
|
8551
|
-
const compact = (
|
|
10146
|
+
const compact = (a2) => ({ total: a2.total, installed: a2.total - a2.missing, outdated: a2.outdated, unknown_version: a2.unknown_version, modified: a2.modified });
|
|
8552
10147
|
return { version: s.version, agents: compact(s.agents), skills: compact(s.skills) };
|
|
8553
10148
|
})(),
|
|
8554
10149
|
deliveryMix,
|
|
@@ -8560,6 +10155,31 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8560
10155
|
projectRoute: buildProjectRoute(dir),
|
|
8561
10156
|
metadataHealth: analyzeMetadataHealth(dir),
|
|
8562
10157
|
mappedModules,
|
|
10158
|
+
moduleStatuses: (() => {
|
|
10159
|
+
const statuses = {};
|
|
10160
|
+
for (const m2 of mappedModules) {
|
|
10161
|
+
if (m2.repoPath) statuses[m2.id] = detectModuleStatus(dir, m2.repoPath);
|
|
10162
|
+
}
|
|
10163
|
+
return statuses;
|
|
10164
|
+
})(),
|
|
10165
|
+
affectedModuleContexts: (() => {
|
|
10166
|
+
const contexts = {};
|
|
10167
|
+
const activeWIs = allArtifacts.filter(
|
|
10168
|
+
(a2) => a2.filePath.replace(/\\/g, "/").includes("/delivery/work-items/") && isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
|
|
10169
|
+
);
|
|
10170
|
+
const affectedIds = /* @__PURE__ */ new Set();
|
|
10171
|
+
for (const wi of activeWIs) {
|
|
10172
|
+
const am = wi.rawFrontmatter?.affected_modules;
|
|
10173
|
+
if (Array.isArray(am)) am.forEach((id) => affectedIds.add(String(id)));
|
|
10174
|
+
}
|
|
10175
|
+
for (const id of affectedIds) {
|
|
10176
|
+
const mod = mappedModules.find((m2) => m2.id === id);
|
|
10177
|
+
if (!mod?.repoPath) continue;
|
|
10178
|
+
const ctx = readModuleContext(dir, mod.repoPath);
|
|
10179
|
+
if (ctx) contexts[id] = ctx;
|
|
10180
|
+
}
|
|
10181
|
+
return contexts;
|
|
10182
|
+
})(),
|
|
8563
10183
|
missing,
|
|
8564
10184
|
// VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
|
|
8565
10185
|
// the Current Phase block above it.
|
|
@@ -8584,7 +10204,7 @@ function renderContextPack(pack) {
|
|
|
8584
10204
|
"> Generated by `kaddo context`. Deterministic CLI output \u2014 not an interpretation of the system.\n"
|
|
8585
10205
|
);
|
|
8586
10206
|
parts.push("## Operating Rules (read first)\n");
|
|
8587
|
-
parts.push(handoff.operatingRules.map((
|
|
10207
|
+
parts.push(handoff.operatingRules.map((r2) => `- ${r2}`).join("\n") + "\n");
|
|
8588
10208
|
parts.push("## Project Metadata\n");
|
|
8589
10209
|
parts.push(
|
|
8590
10210
|
[
|
|
@@ -8600,7 +10220,7 @@ function renderContextPack(pack) {
|
|
|
8600
10220
|
`);
|
|
8601
10221
|
if (pack.phase.reasons.length > 0) {
|
|
8602
10222
|
parts.push("Reason:\n");
|
|
8603
|
-
parts.push(pack.phase.reasons.map((
|
|
10223
|
+
parts.push(pack.phase.reasons.map((r2) => `- ${r2}`).join("\n") + "\n");
|
|
8604
10224
|
}
|
|
8605
10225
|
if (pack.phase.recommendedAgents.length > 0) {
|
|
8606
10226
|
parts.push(`Recommended next: ${pack.phase.recommendedAgents.join(", ")}
|
|
@@ -8641,7 +10261,7 @@ function renderContextPack(pack) {
|
|
|
8641
10261
|
parts.push(
|
|
8642
10262
|
"Project knowledge is organized in four layers: **Business \u2192 Product \u2192 Tech \u2192 Delivery**.\n"
|
|
8643
10263
|
);
|
|
8644
|
-
const maturity = pack.layers.map((
|
|
10264
|
+
const maturity = pack.layers.map((l2) => `${l2.layer}: ${l2.status}`).join(" \xB7 ");
|
|
8645
10265
|
parts.push(`Knowledge maturity \u2014 ${maturity}
|
|
8646
10266
|
`);
|
|
8647
10267
|
parts.push(renderLayersMarkdown(pack.layers) + "\n");
|
|
@@ -8654,19 +10274,19 @@ function renderContextPack(pack) {
|
|
|
8654
10274
|
];
|
|
8655
10275
|
if (scan.sourceDirectories.length > 0) {
|
|
8656
10276
|
lines.push("- Source directories:");
|
|
8657
|
-
scan.sourceDirectories.forEach((
|
|
10277
|
+
scan.sourceDirectories.forEach((d3) => lines.push(` - ${d3}`));
|
|
8658
10278
|
}
|
|
8659
10279
|
if (scan.migrationDirectories.length > 0) {
|
|
8660
10280
|
lines.push("- Migration directories:");
|
|
8661
|
-
scan.migrationDirectories.forEach((
|
|
10281
|
+
scan.migrationDirectories.forEach((d3) => lines.push(` - ${d3}`));
|
|
8662
10282
|
}
|
|
8663
10283
|
if (scan.contractFiles.length > 0) {
|
|
8664
10284
|
lines.push("- Contracts:");
|
|
8665
|
-
scan.contractFiles.forEach((
|
|
10285
|
+
scan.contractFiles.forEach((f3) => lines.push(` - ${f3}`));
|
|
8666
10286
|
}
|
|
8667
10287
|
if (scan.infrastructureFiles.length > 0) {
|
|
8668
10288
|
lines.push("- Infrastructure:");
|
|
8669
|
-
scan.infrastructureFiles.forEach((
|
|
10289
|
+
scan.infrastructureFiles.forEach((f3) => lines.push(` - ${f3}`));
|
|
8670
10290
|
}
|
|
8671
10291
|
parts.push(lines.join("\n") + "\n");
|
|
8672
10292
|
} else {
|
|
@@ -8744,7 +10364,7 @@ function renderContextPack(pack) {
|
|
|
8744
10364
|
} else {
|
|
8745
10365
|
parts.push("No active work items found.\n");
|
|
8746
10366
|
}
|
|
8747
|
-
const mixEntries = Object.entries(pack.deliveryMix).sort((
|
|
10367
|
+
const mixEntries = Object.entries(pack.deliveryMix).sort((a2, b2) => b2[1] - a2[1]);
|
|
8748
10368
|
if (mixEntries.length > 0) {
|
|
8749
10369
|
parts.push("## Delivery Mix\n");
|
|
8750
10370
|
parts.push("Active Work Items by type:\n");
|
|
@@ -8757,7 +10377,7 @@ function renderContextPack(pack) {
|
|
|
8757
10377
|
parts.push("## Artifacts and Ownership\n");
|
|
8758
10378
|
if (knowledge.artifacts.length > 0) {
|
|
8759
10379
|
const lines = knowledge.artifacts.map(
|
|
8760
|
-
(
|
|
10380
|
+
(a2) => `- ${a2.id || a2.title} [${a2.type}] owns: ${a2.codeGlobs.join(", ")}`
|
|
8761
10381
|
);
|
|
8762
10382
|
parts.push(lines.join("\n") + "\n");
|
|
8763
10383
|
} else {
|
|
@@ -8768,15 +10388,35 @@ function renderContextPack(pack) {
|
|
|
8768
10388
|
parts.push("This project has mapped modules registered in `.kaddo/modules.yml`.\n");
|
|
8769
10389
|
const header = "| Module | Type | Repo path | Owner | Capabilities | Artifacts |";
|
|
8770
10390
|
const sep = "|---|---|---|---|---|---|";
|
|
8771
|
-
const rows = pack.mappedModules.map((
|
|
8772
|
-
const caps =
|
|
8773
|
-
const arts = presentArtifacts(
|
|
8774
|
-
return `| ${
|
|
10391
|
+
const rows = pack.mappedModules.map((m2) => {
|
|
10392
|
+
const caps = m2.capabilities.length > 0 ? m2.capabilities.join(", ") : "\u2014";
|
|
10393
|
+
const arts = presentArtifacts(m2.artifacts);
|
|
10394
|
+
return `| ${m2.id} | ${m2.type ?? "\u2014"} | ${m2.repoPath || "\u2014"} | ${m2.owner ?? "\u2014"} | ${caps} | ${arts.length > 0 ? arts.join(", ") : "none"} |`;
|
|
8775
10395
|
});
|
|
8776
10396
|
parts.push([header, sep, ...rows].join("\n") + "\n");
|
|
8777
10397
|
parts.push(
|
|
8778
10398
|
"Note: Kaddo does not scan secondary repositories during `context`. Mapped modules come from `.kaddo/modules.yml` and module artifacts only.\n"
|
|
8779
10399
|
);
|
|
10400
|
+
const statuses = pack.moduleStatuses ?? {};
|
|
10401
|
+
const warnings = Object.entries(statuses).filter(([, s]) => s.warning);
|
|
10402
|
+
if (warnings.length > 0) {
|
|
10403
|
+
parts.push("### Module Warnings\n");
|
|
10404
|
+
for (const [id, s] of warnings) {
|
|
10405
|
+
parts.push(`- **${id}** (${s.status}): ${s.warning}
|
|
10406
|
+
`);
|
|
10407
|
+
}
|
|
10408
|
+
}
|
|
10409
|
+
}
|
|
10410
|
+
const affectedCtx = pack.affectedModuleContexts ?? {};
|
|
10411
|
+
const affectedIds = Object.keys(affectedCtx);
|
|
10412
|
+
if (affectedIds.length > 0) {
|
|
10413
|
+
parts.push("## Affected Module Contexts\n");
|
|
10414
|
+
parts.push("The following module contexts are included because active Work Items reference them via `affected_modules`.\n");
|
|
10415
|
+
for (const id of affectedIds) {
|
|
10416
|
+
parts.push(`### Module: ${id}
|
|
10417
|
+
`);
|
|
10418
|
+
parts.push(affectedCtx[id] + "\n");
|
|
10419
|
+
}
|
|
8780
10420
|
}
|
|
8781
10421
|
if (pack.external.length > 0) {
|
|
8782
10422
|
parts.push("## External Knowledge\n");
|
|
@@ -8818,7 +10458,7 @@ function renderContextPack(pack) {
|
|
|
8818
10458
|
].join("\n") + "\n"
|
|
8819
10459
|
);
|
|
8820
10460
|
const shown = pack.graphHints.messages.slice(0, 3);
|
|
8821
|
-
parts.push(shown.map((
|
|
10461
|
+
parts.push(shown.map((m2) => `- ${m2}`).join("\n") + "\n");
|
|
8822
10462
|
if (pack.graphHints.totalHints > shown.length) {
|
|
8823
10463
|
parts.push(`(+${pack.graphHints.totalHints - shown.length} more in \`.kaddo/graph-hints.md\`)
|
|
8824
10464
|
`);
|
|
@@ -8839,18 +10479,18 @@ function renderContextPack(pack) {
|
|
|
8839
10479
|
...!pack.knowledgeQuality.product || pack.knowledgeQuality.product.status === "Missing" ? ["- Missing product knowledge."] : []
|
|
8840
10480
|
];
|
|
8841
10481
|
if (missing.length > 0) {
|
|
8842
|
-
baselineMissing.push(...missing.filter((
|
|
10482
|
+
baselineMissing.push(...missing.filter((m2) => !baselineMissing.some((b2) => b2.includes(m2))));
|
|
8843
10483
|
}
|
|
8844
10484
|
parts.push(baselineMissing.join("\n") + "\n");
|
|
8845
10485
|
} else if (missing.length > 0) {
|
|
8846
|
-
parts.push(missing.map((
|
|
10486
|
+
parts.push(missing.map((m2) => `- ${m2}`).join("\n") + "\n");
|
|
8847
10487
|
} else {
|
|
8848
10488
|
parts.push("_None \u2014 all expected context is present._\n");
|
|
8849
10489
|
}
|
|
8850
10490
|
if (pack.metadataHealth.findings.length > 0) {
|
|
8851
10491
|
parts.push("\n### Metadata Health\n");
|
|
8852
|
-
for (const
|
|
8853
|
-
parts.push(`- \`${
|
|
10492
|
+
for (const f3 of pack.metadataHealth.findings) {
|
|
10493
|
+
parts.push(`- \`${f3.file}\`: ${f3.detail}
|
|
8854
10494
|
`);
|
|
8855
10495
|
}
|
|
8856
10496
|
}
|
|
@@ -8874,7 +10514,7 @@ function renderContextPack(pack) {
|
|
|
8874
10514
|
parts.push(`Agent prompt: \`${rec.agentPath}\`
|
|
8875
10515
|
`);
|
|
8876
10516
|
}
|
|
8877
|
-
parts.push(handoff.recommendedAgents.map((
|
|
10517
|
+
parts.push(handoff.recommendedAgents.map((a2, i) => `${i + 1}. ${a2}`).join("\n") + "\n");
|
|
8878
10518
|
if (handoff.nextSteps.length > 0) {
|
|
8879
10519
|
parts.push("Next step:\n");
|
|
8880
10520
|
parts.push(handoff.nextSteps.map((s) => `- ${s}`).join("\n") + "\n");
|
|
@@ -9018,7 +10658,7 @@ function renderUnderstand(plan) {
|
|
|
9018
10658
|
}
|
|
9019
10659
|
}
|
|
9020
10660
|
if (flowSteps.length > 0) {
|
|
9021
|
-
parts.push(flowSteps.map((
|
|
10661
|
+
parts.push(flowSteps.map((f3, i) => `${i + 1}. ${f3}`).join("\n") + "\n");
|
|
9022
10662
|
}
|
|
9023
10663
|
}
|
|
9024
10664
|
if (rec) {
|
|
@@ -9037,10 +10677,10 @@ function renderUnderstand(plan) {
|
|
|
9037
10677
|
if (plan.activeWorkItems && plan.activeWorkItems.length > 0) {
|
|
9038
10678
|
parts.push("## Active Work Items\n");
|
|
9039
10679
|
parts.push(
|
|
9040
|
-
plan.activeWorkItems.map((
|
|
9041
|
-
const src =
|
|
9042
|
-
- Source: ${
|
|
9043
|
-
return `- ${
|
|
10680
|
+
plan.activeWorkItems.map((w3) => {
|
|
10681
|
+
const src = w3.source && w3.source.type !== "unknown" ? `
|
|
10682
|
+
- Source: ${w3.source.type}${w3.source.id ? ` \xB7 ${w3.source.id}` : ""}` : "";
|
|
10683
|
+
return `- ${w3.id} [${w3.type}] ${w3.lifecycle} \u2014 ${w3.title}${src}`;
|
|
9044
10684
|
}).join("\n") + "\n"
|
|
9045
10685
|
);
|
|
9046
10686
|
}
|
|
@@ -9090,11 +10730,13 @@ function renderUnderstand(plan) {
|
|
|
9090
10730
|
outputs.push("- Refined Work Item content.");
|
|
9091
10731
|
if (rec.id === "create-work-item")
|
|
9092
10732
|
outputs.push("- A new Work Item under `knowledge/delivery/work-items/`.");
|
|
9093
|
-
if (rec.id === "implement")
|
|
10733
|
+
if (rec.id === "implement" || rec.id === "implement-work-item")
|
|
9094
10734
|
outputs.push("- Implementation plan or code changes guided by the Work Item.");
|
|
10735
|
+
if (rec.id === "refine-module-context")
|
|
10736
|
+
outputs.push("- A refined `knowledge/module/module-context.md` with real, project-specific content.");
|
|
9095
10737
|
if (rec.id === "guard")
|
|
9096
10738
|
outputs.push("- Updated knowledge artifacts reflecting recent code changes.");
|
|
9097
|
-
if (rec.id === "install-adapter")
|
|
10739
|
+
if (rec.id === "install-adapter" || rec.id === "prepare-implementation")
|
|
9098
10740
|
outputs.push("- An adapter configured and injected (`kaddo adapters list`).");
|
|
9099
10741
|
if (outputs.length > 0) {
|
|
9100
10742
|
parts.push("The LLM should produce:\n");
|
|
@@ -9161,10 +10803,23 @@ function renderUnderstand(plan) {
|
|
|
9161
10803
|
} else {
|
|
9162
10804
|
parts.push("Re-run `kaddo understand` any time to see this plan again.\n");
|
|
9163
10805
|
}
|
|
10806
|
+
const moduledWIs = (plan.activeWorkItems ?? []).filter((w3) => w3.affectedModules && w3.affectedModules.length > 0);
|
|
10807
|
+
if (moduledWIs.length > 0) {
|
|
10808
|
+
parts.push("## Branch Strategy\n");
|
|
10809
|
+
for (const w3 of moduledWIs) {
|
|
10810
|
+
const branch = `${w3.id.toLowerCase()}/${w3.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40)}`;
|
|
10811
|
+
parts.push(`**${w3.id}** affects: ${w3.affectedModules.join(", ")}
|
|
10812
|
+
`);
|
|
10813
|
+
for (const mod of w3.affectedModules) {
|
|
10814
|
+
parts.push(`- \`${mod}\`: branch \`${branch}\``);
|
|
10815
|
+
}
|
|
10816
|
+
parts.push("");
|
|
10817
|
+
}
|
|
10818
|
+
}
|
|
9164
10819
|
if (plan.metadataHealth && plan.metadataHealth.findings.length > 0) {
|
|
9165
10820
|
parts.push("## Metadata Health\n");
|
|
9166
|
-
for (const
|
|
9167
|
-
parts.push(`- \`${
|
|
10821
|
+
for (const f3 of plan.metadataHealth.findings) {
|
|
10822
|
+
parts.push(`- \`${f3.file}\`: ${f3.detail}
|
|
9168
10823
|
`);
|
|
9169
10824
|
}
|
|
9170
10825
|
}
|
|
@@ -9340,8 +10995,8 @@ function toolText(result) {
|
|
|
9340
10995
|
if (!result.ok) {
|
|
9341
10996
|
return { content: [{ type: "text", text: result.message }], isError: true };
|
|
9342
10997
|
}
|
|
9343
|
-
const
|
|
9344
|
-
return { content: [{ type: "text", text:
|
|
10998
|
+
const text3 = typeof result.data === "string" ? result.data : JSON.stringify(result.data, null, 2);
|
|
10999
|
+
return { content: [{ type: "text", text: text3 }] };
|
|
9345
11000
|
}
|
|
9346
11001
|
function guarded(root, fn) {
|
|
9347
11002
|
try {
|
|
@@ -9365,11 +11020,11 @@ function generated(root, label, fn) {
|
|
|
9365
11020
|
var DERIVED_NOTE = "Writes only derived files under .kaddo/. Does not modify knowledge, source code, external context or git.";
|
|
9366
11021
|
function createServer(root) {
|
|
9367
11022
|
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
9368
|
-
for (const
|
|
11023
|
+
for (const r2 of RESOURCES) {
|
|
9369
11024
|
server.registerResource(
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
{ title:
|
|
11025
|
+
r2.name,
|
|
11026
|
+
r2.uri,
|
|
11027
|
+
{ title: r2.name, description: r2.description, mimeType: r2.mimeType },
|
|
9373
11028
|
async (uri) => {
|
|
9374
11029
|
try {
|
|
9375
11030
|
assertKaddoProject(root);
|
|
@@ -9377,7 +11032,7 @@ function createServer(root) {
|
|
|
9377
11032
|
const message = err instanceof KaddoMcpError ? err.message : String(err);
|
|
9378
11033
|
return { contents: [{ uri: uri.href, text: message, mimeType: "text/plain" }] };
|
|
9379
11034
|
}
|
|
9380
|
-
const parts =
|
|
11035
|
+
const parts = r2.read(root);
|
|
9381
11036
|
return { contents: parts.map((p) => ({ uri: p.uri, text: p.text, mimeType: p.mimeType })) };
|
|
9382
11037
|
}
|
|
9383
11038
|
);
|
|
@@ -9393,16 +11048,16 @@ function createServer(root) {
|
|
|
9393
11048
|
title: "List Work Items",
|
|
9394
11049
|
description: "List Work Items with optional status/type/knowledge_level filters.",
|
|
9395
11050
|
inputSchema: {
|
|
9396
|
-
status:
|
|
9397
|
-
type:
|
|
9398
|
-
knowledge_level:
|
|
11051
|
+
status: z3.string().optional(),
|
|
11052
|
+
type: z3.string().optional(),
|
|
11053
|
+
knowledge_level: z3.string().optional()
|
|
9399
11054
|
}
|
|
9400
11055
|
},
|
|
9401
11056
|
async (args) => toolText(guarded(root, () => listWorkItemsTool(root, args)))
|
|
9402
11057
|
);
|
|
9403
11058
|
server.registerTool(
|
|
9404
11059
|
"kaddo_get_work_item",
|
|
9405
|
-
{ title: "Get Work Item", description: "Get a Work Item by ID (summary + full markdown).", inputSchema: { id:
|
|
11060
|
+
{ title: "Get Work Item", description: "Get a Work Item by ID (summary + full markdown).", inputSchema: { id: z3.string() } },
|
|
9406
11061
|
async (args) => toolText(guarded(root, () => getWorkItem(root, args.id)))
|
|
9407
11062
|
);
|
|
9408
11063
|
server.registerTool(
|
|
@@ -9410,7 +11065,7 @@ function createServer(root) {
|
|
|
9410
11065
|
{
|
|
9411
11066
|
title: "Mark Work Item ready",
|
|
9412
11067
|
description: "Assess whether a draft Work Item is ready for implementation. Without confirm, returns a preview with readiness warnings. With confirm=true, transitions the Work Item from draft to ready.",
|
|
9413
|
-
inputSchema: { id:
|
|
11068
|
+
inputSchema: { id: z3.string(), confirm: z3.boolean().optional() }
|
|
9414
11069
|
},
|
|
9415
11070
|
async (args) => toolText(guarded(root, () => markWorkItemReady(root, args.id, args.confirm)))
|
|
9416
11071
|
);
|
|
@@ -9421,7 +11076,7 @@ function createServer(root) {
|
|
|
9421
11076
|
);
|
|
9422
11077
|
server.registerTool(
|
|
9423
11078
|
"kaddo_get_capsule",
|
|
9424
|
-
{ title: "Get Knowledge Capsule", description: "Get an external Knowledge Capsule by ID.", inputSchema: { id:
|
|
11079
|
+
{ title: "Get Knowledge Capsule", description: "Get an external Knowledge Capsule by ID.", inputSchema: { id: z3.string() } },
|
|
9425
11080
|
async (args) => toolText(guarded(root, () => getCapsuleTool(root, args.id)))
|
|
9426
11081
|
);
|
|
9427
11082
|
server.registerTool(
|
|
@@ -9431,7 +11086,7 @@ function createServer(root) {
|
|
|
9431
11086
|
);
|
|
9432
11087
|
server.registerTool(
|
|
9433
11088
|
"kaddo_get_agent_prompt",
|
|
9434
|
-
{ title: "Get agent prompt", description: "Get an installed agent prompt by name.", inputSchema: { name:
|
|
11089
|
+
{ title: "Get agent prompt", description: "Get an installed agent prompt by name.", inputSchema: { name: z3.string() } },
|
|
9435
11090
|
async (args) => toolText(guarded(root, () => getAgentPromptTool(root, args.name)))
|
|
9436
11091
|
);
|
|
9437
11092
|
server.registerTool(
|
|
@@ -9440,9 +11095,9 @@ function createServer(root) {
|
|
|
9440
11095
|
title: "List graph hints",
|
|
9441
11096
|
description: "List knowledge-graph relationship hints with optional filters.",
|
|
9442
11097
|
inputSchema: {
|
|
9443
|
-
artifact_type:
|
|
9444
|
-
severity:
|
|
9445
|
-
active_only:
|
|
11098
|
+
artifact_type: z3.string().optional(),
|
|
11099
|
+
severity: z3.string().optional(),
|
|
11100
|
+
active_only: z3.boolean().optional()
|
|
9446
11101
|
}
|
|
9447
11102
|
},
|
|
9448
11103
|
async (args) => toolText(guarded(root, () => listGraphHints(root, args)))
|
|
@@ -9454,7 +11109,7 @@ function createServer(root) {
|
|
|
9454
11109
|
);
|
|
9455
11110
|
server.registerTool(
|
|
9456
11111
|
"kaddo_get_skill",
|
|
9457
|
-
{ title: "Get skill", description: "Get an installed reusable skill by id.", inputSchema: { id:
|
|
11112
|
+
{ title: "Get skill", description: "Get an installed reusable skill by id.", inputSchema: { id: z3.string() } },
|
|
9458
11113
|
async (args) => toolText(guarded(root, () => getSkillTool(root, args.id)))
|
|
9459
11114
|
);
|
|
9460
11115
|
let installedSkills = [];
|
|
@@ -9499,7 +11154,7 @@ function createServer(root) {
|
|
|
9499
11154
|
{
|
|
9500
11155
|
title: "Generate knowledge graph",
|
|
9501
11156
|
description: `Regenerate .kaddo/graph.json/.mmd + graph-hints.md/.json. scope: active (default) or all. ${DERIVED_NOTE}`,
|
|
9502
|
-
inputSchema: { scope:
|
|
11157
|
+
inputSchema: { scope: z3.enum(["active", "all"]).optional() }
|
|
9503
11158
|
},
|
|
9504
11159
|
async (args) => generated(root, "generate knowledge graph", () => generateGraph(root, args.scope ?? "active"))
|
|
9505
11160
|
);
|
|
@@ -9509,9 +11164,9 @@ function createServer(root) {
|
|
|
9509
11164
|
title: "Generate impact report",
|
|
9510
11165
|
description: `Write the Knowledge Impact Report under .kaddo/reports/. format: markdown (default) or json; scope: active or all (default all). ${DERIVED_NOTE}`,
|
|
9511
11166
|
inputSchema: {
|
|
9512
|
-
format:
|
|
9513
|
-
scope:
|
|
9514
|
-
output:
|
|
11167
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11168
|
+
scope: z3.enum(["active", "all"]).optional(),
|
|
11169
|
+
output: z3.string().optional()
|
|
9515
11170
|
}
|
|
9516
11171
|
},
|
|
9517
11172
|
async (args) => generated(
|
|
@@ -9526,9 +11181,9 @@ function createServer(root) {
|
|
|
9526
11181
|
title: "Generate savings report",
|
|
9527
11182
|
description: `Write the Estimated Savings Report under .kaddo/reports/. format: markdown (default) or json; scope: active or all (default all). Evidence-based estimates, not exact ROI. ${DERIVED_NOTE}`,
|
|
9528
11183
|
inputSchema: {
|
|
9529
|
-
format:
|
|
9530
|
-
scope:
|
|
9531
|
-
output:
|
|
11184
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11185
|
+
scope: z3.enum(["active", "all"]).optional(),
|
|
11186
|
+
output: z3.string().optional()
|
|
9532
11187
|
}
|
|
9533
11188
|
},
|
|
9534
11189
|
async (args) => generated(
|
|
@@ -9543,8 +11198,8 @@ function createServer(root) {
|
|
|
9543
11198
|
title: "Generate drift report",
|
|
9544
11199
|
description: `Write the Drift Trend Report under .kaddo/reports/ from recorded guard history. format: markdown (default) or json. Does NOT record guard runs. ${DERIVED_NOTE}`,
|
|
9545
11200
|
inputSchema: {
|
|
9546
|
-
format:
|
|
9547
|
-
output:
|
|
11201
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11202
|
+
output: z3.string().optional()
|
|
9548
11203
|
}
|
|
9549
11204
|
},
|
|
9550
11205
|
async (args) => generated(
|
|
@@ -9559,8 +11214,8 @@ function createServer(root) {
|
|
|
9559
11214
|
title: "Generate open-questions report",
|
|
9560
11215
|
description: `Write the Open Questions readiness report under .kaddo/reports/ (classifies blocking/important/deferred). Does NOT resolve questions. ${DERIVED_NOTE}`,
|
|
9561
11216
|
inputSchema: {
|
|
9562
|
-
format:
|
|
9563
|
-
output:
|
|
11217
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11218
|
+
output: z3.string().optional()
|
|
9564
11219
|
}
|
|
9565
11220
|
},
|
|
9566
11221
|
async (args) => generated(
|