@kaddo/mcp 3.60.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 +2336 -690
- 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
|
|
697
1999
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
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
|
|
2088
|
+
|
|
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,10 +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"),
|
|
2455
|
-
ready_work_item_ids: wis.filter((
|
|
3836
|
+
ready_work_item_ids: wis.filter((w3) => w3.lifecycle === "ready").map((w3) => w3.id),
|
|
2456
3837
|
in_progress_work_items: byState("in-progress"),
|
|
2457
3838
|
blocked_work_items: byState("blocked"),
|
|
2458
3839
|
total_work_items: total,
|
|
@@ -2482,17 +3863,17 @@ function roadmapSignal(dir) {
|
|
|
2482
3863
|
const lines = md.replace(/^---[\s\S]*?---/m, "").split(/\r?\n/);
|
|
2483
3864
|
let inOpenQuestions = false;
|
|
2484
3865
|
let candidates = 0;
|
|
2485
|
-
for (const
|
|
2486
|
-
if (/^#{1,6}\s/.test(
|
|
2487
|
-
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;
|
|
2488
3869
|
}
|
|
2489
3870
|
return candidates > 0 ? "has-candidates" : "empty";
|
|
2490
3871
|
}
|
|
2491
3872
|
function workItemsSignal(dir) {
|
|
2492
3873
|
const wis = discoverWorkItems(dir);
|
|
2493
3874
|
if (wis.length === 0) return "none";
|
|
2494
|
-
if (wis.some((
|
|
2495
|
-
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";
|
|
2496
3877
|
return "none-ready";
|
|
2497
3878
|
}
|
|
2498
3879
|
function installedAdapters(dir) {
|
|
@@ -2500,8 +3881,8 @@ function installedAdapters(dir) {
|
|
|
2500
3881
|
(s) => s.state === "injected" || s.state === "legacy-injected" || s.state === "full-generated" && (s.originAdapter === s.id || s.originAdapter === null)
|
|
2501
3882
|
).map((s) => s.id);
|
|
2502
3883
|
}
|
|
2503
|
-
var
|
|
2504
|
-
var
|
|
3884
|
+
var B2 = "knowledge/business/business.md";
|
|
3885
|
+
var P2 = "knowledge/product/product.md";
|
|
2505
3886
|
var CAP = "knowledge/product/capabilities.md";
|
|
2506
3887
|
var CS = "knowledge/tech/current-state.md";
|
|
2507
3888
|
var CB = "knowledge/tech/codebase.md";
|
|
@@ -2511,8 +3892,61 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2511
3892
|
return { id: "init", phase: "Setup", label: "Run `kaddo init` to initialize Kaddo.", command: "kaddo init", reason: "Kaddo is not initialized in this project." };
|
|
2512
3893
|
}
|
|
2513
3894
|
const state = config.project.state;
|
|
2514
|
-
const
|
|
2515
|
-
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);
|
|
2516
3950
|
if (qBusiness === "missing" || qProduct === "missing") {
|
|
2517
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." };
|
|
2518
3952
|
}
|
|
@@ -2556,12 +3990,12 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2556
3990
|
]
|
|
2557
3991
|
};
|
|
2558
3992
|
};
|
|
2559
|
-
if (qBusiness !== "useful") return refine("refine-business", "business-agent",
|
|
3993
|
+
if (qBusiness !== "useful") return refine("refine-business", "business-agent", B2, qBusiness);
|
|
2560
3994
|
if (qProduct !== "useful" || qCap !== "useful") {
|
|
2561
3995
|
if (qCap !== "useful") {
|
|
2562
3996
|
return refine("refine-product", "capability-agent", CAP, qCap, discovery ? "discover and document existing system capabilities grouped by functional domains in" : "complete");
|
|
2563
3997
|
}
|
|
2564
|
-
return refine("refine-product", "capability-agent",
|
|
3998
|
+
return refine("refine-product", "capability-agent", P2, qProduct);
|
|
2565
3999
|
}
|
|
2566
4000
|
if (qCurrentState !== "useful") return refine("refine-current-state", "architecture-agent", CS, qCurrentState);
|
|
2567
4001
|
if (qCodebase !== "useful") {
|
|
@@ -2765,7 +4199,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2765
4199
|
if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
|
|
2766
4200
|
const scan = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
|
|
2767
4201
|
const understand = exists(join(dir, ".kaddo", "understand.md")) ? "available" : "missing";
|
|
2768
|
-
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((
|
|
4202
|
+
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f3) => [f3.key, analyzeKnowledgeArtifact(dir, f3.path)]));
|
|
2769
4203
|
const ctx = buildCodexAdapterContext(dir);
|
|
2770
4204
|
const agents = ctx.hasAgents ? "present" : "missing";
|
|
2771
4205
|
const skills = ctx.hasSkills ? "present" : "missing";
|
|
@@ -2793,7 +4227,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2793
4227
|
resolved_questions: oq.summary.resolution.resolved,
|
|
2794
4228
|
deferred_questions: oq.summary.resolution.deferred
|
|
2795
4229
|
};
|
|
2796
|
-
const firstWeak = KNOWLEDGE_FILES.find((
|
|
4230
|
+
const firstWeak = KNOWLEDGE_FILES.find((f3) => presence[f3.key] !== "useful");
|
|
2797
4231
|
let overall;
|
|
2798
4232
|
if (scan === "missing") overall = "initialized";
|
|
2799
4233
|
else if (bootstrapBaseline2 === "incomplete") overall = "bootstrap-incomplete";
|
|
@@ -2852,7 +4286,7 @@ function skill(id, title, group, appliesTo, body) {
|
|
|
2852
4286
|
`version: ${KADDO_VERSION}`,
|
|
2853
4287
|
`group: ${group}`,
|
|
2854
4288
|
"applies_to:",
|
|
2855
|
-
...appliesTo.map((
|
|
4289
|
+
...appliesTo.map((a2) => ` - ${a2}`),
|
|
2856
4290
|
"---",
|
|
2857
4291
|
""
|
|
2858
4292
|
].join("\n");
|
|
@@ -3207,6 +4641,58 @@ steps, and stop criteria (when to pause and ask).
|
|
|
3207
4641
|
A numbered plan covering the sections above, ending with a request to confirm before coding.
|
|
3208
4642
|
`
|
|
3209
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
|
+
);
|
|
3210
4696
|
var SKILLS = [
|
|
3211
4697
|
ADR_WRITING,
|
|
3212
4698
|
WORK_ITEM_REFINEMENT,
|
|
@@ -3214,11 +4700,12 @@ var SKILLS = [
|
|
|
3214
4700
|
GRAPH_METADATA_REVIEW,
|
|
3215
4701
|
CAPSULE_WRITING,
|
|
3216
4702
|
LEARNING_CAPTURE,
|
|
3217
|
-
IMPLEMENTATION_PLANNING
|
|
4703
|
+
IMPLEMENTATION_PLANNING,
|
|
4704
|
+
MODULE_CONTEXT_REFINEMENT
|
|
3218
4705
|
];
|
|
3219
4706
|
var SKILL_GROUPS = {
|
|
3220
4707
|
delivery: ["work-item-refinement", "implementation-planning", "learning-capture"],
|
|
3221
|
-
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review"],
|
|
4708
|
+
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review", "module-context-refinement"],
|
|
3222
4709
|
integration: ["capsule-writing"]
|
|
3223
4710
|
};
|
|
3224
4711
|
var SKILL_GROUP_NAMES = Object.keys(SKILL_GROUPS);
|
|
@@ -3305,6 +4792,14 @@ var RESPONSIBILITY_MATRIX = {
|
|
|
3305
4792
|
cannotSuggest: ["Git", "branches", "code"],
|
|
3306
4793
|
next: ["architecture-agent"]
|
|
3307
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
|
+
},
|
|
3308
4803
|
"architecture-agent": {
|
|
3309
4804
|
agent: "architecture-agent",
|
|
3310
4805
|
responsibleFor: ["Architecture", "Technical state", "Risks"],
|
|
@@ -3448,25 +4943,25 @@ function list(items) {
|
|
|
3448
4943
|
return items.length > 0 ? items.join(", ") : "\u2014";
|
|
3449
4944
|
}
|
|
3450
4945
|
function renderAgentBoundaries(agent) {
|
|
3451
|
-
const
|
|
3452
|
-
if (!
|
|
4946
|
+
const r2 = RESPONSIBILITY_MATRIX[agent];
|
|
4947
|
+
if (!r2) return "";
|
|
3453
4948
|
return [
|
|
3454
4949
|
"## Responsibility & Boundaries",
|
|
3455
4950
|
"",
|
|
3456
|
-
`**Responsible for:** ${list(
|
|
3457
|
-
`**Produces:** ${list(
|
|
3458
|
-
`**May suggest:** ${list(
|
|
3459
|
-
`**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)}`,
|
|
3460
4955
|
"",
|
|
3461
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.",
|
|
3462
4957
|
""
|
|
3463
4958
|
].join("\n");
|
|
3464
4959
|
}
|
|
3465
4960
|
function renderAgentTrace(agent) {
|
|
3466
|
-
const
|
|
3467
|
-
if (!
|
|
3468
|
-
const produced =
|
|
3469
|
-
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)";
|
|
3470
4965
|
return [
|
|
3471
4966
|
"## Agent Trace",
|
|
3472
4967
|
"",
|
|
@@ -3474,7 +4969,7 @@ function renderAgentTrace(agent) {
|
|
|
3474
4969
|
"",
|
|
3475
4970
|
"```text",
|
|
3476
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",
|
|
3477
|
-
`Agent: ${
|
|
4972
|
+
`Agent: ${r2.agent}`,
|
|
3478
4973
|
"",
|
|
3479
4974
|
"Produced:",
|
|
3480
4975
|
produced,
|
|
@@ -3522,7 +5017,8 @@ var KNOWLEDGE_REFINING_AGENTS = {
|
|
|
3522
5017
|
"work-item-agent": "work-item-agent",
|
|
3523
5018
|
"backlog-agent": "backlog-agent",
|
|
3524
5019
|
"adr-agent": "adr-agent",
|
|
3525
|
-
"implementation-agent": "implementation-agent"
|
|
5020
|
+
"implementation-agent": "implementation-agent",
|
|
5021
|
+
"module-context-agent": "module-context-agent"
|
|
3526
5022
|
};
|
|
3527
5023
|
function renderFrontmatterRules(agent) {
|
|
3528
5024
|
if (!KNOWLEDGE_REFINING_AGENTS[agent]) return "";
|
|
@@ -4742,6 +6238,92 @@ Save as \`knowledge/tech/modules/<module-name>/module-design.md\`.
|
|
|
4742
6238
|
- Diagrams are suggested, not generated.
|
|
4743
6239
|
- Assumptions and risks are explicit.
|
|
4744
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
|
+
`;
|
|
4745
6327
|
var BUSINESS_AGENT = `# Business Agent
|
|
4746
6328
|
|
|
4747
6329
|
## Role
|
|
@@ -5339,6 +6921,7 @@ var AGENT_PROMPTS = [
|
|
|
5339
6921
|
{ fileName: "standards-agent.md", content: STANDARDS_AGENT },
|
|
5340
6922
|
{ fileName: "stack-agent.md", content: STACK_AGENT },
|
|
5341
6923
|
{ fileName: "module-design-agent.md", content: MODULE_DESIGN_AGENT },
|
|
6924
|
+
{ fileName: "module-context-agent.md", content: MODULE_CONTEXT_AGENT },
|
|
5342
6925
|
// Bootstrap agents (new projects)
|
|
5343
6926
|
{ fileName: "business-agent.md", content: BUSINESS_AGENT },
|
|
5344
6927
|
{ fileName: "bootstrap-agent.md", content: BOOTSTRAP_AGENT },
|
|
@@ -5439,9 +7022,9 @@ var agentReadme = {
|
|
|
5439
7022
|
"- `graph-agent.md` \u2014 review `kaddo graph export` hints and propose precise relationship front matter."
|
|
5440
7023
|
].join("\n")
|
|
5441
7024
|
};
|
|
5442
|
-
var agentFiles = AGENT_PROMPTS.map((
|
|
5443
|
-
path: agentInstallPath(
|
|
5444
|
-
content: withAgentFrontMatter(
|
|
7025
|
+
var agentFiles = AGENT_PROMPTS.map((a2) => ({
|
|
7026
|
+
path: agentInstallPath(a2.fileName),
|
|
7027
|
+
content: withAgentFrontMatter(a2.fileName, a2.content)
|
|
5445
7028
|
}));
|
|
5446
7029
|
var agentsModule = {
|
|
5447
7030
|
name: "agents",
|
|
@@ -5493,10 +7076,10 @@ var agentsModule = {
|
|
|
5493
7076
|
|
|
5494
7077
|
// ../cli/src/core/assets.ts
|
|
5495
7078
|
function canonicalAgents() {
|
|
5496
|
-
return AGENT_PROMPTS.map((
|
|
5497
|
-
name:
|
|
5498
|
-
path: agentInstallPath(
|
|
5499
|
-
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)
|
|
5500
7083
|
}));
|
|
5501
7084
|
}
|
|
5502
7085
|
function canonicalSkills() {
|
|
@@ -5510,12 +7093,12 @@ function versionOf(content) {
|
|
|
5510
7093
|
return null;
|
|
5511
7094
|
}
|
|
5512
7095
|
}
|
|
5513
|
-
function cmpVersion(
|
|
5514
|
-
const pa =
|
|
5515
|
-
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);
|
|
5516
7099
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
5517
|
-
const
|
|
5518
|
-
if (
|
|
7100
|
+
const d3 = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
7101
|
+
if (d3 !== 0) return d3 < 0 ? -1 : 1;
|
|
5519
7102
|
}
|
|
5520
7103
|
return 0;
|
|
5521
7104
|
}
|
|
@@ -5550,7 +7133,7 @@ function summarize(items) {
|
|
|
5550
7133
|
}
|
|
5551
7134
|
function assetStatus(dir, kind) {
|
|
5552
7135
|
const catalog = kind === "agent" ? canonicalAgents() : canonicalSkills();
|
|
5553
|
-
return summarize(catalog.map((
|
|
7136
|
+
return summarize(catalog.map((a2) => classify(dir, a2)));
|
|
5554
7137
|
}
|
|
5555
7138
|
function installedAssetsSummary(dir) {
|
|
5556
7139
|
return { version: KADDO_VERSION, agents: assetStatus(dir, "agent"), skills: assetStatus(dir, "skill") };
|
|
@@ -5561,14 +7144,14 @@ var ROADMAP_PATH = "knowledge/delivery/roadmap.md";
|
|
|
5561
7144
|
var INITIATIVE_RE2 = /^#{2,4}\s+(RM-[\w.-]+)\s*[:\-–]?\s*(.*)$/;
|
|
5562
7145
|
function fieldPresent(lines, label) {
|
|
5563
7146
|
for (let i = 0; i < lines.length; i++) {
|
|
5564
|
-
const
|
|
5565
|
-
if (!
|
|
5566
|
-
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();
|
|
5567
7150
|
if (inline) return true;
|
|
5568
|
-
for (let
|
|
5569
|
-
if (/^\s{2,}[-*]\s+\S/.test(lines[
|
|
5570
|
-
if (/^\S/.test(lines[
|
|
5571
|
-
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;
|
|
5572
7155
|
}
|
|
5573
7156
|
}
|
|
5574
7157
|
return false;
|
|
@@ -5593,10 +7176,10 @@ function parseRoadmapCandidateQuality(md) {
|
|
|
5593
7176
|
cur = null;
|
|
5594
7177
|
};
|
|
5595
7178
|
for (const line of lines) {
|
|
5596
|
-
const
|
|
5597
|
-
if (
|
|
7179
|
+
const m2 = line.match(INITIATIVE_RE2);
|
|
7180
|
+
if (m2) {
|
|
5598
7181
|
flush();
|
|
5599
|
-
cur = { id:
|
|
7182
|
+
cur = { id: m2[1], title: m2[2].trim(), lines: [] };
|
|
5600
7183
|
continue;
|
|
5601
7184
|
}
|
|
5602
7185
|
if (cur) cur.lines.push(line);
|
|
@@ -5772,8 +7355,8 @@ function optStr(v) {
|
|
|
5772
7355
|
}
|
|
5773
7356
|
|
|
5774
7357
|
// ../cli/src/core/project-route.ts
|
|
5775
|
-
function isUseful(
|
|
5776
|
-
return
|
|
7358
|
+
function isUseful(q3) {
|
|
7359
|
+
return q3 === "useful";
|
|
5777
7360
|
}
|
|
5778
7361
|
var enableKaddo = {
|
|
5779
7362
|
id: "enable-kaddo",
|
|
@@ -6058,9 +7641,9 @@ function buildRouteContext(dir) {
|
|
|
6058
7641
|
}
|
|
6059
7642
|
}
|
|
6060
7643
|
const stats = roadmapStats(roadmapMd, wis.length);
|
|
6061
|
-
const byState = (s) => wis.filter((
|
|
7644
|
+
const byState = (s) => wis.filter((w3) => w3.lifecycle === s).length;
|
|
6062
7645
|
const total = wis.length;
|
|
6063
|
-
const withOwnership = wis.filter((
|
|
7646
|
+
const withOwnership = wis.filter((w3) => w3.codeGlobs.length > 0).length;
|
|
6064
7647
|
const adapters = installedAdapters(dir);
|
|
6065
7648
|
const nextStep = resolveNextStep(dir);
|
|
6066
7649
|
return {
|
|
@@ -6089,8 +7672,8 @@ function buildRouteContext(dir) {
|
|
|
6089
7672
|
adaptersInstalled: adapters.length,
|
|
6090
7673
|
hasGuardHistory: exists(join(dir, ".kaddo", "history", "guard-runs.jsonl")),
|
|
6091
7674
|
hasScanWarnings: hasScan ? loadScanWarnings(dir) : false,
|
|
6092
|
-
hasUnknownSources: wis.some((
|
|
6093
|
-
const src = parseWorkItemSource(
|
|
7675
|
+
hasUnknownSources: wis.some((w3) => {
|
|
7676
|
+
const src = parseWorkItemSource(w3.rawFrontmatter);
|
|
6094
7677
|
return src.type === "unknown" && src.inferred;
|
|
6095
7678
|
}),
|
|
6096
7679
|
nextStepId: mapNextStepId(nextStep.id)
|
|
@@ -6119,7 +7702,10 @@ function mapNextStepId(id) {
|
|
|
6119
7702
|
"refine-codebase": "describe-architecture",
|
|
6120
7703
|
"review-work-item": "refine-work-item",
|
|
6121
7704
|
"prepare-implementation": "prepare-implementation",
|
|
6122
|
-
"implement-work-item": "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"
|
|
6123
7709
|
};
|
|
6124
7710
|
return MAP[id] ?? id;
|
|
6125
7711
|
}
|
|
@@ -6128,9 +7714,9 @@ function buildProjectRoute(dir) {
|
|
|
6128
7714
|
const state = config?.project.state ?? "pre-ai";
|
|
6129
7715
|
const defs = stepsForState(state);
|
|
6130
7716
|
const ctx = buildRouteContext(dir);
|
|
6131
|
-
const steps = defs.map((
|
|
6132
|
-
const result =
|
|
6133
|
-
return { id:
|
|
7717
|
+
const steps = defs.map((d3) => {
|
|
7718
|
+
const result = d3.evaluate(ctx);
|
|
7719
|
+
return { id: d3.id, label: d3.label, ...result };
|
|
6134
7720
|
});
|
|
6135
7721
|
for (const s of steps) {
|
|
6136
7722
|
if (s.id === ctx.nextStepId && s.status !== "done") {
|
|
@@ -6194,8 +7780,8 @@ function renderRouteCompact(route) {
|
|
|
6194
7780
|
const warnings = route.steps.filter((s) => s.status === "warning");
|
|
6195
7781
|
if (warnings.length > 0) {
|
|
6196
7782
|
lines.push("Warnings:");
|
|
6197
|
-
for (const
|
|
6198
|
-
lines.push(`- ${
|
|
7783
|
+
for (const w3 of warnings) {
|
|
7784
|
+
lines.push(`- ${w3.label}${w3.reason ? ` \u2014 ${w3.reason}` : ""}`);
|
|
6199
7785
|
}
|
|
6200
7786
|
lines.push("");
|
|
6201
7787
|
}
|
|
@@ -6261,10 +7847,10 @@ function findDuplicateWorkItems(items) {
|
|
|
6261
7847
|
const bucket = (key, reason, pred) => {
|
|
6262
7848
|
const matched = items.filter(pred);
|
|
6263
7849
|
if (matched.length > 1) {
|
|
6264
|
-
const id = `${reason}:${key}:${matched.map((
|
|
7850
|
+
const id = `${reason}:${key}:${matched.map((m2) => m2.id).sort().join(",")}`;
|
|
6265
7851
|
if (!seen.has(id)) {
|
|
6266
7852
|
seen.add(id);
|
|
6267
|
-
groups.push({ reason, items: matched.map((
|
|
7853
|
+
groups.push({ reason, items: matched.map((m2) => ({ id: m2.id, title: m2.title })) });
|
|
6268
7854
|
}
|
|
6269
7855
|
}
|
|
6270
7856
|
};
|
|
@@ -6278,7 +7864,7 @@ function findDuplicateWorkItems(items) {
|
|
|
6278
7864
|
}
|
|
6279
7865
|
function first(values) {
|
|
6280
7866
|
if (Array.isArray(values)) {
|
|
6281
|
-
const v = values.find((
|
|
7867
|
+
const v = values.find((x2) => typeof x2 === "string" && x2);
|
|
6282
7868
|
return v ? String(v) : void 0;
|
|
6283
7869
|
}
|
|
6284
7870
|
return typeof values === "string" && values ? values : void 0;
|
|
@@ -6318,9 +7904,9 @@ function loadScanSignals(dir) {
|
|
|
6318
7904
|
function hasAgents(dir) {
|
|
6319
7905
|
const agentsDir = join(dir, ARCH_DIR2, "agents");
|
|
6320
7906
|
if (!exists(agentsDir)) return false;
|
|
6321
|
-
function hasAgentMd(
|
|
6322
|
-
for (const e of readDir(
|
|
6323
|
-
const full = join(
|
|
7907
|
+
function hasAgentMd(d3) {
|
|
7908
|
+
for (const e of readDir(d3)) {
|
|
7909
|
+
const full = join(d3, e);
|
|
6324
7910
|
if (isFile(full)) {
|
|
6325
7911
|
if (e.endsWith("-agent.md")) return true;
|
|
6326
7912
|
} else if (hasAgentMd(full)) {
|
|
@@ -6360,7 +7946,7 @@ function buildProjectExplanation(dir) {
|
|
|
6360
7946
|
infrastructureFiles: scan.infrastructureFiles
|
|
6361
7947
|
} : null;
|
|
6362
7948
|
const layers = knowledgeLayers(dir);
|
|
6363
|
-
const layerStatus = (name) => layers.find((
|
|
7949
|
+
const layerStatus = (name) => layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
6364
7950
|
const knowledge = {
|
|
6365
7951
|
hasScan: scan !== null,
|
|
6366
7952
|
hasInventory: exists(join(dir, ARCH_DIR2, "inventory.md")),
|
|
@@ -6375,18 +7961,18 @@ function buildProjectExplanation(dir) {
|
|
|
6375
7961
|
hasSkills: hasSkills(dir)
|
|
6376
7962
|
};
|
|
6377
7963
|
const workItemArtifacts = discoverWorkItems(dir);
|
|
6378
|
-
const items = workItemArtifacts.map((
|
|
6379
|
-
const src = parseWorkItemSource(
|
|
7964
|
+
const items = workItemArtifacts.map((a2) => {
|
|
7965
|
+
const src = parseWorkItemSource(a2.rawFrontmatter);
|
|
6380
7966
|
return {
|
|
6381
|
-
id:
|
|
6382
|
-
title:
|
|
6383
|
-
type:
|
|
6384
|
-
status:
|
|
6385
|
-
lifecycle: lifecycleStateOf({ status:
|
|
6386
|
-
initiative:
|
|
6387
|
-
knowledgeLevel:
|
|
6388
|
-
hasOwnership:
|
|
6389
|
-
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,
|
|
6390
7976
|
source: { type: src.type, ...src.id ? { id: src.id } : {}, inferred: src.inferred }
|
|
6391
7977
|
};
|
|
6392
7978
|
});
|
|
@@ -6402,7 +7988,7 @@ function buildProjectExplanation(dir) {
|
|
|
6402
7988
|
if (!initiativeMap.has(name)) initiativeMap.set(name, emptyLifecycleCounts());
|
|
6403
7989
|
initiativeMap.get(name)[i.lifecycle]++;
|
|
6404
7990
|
}
|
|
6405
|
-
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));
|
|
6406
7992
|
const workItems = {
|
|
6407
7993
|
total: items.length,
|
|
6408
7994
|
inProgress: items.filter((i) => i.lifecycle === "in-progress").length,
|
|
@@ -6419,9 +8005,9 @@ function buildProjectExplanation(dir) {
|
|
|
6419
8005
|
workItemsWithOwnership: withOwnership,
|
|
6420
8006
|
workItemsMissingOwnership: items.length - withOwnership
|
|
6421
8007
|
};
|
|
6422
|
-
const domains = [...new Set(workItemArtifacts.flatMap((
|
|
8008
|
+
const domains = [...new Set(workItemArtifacts.flatMap((a2) => a2.domains))].filter(Boolean);
|
|
6423
8009
|
const duplicateWorkItems = findDuplicateWorkItems(
|
|
6424
|
-
workItemArtifacts.map((
|
|
8010
|
+
workItemArtifacts.map((a2) => ({ id: a2.id || a2.title, title: a2.title, sourceId: a2.sourceId }))
|
|
6425
8011
|
);
|
|
6426
8012
|
const roadmapPath = join(dir, ARCH_DIR2, "delivery", "roadmap.md");
|
|
6427
8013
|
const roadmapMd = exists(roadmapPath) ? readFile(roadmapPath) : null;
|
|
@@ -6562,7 +8148,7 @@ function renderExplanationHuman(exp) {
|
|
|
6562
8148
|
lines.push("## Scan Signals");
|
|
6563
8149
|
lines.push(renderSignalsCompact(exp.scanSignals));
|
|
6564
8150
|
}
|
|
6565
|
-
const ls = (name) => exp.layers.find((
|
|
8151
|
+
const ls = (name) => exp.layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
6566
8152
|
lines.push("## Knowledge Status");
|
|
6567
8153
|
lines.push(`- Inventory: ${exp.knowledge.hasInventory ? "available" : "missing"}`);
|
|
6568
8154
|
lines.push(`- Context pack: ${exp.knowledge.hasContextPack ? "available" : "missing"}`);
|
|
@@ -6590,7 +8176,7 @@ function renderExplanationHuman(exp) {
|
|
|
6590
8176
|
lines.push(`- ${LIFECYCLE_LABEL[s2]}: ${exp.workItems.byState[s2]}`);
|
|
6591
8177
|
}
|
|
6592
8178
|
lines.push("");
|
|
6593
|
-
const typeEntries = Object.entries(exp.workItems.byType).sort((
|
|
8179
|
+
const typeEntries = Object.entries(exp.workItems.byType).sort((a2, b2) => b2[1] - a2[1]);
|
|
6594
8180
|
if (typeEntries.length > 0) {
|
|
6595
8181
|
lines.push("## Work Items by Type");
|
|
6596
8182
|
for (const [t, n] of typeEntries) lines.push(`- ${typeLabel(t)}: ${n}`);
|
|
@@ -6638,15 +8224,15 @@ function renderExplanationHuman(exp) {
|
|
|
6638
8224
|
}
|
|
6639
8225
|
lines.push("## Mapped Modules");
|
|
6640
8226
|
if (exp.mappedModules.length > 0) {
|
|
6641
|
-
for (const
|
|
6642
|
-
const owner =
|
|
6643
|
-
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}`);
|
|
6644
8230
|
}
|
|
6645
8231
|
lines.push("");
|
|
6646
8232
|
lines.push("## Module Artifact Coverage");
|
|
6647
|
-
for (const
|
|
6648
|
-
const present = presentArtifacts(
|
|
6649
|
-
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"}`);
|
|
6650
8236
|
}
|
|
6651
8237
|
lines.push("");
|
|
6652
8238
|
} else {
|
|
@@ -6682,7 +8268,7 @@ function renderExplanationHuman(exp) {
|
|
|
6682
8268
|
}
|
|
6683
8269
|
if (exp.skills.total > 0) {
|
|
6684
8270
|
lines.push(`## Skills installed: ${exp.skills.total}`);
|
|
6685
|
-
const groups = Object.entries(exp.skills.byGroup).sort((
|
|
8271
|
+
const groups = Object.entries(exp.skills.byGroup).sort((a2, b2) => a2[0].localeCompare(b2[0]));
|
|
6686
8272
|
if (groups.length > 0) {
|
|
6687
8273
|
lines.push("Groups:");
|
|
6688
8274
|
for (const [g, n] of groups) lines.push(`- ${g}: ${n}`);
|
|
@@ -6691,7 +8277,7 @@ function renderExplanationHuman(exp) {
|
|
|
6691
8277
|
}
|
|
6692
8278
|
if (exp.missingKnowledge.length > 0) {
|
|
6693
8279
|
lines.push("## Missing Knowledge");
|
|
6694
|
-
for (const
|
|
8280
|
+
for (const m2 of exp.missingKnowledge) lines.push(`- ${m2}`);
|
|
6695
8281
|
lines.push("");
|
|
6696
8282
|
}
|
|
6697
8283
|
if (exp.duplicateWorkItems.length > 0) {
|
|
@@ -6709,7 +8295,7 @@ function renderExplanationHuman(exp) {
|
|
|
6709
8295
|
lines.push(`- Phase: ${assessment.phase}`);
|
|
6710
8296
|
if (assessment.reasons.length > 0) {
|
|
6711
8297
|
lines.push("- Reason:");
|
|
6712
|
-
for (const
|
|
8298
|
+
for (const r3 of assessment.reasons) lines.push(` - ${r3}`);
|
|
6713
8299
|
}
|
|
6714
8300
|
lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
|
|
6715
8301
|
lines.push("");
|
|
@@ -6721,11 +8307,11 @@ function renderExplanationHuman(exp) {
|
|
|
6721
8307
|
steps.forEach((s2, i) => lines.push(`${i + 1}. ${s2}`));
|
|
6722
8308
|
lines.push("");
|
|
6723
8309
|
}
|
|
6724
|
-
const
|
|
6725
|
-
const s =
|
|
8310
|
+
const r2 = exp.readiness;
|
|
8311
|
+
const s = r2.signals;
|
|
6726
8312
|
lines.push("## Project Readiness");
|
|
6727
|
-
lines.push(`- overall: ${
|
|
6728
|
-
if (
|
|
8313
|
+
lines.push(`- overall: ${r2.overall}`);
|
|
8314
|
+
if (r2.overall !== "not-initialized" && r2.overall !== "not-applicable" && r2.overall !== "legacy-project") {
|
|
6729
8315
|
lines.push(`- bootstrap baseline: ${s.bootstrap_baseline}`);
|
|
6730
8316
|
lines.push(`- scan: ${s.scan}`);
|
|
6731
8317
|
lines.push(`- understand: ${s.understand}`);
|
|
@@ -6745,11 +8331,11 @@ function renderExplanationHuman(exp) {
|
|
|
6745
8331
|
}
|
|
6746
8332
|
lines.push("");
|
|
6747
8333
|
lines.push("### Recommended next step");
|
|
6748
|
-
lines.push(
|
|
8334
|
+
lines.push(r2.recommended_next_step.label);
|
|
6749
8335
|
lines.push("");
|
|
6750
8336
|
const td = exp.techDecisions;
|
|
6751
8337
|
const tk = exp.techKnowledge;
|
|
6752
|
-
const mark = (
|
|
8338
|
+
const mark = (b2) => b2 ? "\u2713" : "\u2717";
|
|
6753
8339
|
lines.push("## Tech Knowledge");
|
|
6754
8340
|
lines.push("Core:");
|
|
6755
8341
|
lines.push(`- ${mark(tk.core.currentState)} current-state.md`);
|
|
@@ -6824,8 +8410,8 @@ function renderExplanationHuman(exp) {
|
|
|
6824
8410
|
}
|
|
6825
8411
|
if (exp.metadataHealth.findings.length > 0) {
|
|
6826
8412
|
lines.push("## Metadata Health");
|
|
6827
|
-
for (const
|
|
6828
|
-
lines.push(`- \`${
|
|
8413
|
+
for (const f3 of exp.metadataHealth.findings) {
|
|
8414
|
+
lines.push(`- \`${f3.file}\`: ${f3.detail}`);
|
|
6829
8415
|
}
|
|
6830
8416
|
lines.push("");
|
|
6831
8417
|
}
|
|
@@ -6858,30 +8444,30 @@ function loadGuardRuns(dir) {
|
|
|
6858
8444
|
return out;
|
|
6859
8445
|
}
|
|
6860
8446
|
function resolveDriftThreads(runs) {
|
|
6861
|
-
const sorted = [...runs].sort((
|
|
8447
|
+
const sorted = [...runs].sort((a2, b2) => a2.generated_at.localeCompare(b2.generated_at));
|
|
6862
8448
|
const paths = /* @__PURE__ */ new Set();
|
|
6863
|
-
for (const
|
|
8449
|
+
for (const r2 of sorted) for (const w3 of r2.warnings) paths.add(w3.code_path);
|
|
6864
8450
|
const threads = [];
|
|
6865
8451
|
for (const codePath of paths) {
|
|
6866
8452
|
const related = /* @__PURE__ */ new Set();
|
|
6867
8453
|
let firstDetected = "";
|
|
6868
8454
|
let lastWarn = "";
|
|
6869
|
-
for (const
|
|
6870
|
-
const
|
|
6871
|
-
if (
|
|
6872
|
-
if (!firstDetected) firstDetected =
|
|
6873
|
-
lastWarn =
|
|
6874
|
-
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);
|
|
6875
8461
|
}
|
|
6876
8462
|
}
|
|
6877
8463
|
let resolvedAt;
|
|
6878
|
-
for (const
|
|
6879
|
-
if (
|
|
6880
|
-
const touched =
|
|
6881
|
-
const warnedHere =
|
|
6882
|
-
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));
|
|
6883
8469
|
if (touched && updatedRelated && !warnedHere) {
|
|
6884
|
-
resolvedAt =
|
|
8470
|
+
resolvedAt = r2.generated_at;
|
|
6885
8471
|
break;
|
|
6886
8472
|
}
|
|
6887
8473
|
}
|
|
@@ -6902,9 +8488,9 @@ function hotspotDir(codePath) {
|
|
|
6902
8488
|
}
|
|
6903
8489
|
function computeTrend(runs) {
|
|
6904
8490
|
if (runs.length < 2) return { direction: "unknown", reason: "Not enough recorded runs to detect a trend." };
|
|
6905
|
-
const sorted = [...runs].sort((
|
|
8491
|
+
const sorted = [...runs].sort((a2, b2) => a2.generated_at.localeCompare(b2.generated_at));
|
|
6906
8492
|
const mid = Math.floor(sorted.length / 2);
|
|
6907
|
-
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;
|
|
6908
8494
|
const earlier = avg(sorted.slice(0, mid));
|
|
6909
8495
|
const recent = avg(sorted.slice(mid));
|
|
6910
8496
|
if (recent < earlier) return { direction: "improving", reason: "Fewer warnings in the last recorded runs." };
|
|
@@ -6930,18 +8516,18 @@ function buildGuardHistory(dir) {
|
|
|
6930
8516
|
trend: { direction: "unknown", reason: "No guard history recorded yet." }
|
|
6931
8517
|
};
|
|
6932
8518
|
}
|
|
6933
|
-
const sorted = [...runs].sort((
|
|
8519
|
+
const sorted = [...runs].sort((a2, b2) => a2.generated_at.localeCompare(b2.generated_at));
|
|
6934
8520
|
const threads = resolveDriftThreads(sorted);
|
|
6935
8521
|
const open = threads.filter((t) => t.status === "open").length;
|
|
6936
8522
|
const resolved = threads.filter((t) => t.status === "resolved").length;
|
|
6937
8523
|
const detected = threads.length;
|
|
6938
|
-
const runsWithWarnings = sorted.filter((
|
|
8524
|
+
const runsWithWarnings = sorted.filter((r2) => r2.warnings.length > 0).length;
|
|
6939
8525
|
const hotspotMap = /* @__PURE__ */ new Map();
|
|
6940
8526
|
for (const t of threads) {
|
|
6941
|
-
const
|
|
6942
|
-
hotspotMap.set(
|
|
8527
|
+
const d3 = hotspotDir(t.code_path);
|
|
8528
|
+
hotspotMap.set(d3, (hotspotMap.get(d3) ?? 0) + 1);
|
|
6943
8529
|
}
|
|
6944
|
-
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);
|
|
6945
8531
|
return {
|
|
6946
8532
|
available: true,
|
|
6947
8533
|
total_runs: sorted.length,
|
|
@@ -6965,14 +8551,14 @@ function isBroadGlob(glob) {
|
|
|
6965
8551
|
const prefix = glob.slice(0, -3);
|
|
6966
8552
|
return prefix.length > 0 && prefix.split("/").length <= 2;
|
|
6967
8553
|
}
|
|
6968
|
-
function levelFromRatio(
|
|
6969
|
-
if (
|
|
6970
|
-
if (
|
|
6971
|
-
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";
|
|
6972
8558
|
return "Low";
|
|
6973
8559
|
}
|
|
6974
8560
|
function hasSection(body, re) {
|
|
6975
|
-
return body.split(/\r?\n/).some((
|
|
8561
|
+
return body.split(/\r?\n/).some((l2) => /^#{1,6}\s+/.test(l2) && re.test(l2));
|
|
6976
8562
|
}
|
|
6977
8563
|
function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
6978
8564
|
const resolvedScope = opts.scope ?? "all";
|
|
@@ -7038,7 +8624,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7038
8624
|
} catch {
|
|
7039
8625
|
}
|
|
7040
8626
|
}
|
|
7041
|
-
const ownedCodePaths = [...globCounts.values()].reduce((
|
|
8627
|
+
const ownedCodePaths = [...globCounts.values()].reduce((a2, b2) => a2 + b2, 0);
|
|
7042
8628
|
const broadGlobs = [...globCounts.keys()].filter((g2) => isBroadGlob(g2)).length;
|
|
7043
8629
|
for (const [glob, owners] of globOwners) {
|
|
7044
8630
|
if (owners.length > 1) {
|
|
@@ -7055,7 +8641,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7055
8641
|
} else {
|
|
7056
8642
|
g = { available: false, scope: resolvedScope, scopeReason: "", nodes: 0, edges: 0, quality: "unknown", hints: 0, generatedAt: "" };
|
|
7057
8643
|
}
|
|
7058
|
-
const layerStatus = (name) => exp.layers.find((
|
|
8644
|
+
const layerStatus = (name) => exp.layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
7059
8645
|
const byState = exp.workItems.byState;
|
|
7060
8646
|
const skills = discoverInstalledSkills(dir);
|
|
7061
8647
|
const knowledge_health = {
|
|
@@ -7125,7 +8711,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7125
8711
|
let score_breakdown = null;
|
|
7126
8712
|
if (total > 0) {
|
|
7127
8713
|
const healthPts = [layerStatus("Business"), layerStatus("Product"), layerStatus("Tech"), layerStatus("Delivery")].filter((s) => s !== "Missing").length / 4 * 20;
|
|
7128
|
-
const covAvg = knowledge_coverage.reduce((
|
|
8714
|
+
const covAvg = knowledge_coverage.reduce((a2, c) => a2 + coverageRatio(c.have), 0) / knowledge_coverage.length;
|
|
7129
8715
|
const coveragePts = covAvg * 20;
|
|
7130
8716
|
const ownPts = coverageRatio(withOwnership) * 15;
|
|
7131
8717
|
const traceBlend = (exp.roadmap.candidates > 0 ? exp.roadmap.materialized / exp.roadmap.candidates : 1) * 0.5 + coverageRatio(withOwnership) * 0.5;
|
|
@@ -7153,14 +8739,14 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7153
8739
|
if (!g.available) actions.push("Run `kaddo graph export --scope all` to inspect full traceability.");
|
|
7154
8740
|
else if (g.scope === "active" && g.quality === "empty") actions.push("Run `kaddo impact --scope all` to measure accumulated knowledge impact.");
|
|
7155
8741
|
if (exp.roadmap.remaining > 0) actions.push(`Materialize the ${exp.roadmap.remaining} remaining roadmap candidate(s) with \`kaddo create --from roadmap\`.`);
|
|
7156
|
-
for (const
|
|
8742
|
+
for (const a2 of [
|
|
7157
8743
|
groupedAction(gaps.missing_code_ownership, "Add `code:` ownership to"),
|
|
7158
8744
|
groupedAction(gaps.missing_source, "Add `source`/`source_id` to"),
|
|
7159
8745
|
groupedAction(gaps.missing_initiative, "Add an `initiative` to"),
|
|
7160
8746
|
groupedAction(gaps.missing_acceptance_criteria, "Add Acceptance Criteria to"),
|
|
7161
8747
|
groupedAction(gaps.missing_definition_of_done, "Add a Definition of Done to"),
|
|
7162
8748
|
groupedAction(gaps.missing_validation, "Add a validation (How to test it) section to")
|
|
7163
|
-
]) if (
|
|
8749
|
+
]) if (a2) actions.push(a2);
|
|
7164
8750
|
if (gaps.broad_ownership_globs.length > 0) actions.push(`Narrow ${gaps.broad_ownership_globs.length} broad ownership glob(s) into specific paths.`);
|
|
7165
8751
|
if (g.available && g.hints > 0) actions.push("Review graph hints (`kaddo://graph-hints` or `.kaddo/graph-hints.md`).");
|
|
7166
8752
|
if (skills.length === 0) actions.push("Install reusable skills with `kaddo add skills`.");
|
|
@@ -7224,38 +8810,38 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7224
8810
|
function ratio(have, total) {
|
|
7225
8811
|
return `${have}/${total}`;
|
|
7226
8812
|
}
|
|
7227
|
-
function renderImpactMarkdown(
|
|
8813
|
+
function renderImpactMarkdown(r2) {
|
|
7228
8814
|
const L = [];
|
|
7229
8815
|
L.push("# Kaddo Knowledge Impact Report", "");
|
|
7230
|
-
L.push(`Generated at: ${
|
|
7231
|
-
L.push(`Project: ${
|
|
7232
|
-
L.push(`Scope: ${
|
|
7233
|
-
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`);
|
|
7234
8820
|
else L.push("Knowledge Impact Score: not available");
|
|
7235
|
-
if (
|
|
8821
|
+
if (r2.scope_source === "default") {
|
|
7236
8822
|
L.push("Scope note: Impact reports use `all` by default to measure accumulated knowledge impact.");
|
|
7237
|
-
} else if (
|
|
8823
|
+
} else if (r2.scope === "active" && r2.graph_quality.available === false) {
|
|
7238
8824
|
L.push("Tip: Run `kaddo impact --scope all` to inspect accumulated knowledge impact.");
|
|
7239
8825
|
}
|
|
7240
8826
|
L.push("");
|
|
7241
8827
|
L.push("## Executive Summary", "");
|
|
7242
|
-
for (const s2 of
|
|
8828
|
+
for (const s2 of r2.executive_summary) L.push(`- ${s2}`);
|
|
7243
8829
|
L.push("");
|
|
7244
8830
|
L.push("## Knowledge Health", "");
|
|
7245
|
-
for (const [
|
|
8831
|
+
for (const [k2, v] of Object.entries(r2.knowledge_health)) L.push(`- ${k2}: ${v}`);
|
|
7246
8832
|
L.push("");
|
|
7247
8833
|
L.push("## Knowledge Coverage", "");
|
|
7248
|
-
for (const c of
|
|
8834
|
+
for (const c of r2.knowledge_coverage) L.push(`- ${c.label}: ${ratio(c.have, c.total)}`);
|
|
7249
8835
|
L.push("");
|
|
7250
8836
|
L.push("## Ownership Coverage", "");
|
|
7251
|
-
L.push(`- Coverage: ${
|
|
7252
|
-
L.push(`- Work Items with code ownership: ${
|
|
7253
|
-
L.push(`- Owned code paths: ${
|
|
7254
|
-
L.push(`- Broad globs detected: ${
|
|
7255
|
-
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}`);
|
|
7256
8842
|
L.push("");
|
|
7257
8843
|
L.push("## Traceability", "");
|
|
7258
|
-
const t =
|
|
8844
|
+
const t = r2.traceability;
|
|
7259
8845
|
L.push(`- Roadmap candidates: ${t.roadmap_candidates}`);
|
|
7260
8846
|
L.push(`- Materialized Work Items: ${t.materialized_work_items}`);
|
|
7261
8847
|
L.push(`- Remaining candidates: ${t.remaining_candidates}`);
|
|
@@ -7268,24 +8854,24 @@ function renderImpactMarkdown(r) {
|
|
|
7268
8854
|
if (t.graph_hints !== null) L.push(`- Graph hints: ${t.graph_hints}`);
|
|
7269
8855
|
L.push("");
|
|
7270
8856
|
L.push("## Context Readiness", "");
|
|
7271
|
-
L.push(`Context Readiness: ${
|
|
7272
|
-
if (
|
|
8857
|
+
L.push(`Context Readiness: ${r2.context_readiness.level}`);
|
|
8858
|
+
if (r2.context_readiness.reasons.length > 0) {
|
|
7273
8859
|
L.push("", "Reason:");
|
|
7274
|
-
for (const reason of
|
|
8860
|
+
for (const reason of r2.context_readiness.reasons) L.push(`- ${reason}`);
|
|
7275
8861
|
}
|
|
7276
8862
|
L.push("");
|
|
7277
8863
|
L.push("## Work Item Readiness", "");
|
|
7278
|
-
const
|
|
7279
|
-
L.push(`- Draft: ${
|
|
7280
|
-
L.push(`- Ready: ${
|
|
7281
|
-
L.push(`- In Progress: ${
|
|
7282
|
-
L.push(`- Blocked: ${
|
|
7283
|
-
L.push(`- Completed: ${
|
|
7284
|
-
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}`);
|
|
7285
8871
|
L.push("");
|
|
7286
8872
|
L.push("## Graph Quality", "");
|
|
7287
|
-
if (
|
|
7288
|
-
const gq =
|
|
8873
|
+
if (r2.graph_quality.available) {
|
|
8874
|
+
const gq = r2.graph_quality;
|
|
7289
8875
|
L.push(`- Scope: ${gq.scope}`);
|
|
7290
8876
|
L.push(`- Quality: ${gq.quality}`);
|
|
7291
8877
|
L.push(`- Nodes: ${gq.nodes}`);
|
|
@@ -7298,12 +8884,12 @@ function renderImpactMarkdown(r) {
|
|
|
7298
8884
|
}
|
|
7299
8885
|
} else {
|
|
7300
8886
|
L.push("- Graph data not available.");
|
|
7301
|
-
L.push(`- Tip: ${
|
|
8887
|
+
L.push(`- Tip: ${r2.graph_quality.suggestion}`);
|
|
7302
8888
|
}
|
|
7303
8889
|
L.push("");
|
|
7304
8890
|
L.push("## Guard Activity", "");
|
|
7305
|
-
if (
|
|
7306
|
-
const ga =
|
|
8891
|
+
if (r2.guard_activity.available) {
|
|
8892
|
+
const ga = r2.guard_activity;
|
|
7307
8893
|
L.push("- Guard history: available");
|
|
7308
8894
|
L.push(`- Guard runs recorded: ${ga.runs_recorded}`);
|
|
7309
8895
|
L.push(`- Drift warnings detected: ${ga.detected}`);
|
|
@@ -7312,11 +8898,11 @@ function renderImpactMarkdown(r) {
|
|
|
7312
8898
|
L.push(`- Resolution rate: ${ga.resolution_rate}%`);
|
|
7313
8899
|
} else {
|
|
7314
8900
|
L.push("- Guard history: not available");
|
|
7315
|
-
L.push(`- Note: ${
|
|
8901
|
+
L.push(`- Note: ${r2.guard_activity.note}`);
|
|
7316
8902
|
}
|
|
7317
8903
|
L.push("");
|
|
7318
8904
|
L.push("## Impact Signals", "");
|
|
7319
|
-
const s =
|
|
8905
|
+
const s = r2.impact_signals;
|
|
7320
8906
|
L.push(`- Ambiguity reduction: ${s.ambiguity_reduction}`);
|
|
7321
8907
|
L.push(`- Drift prevention: ${s.drift_prevention}`);
|
|
7322
8908
|
L.push(`- Onboarding support: ${s.onboarding_support}`);
|
|
@@ -7325,7 +8911,7 @@ function renderImpactMarkdown(r) {
|
|
|
7325
8911
|
L.push(`- Maintenance readiness: ${s.maintenance_readiness}`);
|
|
7326
8912
|
L.push("");
|
|
7327
8913
|
L.push("## Actionable Gaps", "");
|
|
7328
|
-
const gp =
|
|
8914
|
+
const gp = r2.actionable_gaps;
|
|
7329
8915
|
const gapSection = (title, items) => {
|
|
7330
8916
|
if (items.length === 0) return;
|
|
7331
8917
|
L.push(`### ${title}`, "");
|
|
@@ -7345,19 +8931,19 @@ function renderImpactMarkdown(r) {
|
|
|
7345
8931
|
gapSection("Work Items missing validation", gp.missing_validation);
|
|
7346
8932
|
if (gp.broad_ownership_globs.length > 0) {
|
|
7347
8933
|
L.push("### Broad ownership globs", "");
|
|
7348
|
-
for (const
|
|
7349
|
-
L.push(`- ${
|
|
7350
|
-
L.push(` - Glob: \`${
|
|
7351
|
-
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}`);
|
|
7352
8938
|
}
|
|
7353
8939
|
L.push("");
|
|
7354
8940
|
}
|
|
7355
8941
|
if (gp.ownership_overlaps.length > 0) {
|
|
7356
8942
|
L.push("### Ownership overlaps", "");
|
|
7357
|
-
for (const
|
|
7358
|
-
L.push(`- \`${
|
|
7359
|
-
L.push(` - Owned by: ${
|
|
7360
|
-
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}`);
|
|
7361
8947
|
}
|
|
7362
8948
|
L.push("");
|
|
7363
8949
|
}
|
|
@@ -7365,28 +8951,28 @@ function renderImpactMarkdown(r) {
|
|
|
7365
8951
|
if (anyGaps === 0) {
|
|
7366
8952
|
L.push("No actionable knowledge gaps detected. \u{1F389}", "");
|
|
7367
8953
|
}
|
|
7368
|
-
if (
|
|
8954
|
+
if (r2.score_breakdown) {
|
|
7369
8955
|
L.push("## Score Breakdown", "");
|
|
7370
|
-
const
|
|
7371
|
-
L.push(`- Knowledge Health: ${
|
|
7372
|
-
L.push(`- Knowledge Coverage: ${
|
|
7373
|
-
L.push(`- Ownership Coverage: ${
|
|
7374
|
-
L.push(`- Traceability: ${
|
|
7375
|
-
L.push(`- Graph Quality: ${
|
|
7376
|
-
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}`);
|
|
7377
8963
|
L.push("");
|
|
7378
8964
|
}
|
|
7379
8965
|
L.push("## Suggested Actions", "");
|
|
7380
|
-
|
|
8966
|
+
r2.suggested_actions.forEach((a2, i) => L.push(`${i + 1}. ${a2}`));
|
|
7381
8967
|
L.push("");
|
|
7382
8968
|
return L.join("\n");
|
|
7383
8969
|
}
|
|
7384
|
-
function serializeImpactJson(
|
|
7385
|
-
return JSON.stringify(
|
|
8970
|
+
function serializeImpactJson(r2) {
|
|
8971
|
+
return JSON.stringify(r2, null, 2) + "\n";
|
|
7386
8972
|
}
|
|
7387
8973
|
|
|
7388
8974
|
// ../cli/src/core/savings.ts
|
|
7389
|
-
import { parse as
|
|
8975
|
+
import { parse as parseYaml7 } from "yaml";
|
|
7390
8976
|
var DEFAULT_ASSUMPTIONS = {
|
|
7391
8977
|
currency: "USD",
|
|
7392
8978
|
hourly_cost: 40,
|
|
@@ -7404,21 +8990,21 @@ function loadAssumptions(dir) {
|
|
|
7404
8990
|
const p = join(dir, SAVINGS_PATH);
|
|
7405
8991
|
if (!exists(p)) return { assumptions: { ...DEFAULT_ASSUMPTIONS }, source: "default" };
|
|
7406
8992
|
try {
|
|
7407
|
-
const raw =
|
|
7408
|
-
const
|
|
8993
|
+
const raw = parseYaml7(readFile(p));
|
|
8994
|
+
const a2 = raw?.assumptions ?? {};
|
|
7409
8995
|
const t = raw?.team ?? {};
|
|
7410
|
-
const num = (v,
|
|
8996
|
+
const num = (v, d3) => typeof v === "number" && Number.isFinite(v) ? v : d3;
|
|
7411
8997
|
return {
|
|
7412
8998
|
source: "file",
|
|
7413
8999
|
assumptions: {
|
|
7414
9000
|
currency: raw?.currency ?? DEFAULT_ASSUMPTIONS.currency,
|
|
7415
9001
|
hourly_cost: num(raw?.hourly_cost, DEFAULT_ASSUMPTIONS.hourly_cost),
|
|
7416
|
-
context_preparation_minutes_saved_per_work_item: num(
|
|
7417
|
-
rework_hours_avoided_per_resolved_drift: num(
|
|
7418
|
-
onboarding_hours_saved_per_new_contributor: num(
|
|
7419
|
-
review_minutes_saved_per_work_item_with_ownership: num(
|
|
7420
|
-
clarification_minutes_saved_per_ready_work_item: num(
|
|
7421
|
-
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),
|
|
7422
9008
|
expected_new_contributors_per_month: num(t.expected_new_contributors_per_month, DEFAULT_ASSUMPTIONS.expected_new_contributors_per_month),
|
|
7423
9009
|
expected_work_items_per_month: num(t.expected_work_items_per_month, DEFAULT_ASSUMPTIONS.expected_work_items_per_month)
|
|
7424
9010
|
}
|
|
@@ -7431,12 +9017,12 @@ var READINESS_MULT = { Low: 0.25, Medium: 0.5, High: 0.75, "Very High": 1 };
|
|
|
7431
9017
|
var GRAPH_MULT = { empty: 0, sparse: 0.25, partial: 0.6, good: 1, unknown: 0 };
|
|
7432
9018
|
var round2 = (n) => Math.round(n * 100) / 100;
|
|
7433
9019
|
function parseRatioNumerator(s) {
|
|
7434
|
-
const
|
|
7435
|
-
return
|
|
9020
|
+
const m2 = s.match(/^(\d+)/);
|
|
9021
|
+
return m2 ? Number(m2[1]) : 0;
|
|
7436
9022
|
}
|
|
7437
9023
|
var SAVINGS_DISCLAIMER = "These are evidence-based estimates, not exact ROI. Adjust assumptions with real team data.";
|
|
7438
9024
|
function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
7439
|
-
const { assumptions:
|
|
9025
|
+
const { assumptions: a2, source } = loadAssumptions(dir);
|
|
7440
9026
|
const impact = buildImpactReport(dir, { scope: opts.scope, scopeSource: opts.scopeSource }, now);
|
|
7441
9027
|
const completed = impact.traceability.completed_work_items;
|
|
7442
9028
|
const wiWithOwnership = parseRatioNumerator(impact.traceability.work_items_connected_to_code);
|
|
@@ -7444,13 +9030,13 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7444
9030
|
const wiWithAcceptance = acceptanceCov?.have ?? 0;
|
|
7445
9031
|
const graphQuality = impact.graph_quality.available ? impact.graph_quality.quality : "unknown";
|
|
7446
9032
|
const readiness = impact.context_readiness.level;
|
|
7447
|
-
const ctxPrepH = round2(completed *
|
|
7448
|
-
const reviewH = round2(wiWithOwnership *
|
|
7449
|
-
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);
|
|
7450
9036
|
const readinessMult = READINESS_MULT[readiness] ?? 0.5;
|
|
7451
|
-
const onboardH = round2(
|
|
9037
|
+
const onboardH = round2(a2.expected_new_contributors_per_month * a2.onboarding_hours_saved_per_new_contributor * readinessMult);
|
|
7452
9038
|
const graphMult = GRAPH_MULT[graphQuality] ?? 0;
|
|
7453
|
-
const archH = round2(
|
|
9039
|
+
const archH = round2(a2.architecture_discovery_hours_saved_when_graph_good * graphMult);
|
|
7454
9040
|
const guard = buildGuardHistory(dir);
|
|
7455
9041
|
let driftSavings;
|
|
7456
9042
|
if (!guard.available) {
|
|
@@ -7458,19 +9044,19 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7458
9044
|
} else if (guard.resolved > 0) {
|
|
7459
9045
|
driftSavings = {
|
|
7460
9046
|
available: true,
|
|
7461
|
-
hours: round2(guard.resolved *
|
|
7462
|
-
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`
|
|
7463
9049
|
};
|
|
7464
9050
|
} else {
|
|
7465
9051
|
driftSavings = {
|
|
7466
9052
|
available: true,
|
|
7467
9053
|
hours: 0,
|
|
7468
|
-
formula: `0 resolved drift warnings \xD7 ${
|
|
9054
|
+
formula: `0 resolved drift warnings \xD7 ${a2.rework_hours_avoided_per_resolved_drift} h`,
|
|
7469
9055
|
reason: "Guard history exists, but no resolved drift warnings have been recorded yet."
|
|
7470
9056
|
};
|
|
7471
9057
|
}
|
|
7472
9058
|
const totalHours = round2(ctxPrepH + reviewH + clarH + onboardH + archH + driftSavings.hours);
|
|
7473
|
-
const totalValue = Math.round(totalHours *
|
|
9059
|
+
const totalValue = Math.round(totalHours * a2.hourly_cost);
|
|
7474
9060
|
const reasons = [];
|
|
7475
9061
|
let level;
|
|
7476
9062
|
if (impact.score === null || impact.score < 60 || graphQuality === "empty") {
|
|
@@ -7508,17 +9094,17 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7508
9094
|
generated_at: now.toISOString(),
|
|
7509
9095
|
project: impact.project,
|
|
7510
9096
|
scope: impact.scope,
|
|
7511
|
-
currency:
|
|
9097
|
+
currency: a2.currency,
|
|
7512
9098
|
disclaimer: SAVINGS_DISCLAIMER,
|
|
7513
9099
|
assumptions_source: source,
|
|
7514
9100
|
assumptions: {
|
|
7515
|
-
hourly_cost:
|
|
7516
|
-
context_preparation_minutes_saved_per_work_item:
|
|
7517
|
-
review_minutes_saved_per_work_item_with_ownership:
|
|
7518
|
-
clarification_minutes_saved_per_ready_work_item:
|
|
7519
|
-
onboarding_hours_saved_per_new_contributor:
|
|
7520
|
-
expected_new_contributors_per_month:
|
|
7521
|
-
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
|
|
7522
9108
|
},
|
|
7523
9109
|
evidence: {
|
|
7524
9110
|
knowledge_impact_score: impact.score,
|
|
@@ -7534,45 +9120,45 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
7534
9120
|
resolved_drift_warnings: guard.resolved
|
|
7535
9121
|
},
|
|
7536
9122
|
estimated_savings: {
|
|
7537
|
-
context_preparation: { hours: ctxPrepH, formula: `${completed} Work Items \xD7 ${
|
|
7538
|
-
review_effort: { hours: reviewH, formula: `${wiWithOwnership} Work Items with ownership \xD7 ${
|
|
7539
|
-
clarification_reduction: { hours: clarH, formula: `${wiWithAcceptance} Work Items with Acceptance Criteria \xD7 ${
|
|
7540
|
-
onboarding: { hours: onboardH, formula: `${
|
|
7541
|
-
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` },
|
|
7542
9128
|
drift_prevention: driftSavings
|
|
7543
9129
|
},
|
|
7544
|
-
total: { estimated_hours_saved: totalHours, estimated_value: totalValue, currency:
|
|
9130
|
+
total: { estimated_hours_saved: totalHours, estimated_value: totalValue, currency: a2.currency },
|
|
7545
9131
|
confidence: { level, reasons },
|
|
7546
9132
|
suggested_actions: actions
|
|
7547
9133
|
};
|
|
7548
9134
|
}
|
|
7549
|
-
function renderSavingsMarkdown(
|
|
9135
|
+
function renderSavingsMarkdown(r2) {
|
|
7550
9136
|
const L = [];
|
|
7551
9137
|
L.push("# Kaddo Estimated Savings Report", "");
|
|
7552
|
-
L.push(`Generated at: ${
|
|
7553
|
-
L.push(`Project: ${
|
|
7554
|
-
L.push(`Scope: ${
|
|
7555
|
-
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}`);
|
|
7556
9142
|
L.push("");
|
|
7557
9143
|
L.push("## Disclaimer", "");
|
|
7558
|
-
L.push(
|
|
9144
|
+
L.push(r2.disclaimer, "");
|
|
7559
9145
|
L.push("## Executive Summary", "");
|
|
7560
|
-
L.push(`- Estimated time saved: ${
|
|
7561
|
-
L.push(`- Estimated value: ${
|
|
7562
|
-
L.push(`- Confidence: ${
|
|
7563
|
-
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.");
|
|
7564
9150
|
L.push("");
|
|
7565
9151
|
L.push("## Assumptions", "");
|
|
7566
|
-
L.push(`- Hourly cost: ${
|
|
7567
|
-
L.push(`- Context preparation saved per Work Item: ${
|
|
7568
|
-
L.push(`- Review saved per Work Item with ownership: ${
|
|
7569
|
-
L.push(`- Clarification saved per Work Item with acceptance criteria: ${
|
|
7570
|
-
L.push(`- Onboarding saved per new contributor: ${
|
|
7571
|
-
L.push(`- Expected new contributors per month: ${
|
|
7572
|
-
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`);
|
|
7573
9159
|
L.push("");
|
|
7574
9160
|
L.push("## Evidence Used", "");
|
|
7575
|
-
const e =
|
|
9161
|
+
const e = r2.evidence;
|
|
7576
9162
|
L.push(`- Knowledge Impact Score: ${e.knowledge_impact_score ?? "not available"}${e.knowledge_impact_score !== null ? "/100" : ""}`);
|
|
7577
9163
|
L.push(`- Completed Work Items: ${e.completed_work_items}`);
|
|
7578
9164
|
L.push(`- Ownership coverage: ${e.ownership_coverage_percent}%`);
|
|
@@ -7590,11 +9176,11 @@ function renderSavingsMarkdown(r) {
|
|
|
7590
9176
|
}
|
|
7591
9177
|
L.push("");
|
|
7592
9178
|
L.push("## Estimated Savings", "");
|
|
7593
|
-
const s =
|
|
7594
|
-
const line = (title,
|
|
9179
|
+
const s = r2.estimated_savings;
|
|
9180
|
+
const line = (title, l2) => {
|
|
7595
9181
|
L.push(`### ${title}`, "");
|
|
7596
|
-
L.push(`- Formula: ${
|
|
7597
|
-
L.push(`- Estimated: ${
|
|
9182
|
+
L.push(`- Formula: ${l2.formula}`);
|
|
9183
|
+
L.push(`- Estimated: ${l2.hours} h`, "");
|
|
7598
9184
|
};
|
|
7599
9185
|
line("Context Preparation", s.context_preparation);
|
|
7600
9186
|
line("Review Effort", s.review_effort);
|
|
@@ -7612,31 +9198,31 @@ function renderSavingsMarkdown(r) {
|
|
|
7612
9198
|
L.push(`- Reason: ${s.drift_prevention.reason}`, "");
|
|
7613
9199
|
}
|
|
7614
9200
|
L.push("## Total", "");
|
|
7615
|
-
L.push(`- Estimated time saved: ${
|
|
7616
|
-
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}`);
|
|
7617
9203
|
L.push("");
|
|
7618
9204
|
L.push("## Confidence", "");
|
|
7619
|
-
L.push(`Confidence: ${
|
|
7620
|
-
for (const reason of
|
|
9205
|
+
L.push(`Confidence: ${r2.confidence.level}`, "", "Reason:");
|
|
9206
|
+
for (const reason of r2.confidence.reasons) L.push(`- ${reason}`);
|
|
7621
9207
|
L.push("");
|
|
7622
9208
|
L.push("## Suggested Actions", "");
|
|
7623
|
-
|
|
9209
|
+
r2.suggested_actions.forEach((act, i) => L.push(`${i + 1}. ${act}`));
|
|
7624
9210
|
L.push("");
|
|
7625
9211
|
return L.join("\n");
|
|
7626
9212
|
}
|
|
7627
|
-
function serializeSavingsJson(
|
|
7628
|
-
return JSON.stringify(
|
|
9213
|
+
function serializeSavingsJson(r2) {
|
|
9214
|
+
return JSON.stringify(r2, null, 2) + "\n";
|
|
7629
9215
|
}
|
|
7630
9216
|
|
|
7631
9217
|
// ../cli/src/core/drift-report.ts
|
|
7632
9218
|
function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
7633
|
-
const
|
|
9219
|
+
const h2 = buildGuardHistory(dir);
|
|
7634
9220
|
const project = loadConfig(dir)?.project.name ?? "unknown";
|
|
7635
9221
|
const actions = [];
|
|
7636
|
-
if (!
|
|
9222
|
+
if (!h2.available) {
|
|
7637
9223
|
actions.push("Run `kaddo guard --record` to start recording guard history.");
|
|
7638
9224
|
} else {
|
|
7639
|
-
if (
|
|
9225
|
+
if (h2.open > 0) actions.push("Review open drift warnings and update related Work Items or ownership.");
|
|
7640
9226
|
actions.push("Run `kaddo guard --record` before important commits.");
|
|
7641
9227
|
actions.push("Use this report to calibrate estimated drift-prevention savings.");
|
|
7642
9228
|
}
|
|
@@ -7644,55 +9230,55 @@ function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
7644
9230
|
generated_at: now.toISOString(),
|
|
7645
9231
|
project,
|
|
7646
9232
|
guard_history: {
|
|
7647
|
-
available:
|
|
7648
|
-
total_runs:
|
|
7649
|
-
first_run:
|
|
7650
|
-
last_run:
|
|
7651
|
-
runs_with_warnings:
|
|
7652
|
-
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
|
|
7653
9239
|
},
|
|
7654
|
-
drift_warnings: { detected:
|
|
7655
|
-
hotspots:
|
|
7656
|
-
trend:
|
|
7657
|
-
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,
|
|
7658
9244
|
suggested_actions: actions
|
|
7659
9245
|
};
|
|
7660
9246
|
}
|
|
7661
|
-
function renderDriftMarkdown(
|
|
9247
|
+
function renderDriftMarkdown(r2) {
|
|
7662
9248
|
const L = [];
|
|
7663
9249
|
L.push("# Kaddo Drift Trend Report", "");
|
|
7664
|
-
L.push(`Generated at: ${
|
|
7665
|
-
L.push(`Project: ${
|
|
9250
|
+
L.push(`Generated at: ${r2.generated_at}`);
|
|
9251
|
+
L.push(`Project: ${r2.project}`);
|
|
7666
9252
|
L.push("");
|
|
7667
|
-
if (!
|
|
9253
|
+
if (!r2.guard_history.available) {
|
|
7668
9254
|
L.push("## Guard History", "");
|
|
7669
9255
|
L.push("No guard history recorded yet.");
|
|
7670
9256
|
L.push("");
|
|
7671
9257
|
L.push("Run `kaddo guard --record` to start recording drift evidence.");
|
|
7672
9258
|
L.push("");
|
|
7673
9259
|
L.push("## Suggested Actions", "");
|
|
7674
|
-
|
|
9260
|
+
r2.suggested_actions.forEach((a2, i) => L.push(`${i + 1}. ${a2}`));
|
|
7675
9261
|
L.push("");
|
|
7676
9262
|
return L.join("\n");
|
|
7677
9263
|
}
|
|
7678
|
-
const
|
|
9264
|
+
const w3 = r2.drift_warnings;
|
|
7679
9265
|
L.push("## Executive Summary", "");
|
|
7680
|
-
L.push(`- Guard runs recorded: ${
|
|
7681
|
-
L.push(`- Drift warnings detected: ${
|
|
7682
|
-
L.push(`- Open warnings: ${
|
|
7683
|
-
L.push(`- Resolved warnings: ${
|
|
7684
|
-
L.push(`- Resolution rate: ${
|
|
7685
|
-
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}`);
|
|
7686
9272
|
L.push("");
|
|
7687
9273
|
L.push("## Guard History", "");
|
|
7688
|
-
L.push(`- First run: ${
|
|
7689
|
-
L.push(`- Last run: ${
|
|
7690
|
-
L.push(`- Runs with warnings: ${
|
|
7691
|
-
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}`);
|
|
7692
9278
|
L.push("");
|
|
7693
9279
|
L.push("## Drift Warnings", "");
|
|
7694
|
-
const open =
|
|
7695
|
-
const resolved =
|
|
9280
|
+
const open = r2.threads.filter((t) => t.status === "open");
|
|
9281
|
+
const resolved = r2.threads.filter((t) => t.status === "resolved");
|
|
7696
9282
|
L.push("### Open", "");
|
|
7697
9283
|
if (open.length === 0) L.push("_None._", "");
|
|
7698
9284
|
for (const t of open) {
|
|
@@ -7714,28 +9300,28 @@ function renderDriftMarkdown(r) {
|
|
|
7714
9300
|
}
|
|
7715
9301
|
L.push("");
|
|
7716
9302
|
L.push("## Hotspots", "");
|
|
7717
|
-
if (
|
|
7718
|
-
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)`);
|
|
7719
9305
|
L.push("");
|
|
7720
9306
|
L.push("## Trend", "");
|
|
7721
|
-
L.push(`- Recent direction: ${
|
|
7722
|
-
L.push(`- Reason: ${
|
|
9307
|
+
L.push(`- Recent direction: ${r2.trend.direction}`);
|
|
9308
|
+
L.push(`- Reason: ${r2.trend.reason}`);
|
|
7723
9309
|
L.push("");
|
|
7724
9310
|
L.push("## Suggested Actions", "");
|
|
7725
|
-
|
|
9311
|
+
r2.suggested_actions.forEach((a2, i) => L.push(`${i + 1}. ${a2}`));
|
|
7726
9312
|
L.push("");
|
|
7727
9313
|
return L.join("\n");
|
|
7728
9314
|
}
|
|
7729
|
-
function serializeDriftJson(
|
|
9315
|
+
function serializeDriftJson(r2) {
|
|
7730
9316
|
const out = {
|
|
7731
|
-
generated_at:
|
|
7732
|
-
project:
|
|
7733
|
-
guard_history:
|
|
7734
|
-
drift_warnings:
|
|
7735
|
-
hotspots:
|
|
7736
|
-
trend:
|
|
7737
|
-
threads:
|
|
7738
|
-
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
|
|
7739
9325
|
};
|
|
7740
9326
|
return JSON.stringify(out, null, 2) + "\n";
|
|
7741
9327
|
}
|
|
@@ -7765,7 +9351,7 @@ function parseSource(data) {
|
|
|
7765
9351
|
}
|
|
7766
9352
|
var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["draft", "ready", "in-progress", "blocked"]);
|
|
7767
9353
|
function strArray(v) {
|
|
7768
|
-
return Array.isArray(v) ? v.map((
|
|
9354
|
+
return Array.isArray(v) ? v.map((x2) => String(x2)).filter(Boolean) : [];
|
|
7769
9355
|
}
|
|
7770
9356
|
function lifecycleOf(data, relPath) {
|
|
7771
9357
|
const status = String(data.status ?? "").trim();
|
|
@@ -7817,7 +9403,7 @@ function listWorkItems(root) {
|
|
|
7817
9403
|
readiness
|
|
7818
9404
|
});
|
|
7819
9405
|
}
|
|
7820
|
-
return items.sort((
|
|
9406
|
+
return items.sort((a2, b2) => a2.id.localeCompare(b2.id));
|
|
7821
9407
|
}
|
|
7822
9408
|
function assessReadiness(data, content, code, domains, source) {
|
|
7823
9409
|
const body = content.trim();
|
|
@@ -7844,12 +9430,12 @@ function assessReadiness(data, content, code, domains, source) {
|
|
|
7844
9430
|
}
|
|
7845
9431
|
|
|
7846
9432
|
// src/resources.ts
|
|
7847
|
-
function
|
|
9433
|
+
function text2(uri, body, mimeType = "text/markdown") {
|
|
7848
9434
|
return [{ uri, text: body, mimeType }];
|
|
7849
9435
|
}
|
|
7850
9436
|
function fileOrHint(root, uri, rel, hint, mimeType = "text/markdown") {
|
|
7851
9437
|
const body = readText(root, rel);
|
|
7852
|
-
return
|
|
9438
|
+
return text2(uri, body ?? hint, body ? mimeType : "text/plain");
|
|
7853
9439
|
}
|
|
7854
9440
|
var RESOURCES = [
|
|
7855
9441
|
{
|
|
@@ -7897,7 +9483,7 @@ var RESOURCES = [
|
|
|
7897
9483
|
const json = readText(root, ".kaddo/graph.json");
|
|
7898
9484
|
const mmd = readText(root, ".kaddo/graph.mmd");
|
|
7899
9485
|
if (!json && !mmd) {
|
|
7900
|
-
return
|
|
9486
|
+
return text2("kaddo://graph", "Knowledge graph not found. Run `kaddo graph export` first.", "text/plain");
|
|
7901
9487
|
}
|
|
7902
9488
|
const parts = [];
|
|
7903
9489
|
if (json) parts.push({ uri: "kaddo://graph", text: json, mimeType: "application/json" });
|
|
@@ -7914,7 +9500,7 @@ var RESOURCES = [
|
|
|
7914
9500
|
const md = readText(root, ".kaddo/graph-hints.md");
|
|
7915
9501
|
const json = readText(root, ".kaddo/graph-hints.json");
|
|
7916
9502
|
if (!md && !json) {
|
|
7917
|
-
return
|
|
9503
|
+
return text2("kaddo://graph-hints", "Graph hints not found. Run `kaddo graph export` first.", "text/plain");
|
|
7918
9504
|
}
|
|
7919
9505
|
const parts = [];
|
|
7920
9506
|
if (md) parts.push({ uri: "kaddo://graph-hints", text: md, mimeType: "text/markdown" });
|
|
@@ -7929,7 +9515,7 @@ var RESOURCES = [
|
|
|
7929
9515
|
mimeType: "application/json",
|
|
7930
9516
|
read: (root) => {
|
|
7931
9517
|
if (!hasKnowledge(root)) {
|
|
7932
|
-
return
|
|
9518
|
+
return text2("kaddo://work-items", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
7933
9519
|
}
|
|
7934
9520
|
return [
|
|
7935
9521
|
{
|
|
@@ -8000,7 +9586,7 @@ var RESOURCES = [
|
|
|
8000
9586
|
const saved = readText(root, ".kaddo/reports/impact-report.md");
|
|
8001
9587
|
if (saved) return [{ uri: "kaddo://impact-report", text: saved, mimeType: "text/markdown" }];
|
|
8002
9588
|
if (!hasKnowledge(root)) {
|
|
8003
|
-
return
|
|
9589
|
+
return text2("kaddo://impact-report", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8004
9590
|
}
|
|
8005
9591
|
return [{ uri: "kaddo://impact-report", text: renderImpactMarkdown(buildImpactReport(root, { scope: "all", scopeSource: "default" })), mimeType: "text/markdown" }];
|
|
8006
9592
|
}
|
|
@@ -8014,7 +9600,7 @@ var RESOURCES = [
|
|
|
8014
9600
|
const saved = readText(root, ".kaddo/reports/savings-report.md");
|
|
8015
9601
|
if (saved) return [{ uri: "kaddo://savings-report", text: saved, mimeType: "text/markdown" }];
|
|
8016
9602
|
if (!hasKnowledge(root)) {
|
|
8017
|
-
return
|
|
9603
|
+
return text2("kaddo://savings-report", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8018
9604
|
}
|
|
8019
9605
|
return [{ uri: "kaddo://savings-report", text: renderSavingsMarkdown(buildSavingsReport(root, { scope: "all", scopeSource: "default" })), mimeType: "text/markdown" }];
|
|
8020
9606
|
}
|
|
@@ -8038,7 +9624,7 @@ var RESOURCES = [
|
|
|
8038
9624
|
read: (root) => {
|
|
8039
9625
|
const runs = readText(root, ".kaddo/history/guard-runs.jsonl");
|
|
8040
9626
|
if (runs === null) {
|
|
8041
|
-
return
|
|
9627
|
+
return text2("kaddo://guard-history", "No guard history recorded yet. Run `kaddo guard --record`.", "text/plain");
|
|
8042
9628
|
}
|
|
8043
9629
|
return [{ uri: "kaddo://guard-history", text: runs, mimeType: "application/jsonl" }];
|
|
8044
9630
|
}
|
|
@@ -8050,10 +9636,10 @@ var RESOURCES = [
|
|
|
8050
9636
|
mimeType: "application/json",
|
|
8051
9637
|
read: (root) => {
|
|
8052
9638
|
if (!hasKnowledge(root)) {
|
|
8053
|
-
return
|
|
9639
|
+
return text2("kaddo://open-questions", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8054
9640
|
}
|
|
8055
|
-
const
|
|
8056
|
-
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" }];
|
|
8057
9643
|
}
|
|
8058
9644
|
},
|
|
8059
9645
|
{
|
|
@@ -8063,7 +9649,7 @@ var RESOURCES = [
|
|
|
8063
9649
|
mimeType: "application/json",
|
|
8064
9650
|
read: (root) => {
|
|
8065
9651
|
if (!hasKnowledge(root)) {
|
|
8066
|
-
return
|
|
9652
|
+
return text2("kaddo://roadmap-readiness", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8067
9653
|
}
|
|
8068
9654
|
return [{ uri: "kaddo://roadmap-readiness", text: JSON.stringify(roadmapReadinessSummary(root), null, 2), mimeType: "application/json" }];
|
|
8069
9655
|
}
|
|
@@ -8075,7 +9661,7 @@ var RESOURCES = [
|
|
|
8075
9661
|
mimeType: "application/json",
|
|
8076
9662
|
read: (root) => {
|
|
8077
9663
|
if (!hasKnowledge(root)) {
|
|
8078
|
-
return
|
|
9664
|
+
return text2("kaddo://tech-decisions", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8079
9665
|
}
|
|
8080
9666
|
return [{ uri: "kaddo://tech-decisions", text: JSON.stringify(buildTechDecisions(root), null, 2), mimeType: "application/json" }];
|
|
8081
9667
|
}
|
|
@@ -8087,7 +9673,7 @@ var RESOURCES = [
|
|
|
8087
9673
|
mimeType: "application/json",
|
|
8088
9674
|
read: (root) => {
|
|
8089
9675
|
if (!hasKnowledge(root)) {
|
|
8090
|
-
return
|
|
9676
|
+
return text2("kaddo://installed-assets", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8091
9677
|
}
|
|
8092
9678
|
return [{ uri: "kaddo://installed-assets", text: JSON.stringify(installedAssetsSummary(root), null, 2), mimeType: "application/json" }];
|
|
8093
9679
|
}
|
|
@@ -8099,7 +9685,7 @@ var RESOURCES = [
|
|
|
8099
9685
|
mimeType: "application/json",
|
|
8100
9686
|
read: (root) => {
|
|
8101
9687
|
if (!hasKnowledge(root)) {
|
|
8102
|
-
return
|
|
9688
|
+
return text2("kaddo://roadmap-quality", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8103
9689
|
}
|
|
8104
9690
|
return [{ uri: "kaddo://roadmap-quality", text: JSON.stringify(buildRoadmapQuality(root), null, 2), mimeType: "application/json" }];
|
|
8105
9691
|
}
|
|
@@ -8111,7 +9697,7 @@ var RESOURCES = [
|
|
|
8111
9697
|
mimeType: "application/json",
|
|
8112
9698
|
read: (root) => {
|
|
8113
9699
|
if (!hasKnowledge(root)) {
|
|
8114
|
-
return
|
|
9700
|
+
return text2("kaddo://work-item-candidates", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8115
9701
|
}
|
|
8116
9702
|
const md = readText(root, "knowledge/delivery/roadmap.md");
|
|
8117
9703
|
const candidates = md ? parseRoadmapCandidates(md) : [];
|
|
@@ -8125,7 +9711,7 @@ var RESOURCES = [
|
|
|
8125
9711
|
mimeType: "application/json",
|
|
8126
9712
|
read: (root) => {
|
|
8127
9713
|
if (!hasKnowledge(root)) {
|
|
8128
|
-
return
|
|
9714
|
+
return text2("kaddo://next-step", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8129
9715
|
}
|
|
8130
9716
|
const nextStepRecommendation = resolveNextStep(root);
|
|
8131
9717
|
const deliveryState = { ...buildDeliveryState(root), phase: nextStepRecommendation.phase };
|
|
@@ -8139,7 +9725,7 @@ var RESOURCES = [
|
|
|
8139
9725
|
mimeType: "application/json",
|
|
8140
9726
|
read: (root) => {
|
|
8141
9727
|
if (!hasKnowledge(root)) {
|
|
8142
|
-
return
|
|
9728
|
+
return text2("kaddo://project-route", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
8143
9729
|
}
|
|
8144
9730
|
return [{ uri: "kaddo://project-route", text: JSON.stringify(buildProjectRoute(root), null, 2), mimeType: "application/json" }];
|
|
8145
9731
|
}
|
|
@@ -8160,7 +9746,7 @@ var RESOURCES = [
|
|
|
8160
9746
|
} catch {
|
|
8161
9747
|
}
|
|
8162
9748
|
}
|
|
8163
|
-
return
|
|
9749
|
+
return text2("kaddo://scan-signals", "Scan signals not found. Run `kaddo scan` first.", "text/plain");
|
|
8164
9750
|
}
|
|
8165
9751
|
}
|
|
8166
9752
|
];
|
|
@@ -8177,11 +9763,11 @@ function recommendedInputs(name) {
|
|
|
8177
9763
|
return [".kaddo/context-pack.md", ...EXTRA_INPUTS[name] ?? []];
|
|
8178
9764
|
}
|
|
8179
9765
|
function listPrompts(root) {
|
|
8180
|
-
return listAgents(root).map((
|
|
8181
|
-
name:
|
|
8182
|
-
description:
|
|
9766
|
+
return listAgents(root).map((a2) => ({
|
|
9767
|
+
name: a2.name,
|
|
9768
|
+
description: a2.description || `Kaddo ${a2.name}`,
|
|
8183
9769
|
content: "",
|
|
8184
|
-
recommended_inputs: recommendedInputs(
|
|
9770
|
+
recommended_inputs: recommendedInputs(a2.name)
|
|
8185
9771
|
}));
|
|
8186
9772
|
}
|
|
8187
9773
|
function getPrompt(root, name) {
|
|
@@ -8206,7 +9792,7 @@ function projectStatus(root) {
|
|
|
8206
9792
|
if (!explain) {
|
|
8207
9793
|
return fail("Project status needs `.kaddo/explain.json`. Run `kaddo explain` first.");
|
|
8208
9794
|
}
|
|
8209
|
-
const maturity = (explain.layers ?? []).map((
|
|
9795
|
+
const maturity = (explain.layers ?? []).map((l2) => `${l2.layer}: ${l2.status}`);
|
|
8210
9796
|
return ok({
|
|
8211
9797
|
project: explain.project?.name ?? "unknown",
|
|
8212
9798
|
state: explain.project?.state ?? "unknown",
|
|
@@ -8231,19 +9817,19 @@ function projectStatus(root) {
|
|
|
8231
9817
|
}
|
|
8232
9818
|
function listWorkItemsTool(root, filter = {}) {
|
|
8233
9819
|
let items = listWorkItems(root);
|
|
8234
|
-
if (filter.status) items = items.filter((
|
|
8235
|
-
if (filter.type) items = items.filter((
|
|
8236
|
-
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);
|
|
8237
9823
|
return ok(items);
|
|
8238
9824
|
}
|
|
8239
9825
|
function getWorkItem(root, id) {
|
|
8240
|
-
const item = listWorkItems(root).find((
|
|
9826
|
+
const item = listWorkItems(root).find((w3) => w3.id === id);
|
|
8241
9827
|
if (!item) return fail(`Work Item "${id}" not found.`);
|
|
8242
9828
|
const content = readText(root, item.path);
|
|
8243
9829
|
return ok({ ...item, content: content ?? "" });
|
|
8244
9830
|
}
|
|
8245
9831
|
function markWorkItemReady(root, id, confirm) {
|
|
8246
|
-
const item = listWorkItems(root).find((
|
|
9832
|
+
const item = listWorkItems(root).find((w3) => w3.id === id);
|
|
8247
9833
|
if (!item) return fail(`Work Item "${id}" not found.`);
|
|
8248
9834
|
if (item.status === "ready") {
|
|
8249
9835
|
return ok({ status: "already_ready", id: item.id, message: `Work Item ${item.id} is already ready.` });
|
|
@@ -8326,9 +9912,9 @@ function listGraphHints(root, filter = {}) {
|
|
|
8326
9912
|
const report = readJson(root, ".kaddo/graph-hints.json");
|
|
8327
9913
|
if (!report) return fail("Graph hints not found. Run `kaddo graph export` first.");
|
|
8328
9914
|
let hints = Array.isArray(report.hints) ? report.hints : [];
|
|
8329
|
-
if (filter.artifact_type) hints = hints.filter((
|
|
8330
|
-
if (filter.severity) hints = hints.filter((
|
|
8331
|
-
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");
|
|
8332
9918
|
return ok({
|
|
8333
9919
|
scope: report.scope ?? "active",
|
|
8334
9920
|
scope_reason: report.scope_reason ?? "",
|
|
@@ -8389,23 +9975,23 @@ var OPERATING_RULES = [
|
|
|
8389
9975
|
"After significant changes run `kaddo scan`, `kaddo owners suggest` and `kaddo guard`, and update the affected knowledge (ADR / capabilities / current-state).",
|
|
8390
9976
|
"Kaddo itself never calls an LLM and never runs git \u2014 every git action is the human\u2019s."
|
|
8391
9977
|
];
|
|
8392
|
-
function toContextWorkItem(
|
|
9978
|
+
function toContextWorkItem(a2) {
|
|
8393
9979
|
return {
|
|
8394
|
-
id:
|
|
8395
|
-
type:
|
|
8396
|
-
title:
|
|
8397
|
-
status:
|
|
8398
|
-
lifecycle: lifecycleStateOf({ status:
|
|
8399
|
-
knowledgeLevel:
|
|
8400
|
-
domains:
|
|
8401
|
-
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)
|
|
8402
9988
|
};
|
|
8403
9989
|
}
|
|
8404
|
-
function toContextArtifact(
|
|
8405
|
-
return { id:
|
|
9990
|
+
function toContextArtifact(a2) {
|
|
9991
|
+
return { id: a2.id, type: a2.type, title: a2.title, summary: a2.summary, codeGlobs: a2.codeGlobs };
|
|
8406
9992
|
}
|
|
8407
|
-
function isDeliveryWorkItem(
|
|
8408
|
-
return
|
|
9993
|
+
function isDeliveryWorkItem(a2) {
|
|
9994
|
+
return a2.filePath.replace(/\\/g, "/").includes("/delivery/work-items/") && Boolean(a2.type);
|
|
8409
9995
|
}
|
|
8410
9996
|
function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
8411
9997
|
const missing = [];
|
|
@@ -8428,7 +10014,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8428
10014
|
}
|
|
8429
10015
|
const allArtifacts = discoverKnowledge(dir);
|
|
8430
10016
|
const workItems = allArtifacts.filter(
|
|
8431
|
-
(
|
|
10017
|
+
(a2) => isDeliveryWorkItem(a2) && isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
|
|
8432
10018
|
);
|
|
8433
10019
|
if (workItems.length === 0) {
|
|
8434
10020
|
missing.push("No work items found.");
|
|
@@ -8436,15 +10022,15 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8436
10022
|
const state = config.project.state;
|
|
8437
10023
|
const roadmapPath = join(dir, ARCH_DIR3, "delivery", "roadmap.md");
|
|
8438
10024
|
const materialized = allArtifacts.filter(
|
|
8439
|
-
(
|
|
10025
|
+
(a2) => a2.filePath.replace(/\\/g, "/").includes("/delivery/work-items/") && Boolean(a2.type)
|
|
8440
10026
|
).length;
|
|
8441
10027
|
const roadmap = roadmapStats(exists(roadmapPath) ? readFile(roadmapPath) : null, materialized);
|
|
8442
10028
|
const deliveryMix = {};
|
|
8443
|
-
for (const
|
|
8444
|
-
const p =
|
|
8445
|
-
if (!
|
|
8446
|
-
if (!isActiveState(lifecycleStateOf({ status:
|
|
8447
|
-
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;
|
|
8448
10034
|
}
|
|
8449
10035
|
const mappedModules = loadMappedModules(dir);
|
|
8450
10036
|
const layers = knowledgeLayers(dir);
|
|
@@ -8455,7 +10041,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8455
10041
|
const qCodebase = qa("knowledge/tech/codebase.md");
|
|
8456
10042
|
const qCurrentState = qa("knowledge/tech/current-state.md");
|
|
8457
10043
|
const qRoadmap = qa("knowledge/delivery/roadmap.md");
|
|
8458
|
-
const layerStatusOf = (name) => layers.find((
|
|
10044
|
+
const layerStatusOf = (name) => layers.find((l2) => l2.layer === name)?.status ?? "Missing";
|
|
8459
10045
|
const knowledgeQuality = {
|
|
8460
10046
|
business: { status: layerStatusOf("Business"), artifacts: { "knowledge/business/business.md": qBusiness } },
|
|
8461
10047
|
product: { status: layerStatusOf("Product"), artifacts: { "knowledge/product/product.md": qProduct, "knowledge/product/capabilities.md": qCapabilities } },
|
|
@@ -8466,20 +10052,20 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8466
10052
|
if (qProduct === "placeholder" || qCapabilities === "placeholder") missing.push("Product capabilities exist but still look like a bootstrap placeholder.");
|
|
8467
10053
|
if (qCurrentState === "placeholder") missing.push("Current state exists but still looks like a bootstrap placeholder.");
|
|
8468
10054
|
if (qCodebase === "placeholder") missing.push("Codebase map exists but still looks like a bootstrap placeholder.");
|
|
8469
|
-
const allWorkItems = allArtifacts.filter((
|
|
8470
|
-
const wiWithOwnership = allWorkItems.filter((
|
|
10055
|
+
const allWorkItems = allArtifacts.filter((a2) => a2.isWorkItem);
|
|
10056
|
+
const wiWithOwnership = allWorkItems.filter((a2) => a2.codeGlobs.length > 0).length;
|
|
8471
10057
|
const phase = assessPhase({
|
|
8472
10058
|
layers,
|
|
8473
10059
|
roadmap,
|
|
8474
10060
|
workItems: {
|
|
8475
10061
|
total: allWorkItems.length,
|
|
8476
10062
|
byState: lifecycleCounts(
|
|
8477
|
-
allWorkItems.map((
|
|
10063
|
+
allWorkItems.map((a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
|
|
8478
10064
|
),
|
|
8479
|
-
items: allWorkItems.map((
|
|
8480
|
-
id:
|
|
8481
|
-
title:
|
|
8482
|
-
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 })
|
|
8483
10069
|
}))
|
|
8484
10070
|
},
|
|
8485
10071
|
ownership: {
|
|
@@ -8544,7 +10130,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8544
10130
|
roadmapSummary,
|
|
8545
10131
|
inventoryAvailable,
|
|
8546
10132
|
workItems: workItems.map(toContextWorkItem),
|
|
8547
|
-
artifacts: allArtifacts.filter((
|
|
10133
|
+
artifacts: allArtifacts.filter((a2) => a2.codeGlobs.length > 0).map(toContextArtifact)
|
|
8548
10134
|
},
|
|
8549
10135
|
layers,
|
|
8550
10136
|
knowledgeQuality,
|
|
@@ -8557,7 +10143,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8557
10143
|
roadmapQuality: buildRoadmapQuality(dir),
|
|
8558
10144
|
installedAssets: (() => {
|
|
8559
10145
|
const s = installedAssetsSummary(dir);
|
|
8560
|
-
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 });
|
|
8561
10147
|
return { version: s.version, agents: compact(s.agents), skills: compact(s.skills) };
|
|
8562
10148
|
})(),
|
|
8563
10149
|
deliveryMix,
|
|
@@ -8569,6 +10155,31 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8569
10155
|
projectRoute: buildProjectRoute(dir),
|
|
8570
10156
|
metadataHealth: analyzeMetadataHealth(dir),
|
|
8571
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
|
+
})(),
|
|
8572
10183
|
missing,
|
|
8573
10184
|
// VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
|
|
8574
10185
|
// the Current Phase block above it.
|
|
@@ -8593,7 +10204,7 @@ function renderContextPack(pack) {
|
|
|
8593
10204
|
"> Generated by `kaddo context`. Deterministic CLI output \u2014 not an interpretation of the system.\n"
|
|
8594
10205
|
);
|
|
8595
10206
|
parts.push("## Operating Rules (read first)\n");
|
|
8596
|
-
parts.push(handoff.operatingRules.map((
|
|
10207
|
+
parts.push(handoff.operatingRules.map((r2) => `- ${r2}`).join("\n") + "\n");
|
|
8597
10208
|
parts.push("## Project Metadata\n");
|
|
8598
10209
|
parts.push(
|
|
8599
10210
|
[
|
|
@@ -8609,7 +10220,7 @@ function renderContextPack(pack) {
|
|
|
8609
10220
|
`);
|
|
8610
10221
|
if (pack.phase.reasons.length > 0) {
|
|
8611
10222
|
parts.push("Reason:\n");
|
|
8612
|
-
parts.push(pack.phase.reasons.map((
|
|
10223
|
+
parts.push(pack.phase.reasons.map((r2) => `- ${r2}`).join("\n") + "\n");
|
|
8613
10224
|
}
|
|
8614
10225
|
if (pack.phase.recommendedAgents.length > 0) {
|
|
8615
10226
|
parts.push(`Recommended next: ${pack.phase.recommendedAgents.join(", ")}
|
|
@@ -8650,7 +10261,7 @@ function renderContextPack(pack) {
|
|
|
8650
10261
|
parts.push(
|
|
8651
10262
|
"Project knowledge is organized in four layers: **Business \u2192 Product \u2192 Tech \u2192 Delivery**.\n"
|
|
8652
10263
|
);
|
|
8653
|
-
const maturity = pack.layers.map((
|
|
10264
|
+
const maturity = pack.layers.map((l2) => `${l2.layer}: ${l2.status}`).join(" \xB7 ");
|
|
8654
10265
|
parts.push(`Knowledge maturity \u2014 ${maturity}
|
|
8655
10266
|
`);
|
|
8656
10267
|
parts.push(renderLayersMarkdown(pack.layers) + "\n");
|
|
@@ -8663,19 +10274,19 @@ function renderContextPack(pack) {
|
|
|
8663
10274
|
];
|
|
8664
10275
|
if (scan.sourceDirectories.length > 0) {
|
|
8665
10276
|
lines.push("- Source directories:");
|
|
8666
|
-
scan.sourceDirectories.forEach((
|
|
10277
|
+
scan.sourceDirectories.forEach((d3) => lines.push(` - ${d3}`));
|
|
8667
10278
|
}
|
|
8668
10279
|
if (scan.migrationDirectories.length > 0) {
|
|
8669
10280
|
lines.push("- Migration directories:");
|
|
8670
|
-
scan.migrationDirectories.forEach((
|
|
10281
|
+
scan.migrationDirectories.forEach((d3) => lines.push(` - ${d3}`));
|
|
8671
10282
|
}
|
|
8672
10283
|
if (scan.contractFiles.length > 0) {
|
|
8673
10284
|
lines.push("- Contracts:");
|
|
8674
|
-
scan.contractFiles.forEach((
|
|
10285
|
+
scan.contractFiles.forEach((f3) => lines.push(` - ${f3}`));
|
|
8675
10286
|
}
|
|
8676
10287
|
if (scan.infrastructureFiles.length > 0) {
|
|
8677
10288
|
lines.push("- Infrastructure:");
|
|
8678
|
-
scan.infrastructureFiles.forEach((
|
|
10289
|
+
scan.infrastructureFiles.forEach((f3) => lines.push(` - ${f3}`));
|
|
8679
10290
|
}
|
|
8680
10291
|
parts.push(lines.join("\n") + "\n");
|
|
8681
10292
|
} else {
|
|
@@ -8753,7 +10364,7 @@ function renderContextPack(pack) {
|
|
|
8753
10364
|
} else {
|
|
8754
10365
|
parts.push("No active work items found.\n");
|
|
8755
10366
|
}
|
|
8756
|
-
const mixEntries = Object.entries(pack.deliveryMix).sort((
|
|
10367
|
+
const mixEntries = Object.entries(pack.deliveryMix).sort((a2, b2) => b2[1] - a2[1]);
|
|
8757
10368
|
if (mixEntries.length > 0) {
|
|
8758
10369
|
parts.push("## Delivery Mix\n");
|
|
8759
10370
|
parts.push("Active Work Items by type:\n");
|
|
@@ -8766,7 +10377,7 @@ function renderContextPack(pack) {
|
|
|
8766
10377
|
parts.push("## Artifacts and Ownership\n");
|
|
8767
10378
|
if (knowledge.artifacts.length > 0) {
|
|
8768
10379
|
const lines = knowledge.artifacts.map(
|
|
8769
|
-
(
|
|
10380
|
+
(a2) => `- ${a2.id || a2.title} [${a2.type}] owns: ${a2.codeGlobs.join(", ")}`
|
|
8770
10381
|
);
|
|
8771
10382
|
parts.push(lines.join("\n") + "\n");
|
|
8772
10383
|
} else {
|
|
@@ -8777,15 +10388,35 @@ function renderContextPack(pack) {
|
|
|
8777
10388
|
parts.push("This project has mapped modules registered in `.kaddo/modules.yml`.\n");
|
|
8778
10389
|
const header = "| Module | Type | Repo path | Owner | Capabilities | Artifacts |";
|
|
8779
10390
|
const sep = "|---|---|---|---|---|---|";
|
|
8780
|
-
const rows = pack.mappedModules.map((
|
|
8781
|
-
const caps =
|
|
8782
|
-
const arts = presentArtifacts(
|
|
8783
|
-
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"} |`;
|
|
8784
10395
|
});
|
|
8785
10396
|
parts.push([header, sep, ...rows].join("\n") + "\n");
|
|
8786
10397
|
parts.push(
|
|
8787
10398
|
"Note: Kaddo does not scan secondary repositories during `context`. Mapped modules come from `.kaddo/modules.yml` and module artifacts only.\n"
|
|
8788
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
|
+
}
|
|
8789
10420
|
}
|
|
8790
10421
|
if (pack.external.length > 0) {
|
|
8791
10422
|
parts.push("## External Knowledge\n");
|
|
@@ -8827,7 +10458,7 @@ function renderContextPack(pack) {
|
|
|
8827
10458
|
].join("\n") + "\n"
|
|
8828
10459
|
);
|
|
8829
10460
|
const shown = pack.graphHints.messages.slice(0, 3);
|
|
8830
|
-
parts.push(shown.map((
|
|
10461
|
+
parts.push(shown.map((m2) => `- ${m2}`).join("\n") + "\n");
|
|
8831
10462
|
if (pack.graphHints.totalHints > shown.length) {
|
|
8832
10463
|
parts.push(`(+${pack.graphHints.totalHints - shown.length} more in \`.kaddo/graph-hints.md\`)
|
|
8833
10464
|
`);
|
|
@@ -8848,18 +10479,18 @@ function renderContextPack(pack) {
|
|
|
8848
10479
|
...!pack.knowledgeQuality.product || pack.knowledgeQuality.product.status === "Missing" ? ["- Missing product knowledge."] : []
|
|
8849
10480
|
];
|
|
8850
10481
|
if (missing.length > 0) {
|
|
8851
|
-
baselineMissing.push(...missing.filter((
|
|
10482
|
+
baselineMissing.push(...missing.filter((m2) => !baselineMissing.some((b2) => b2.includes(m2))));
|
|
8852
10483
|
}
|
|
8853
10484
|
parts.push(baselineMissing.join("\n") + "\n");
|
|
8854
10485
|
} else if (missing.length > 0) {
|
|
8855
|
-
parts.push(missing.map((
|
|
10486
|
+
parts.push(missing.map((m2) => `- ${m2}`).join("\n") + "\n");
|
|
8856
10487
|
} else {
|
|
8857
10488
|
parts.push("_None \u2014 all expected context is present._\n");
|
|
8858
10489
|
}
|
|
8859
10490
|
if (pack.metadataHealth.findings.length > 0) {
|
|
8860
10491
|
parts.push("\n### Metadata Health\n");
|
|
8861
|
-
for (const
|
|
8862
|
-
parts.push(`- \`${
|
|
10492
|
+
for (const f3 of pack.metadataHealth.findings) {
|
|
10493
|
+
parts.push(`- \`${f3.file}\`: ${f3.detail}
|
|
8863
10494
|
`);
|
|
8864
10495
|
}
|
|
8865
10496
|
}
|
|
@@ -8883,7 +10514,7 @@ function renderContextPack(pack) {
|
|
|
8883
10514
|
parts.push(`Agent prompt: \`${rec.agentPath}\`
|
|
8884
10515
|
`);
|
|
8885
10516
|
}
|
|
8886
|
-
parts.push(handoff.recommendedAgents.map((
|
|
10517
|
+
parts.push(handoff.recommendedAgents.map((a2, i) => `${i + 1}. ${a2}`).join("\n") + "\n");
|
|
8887
10518
|
if (handoff.nextSteps.length > 0) {
|
|
8888
10519
|
parts.push("Next step:\n");
|
|
8889
10520
|
parts.push(handoff.nextSteps.map((s) => `- ${s}`).join("\n") + "\n");
|
|
@@ -9027,7 +10658,7 @@ function renderUnderstand(plan) {
|
|
|
9027
10658
|
}
|
|
9028
10659
|
}
|
|
9029
10660
|
if (flowSteps.length > 0) {
|
|
9030
|
-
parts.push(flowSteps.map((
|
|
10661
|
+
parts.push(flowSteps.map((f3, i) => `${i + 1}. ${f3}`).join("\n") + "\n");
|
|
9031
10662
|
}
|
|
9032
10663
|
}
|
|
9033
10664
|
if (rec) {
|
|
@@ -9046,10 +10677,10 @@ function renderUnderstand(plan) {
|
|
|
9046
10677
|
if (plan.activeWorkItems && plan.activeWorkItems.length > 0) {
|
|
9047
10678
|
parts.push("## Active Work Items\n");
|
|
9048
10679
|
parts.push(
|
|
9049
|
-
plan.activeWorkItems.map((
|
|
9050
|
-
const src =
|
|
9051
|
-
- Source: ${
|
|
9052
|
-
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}`;
|
|
9053
10684
|
}).join("\n") + "\n"
|
|
9054
10685
|
);
|
|
9055
10686
|
}
|
|
@@ -9101,6 +10732,8 @@ function renderUnderstand(plan) {
|
|
|
9101
10732
|
outputs.push("- A new Work Item under `knowledge/delivery/work-items/`.");
|
|
9102
10733
|
if (rec.id === "implement" || rec.id === "implement-work-item")
|
|
9103
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.");
|
|
9104
10737
|
if (rec.id === "guard")
|
|
9105
10738
|
outputs.push("- Updated knowledge artifacts reflecting recent code changes.");
|
|
9106
10739
|
if (rec.id === "install-adapter" || rec.id === "prepare-implementation")
|
|
@@ -9170,10 +10803,23 @@ function renderUnderstand(plan) {
|
|
|
9170
10803
|
} else {
|
|
9171
10804
|
parts.push("Re-run `kaddo understand` any time to see this plan again.\n");
|
|
9172
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
|
+
}
|
|
9173
10819
|
if (plan.metadataHealth && plan.metadataHealth.findings.length > 0) {
|
|
9174
10820
|
parts.push("## Metadata Health\n");
|
|
9175
|
-
for (const
|
|
9176
|
-
parts.push(`- \`${
|
|
10821
|
+
for (const f3 of plan.metadataHealth.findings) {
|
|
10822
|
+
parts.push(`- \`${f3.file}\`: ${f3.detail}
|
|
9177
10823
|
`);
|
|
9178
10824
|
}
|
|
9179
10825
|
}
|
|
@@ -9349,8 +10995,8 @@ function toolText(result) {
|
|
|
9349
10995
|
if (!result.ok) {
|
|
9350
10996
|
return { content: [{ type: "text", text: result.message }], isError: true };
|
|
9351
10997
|
}
|
|
9352
|
-
const
|
|
9353
|
-
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 }] };
|
|
9354
11000
|
}
|
|
9355
11001
|
function guarded(root, fn) {
|
|
9356
11002
|
try {
|
|
@@ -9374,11 +11020,11 @@ function generated(root, label, fn) {
|
|
|
9374
11020
|
var DERIVED_NOTE = "Writes only derived files under .kaddo/. Does not modify knowledge, source code, external context or git.";
|
|
9375
11021
|
function createServer(root) {
|
|
9376
11022
|
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
9377
|
-
for (const
|
|
11023
|
+
for (const r2 of RESOURCES) {
|
|
9378
11024
|
server.registerResource(
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
{ title:
|
|
11025
|
+
r2.name,
|
|
11026
|
+
r2.uri,
|
|
11027
|
+
{ title: r2.name, description: r2.description, mimeType: r2.mimeType },
|
|
9382
11028
|
async (uri) => {
|
|
9383
11029
|
try {
|
|
9384
11030
|
assertKaddoProject(root);
|
|
@@ -9386,7 +11032,7 @@ function createServer(root) {
|
|
|
9386
11032
|
const message = err instanceof KaddoMcpError ? err.message : String(err);
|
|
9387
11033
|
return { contents: [{ uri: uri.href, text: message, mimeType: "text/plain" }] };
|
|
9388
11034
|
}
|
|
9389
|
-
const parts =
|
|
11035
|
+
const parts = r2.read(root);
|
|
9390
11036
|
return { contents: parts.map((p) => ({ uri: p.uri, text: p.text, mimeType: p.mimeType })) };
|
|
9391
11037
|
}
|
|
9392
11038
|
);
|
|
@@ -9402,16 +11048,16 @@ function createServer(root) {
|
|
|
9402
11048
|
title: "List Work Items",
|
|
9403
11049
|
description: "List Work Items with optional status/type/knowledge_level filters.",
|
|
9404
11050
|
inputSchema: {
|
|
9405
|
-
status:
|
|
9406
|
-
type:
|
|
9407
|
-
knowledge_level:
|
|
11051
|
+
status: z3.string().optional(),
|
|
11052
|
+
type: z3.string().optional(),
|
|
11053
|
+
knowledge_level: z3.string().optional()
|
|
9408
11054
|
}
|
|
9409
11055
|
},
|
|
9410
11056
|
async (args) => toolText(guarded(root, () => listWorkItemsTool(root, args)))
|
|
9411
11057
|
);
|
|
9412
11058
|
server.registerTool(
|
|
9413
11059
|
"kaddo_get_work_item",
|
|
9414
|
-
{ 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() } },
|
|
9415
11061
|
async (args) => toolText(guarded(root, () => getWorkItem(root, args.id)))
|
|
9416
11062
|
);
|
|
9417
11063
|
server.registerTool(
|
|
@@ -9419,7 +11065,7 @@ function createServer(root) {
|
|
|
9419
11065
|
{
|
|
9420
11066
|
title: "Mark Work Item ready",
|
|
9421
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.",
|
|
9422
|
-
inputSchema: { id:
|
|
11068
|
+
inputSchema: { id: z3.string(), confirm: z3.boolean().optional() }
|
|
9423
11069
|
},
|
|
9424
11070
|
async (args) => toolText(guarded(root, () => markWorkItemReady(root, args.id, args.confirm)))
|
|
9425
11071
|
);
|
|
@@ -9430,7 +11076,7 @@ function createServer(root) {
|
|
|
9430
11076
|
);
|
|
9431
11077
|
server.registerTool(
|
|
9432
11078
|
"kaddo_get_capsule",
|
|
9433
|
-
{ 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() } },
|
|
9434
11080
|
async (args) => toolText(guarded(root, () => getCapsuleTool(root, args.id)))
|
|
9435
11081
|
);
|
|
9436
11082
|
server.registerTool(
|
|
@@ -9440,7 +11086,7 @@ function createServer(root) {
|
|
|
9440
11086
|
);
|
|
9441
11087
|
server.registerTool(
|
|
9442
11088
|
"kaddo_get_agent_prompt",
|
|
9443
|
-
{ 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() } },
|
|
9444
11090
|
async (args) => toolText(guarded(root, () => getAgentPromptTool(root, args.name)))
|
|
9445
11091
|
);
|
|
9446
11092
|
server.registerTool(
|
|
@@ -9449,9 +11095,9 @@ function createServer(root) {
|
|
|
9449
11095
|
title: "List graph hints",
|
|
9450
11096
|
description: "List knowledge-graph relationship hints with optional filters.",
|
|
9451
11097
|
inputSchema: {
|
|
9452
|
-
artifact_type:
|
|
9453
|
-
severity:
|
|
9454
|
-
active_only:
|
|
11098
|
+
artifact_type: z3.string().optional(),
|
|
11099
|
+
severity: z3.string().optional(),
|
|
11100
|
+
active_only: z3.boolean().optional()
|
|
9455
11101
|
}
|
|
9456
11102
|
},
|
|
9457
11103
|
async (args) => toolText(guarded(root, () => listGraphHints(root, args)))
|
|
@@ -9463,7 +11109,7 @@ function createServer(root) {
|
|
|
9463
11109
|
);
|
|
9464
11110
|
server.registerTool(
|
|
9465
11111
|
"kaddo_get_skill",
|
|
9466
|
-
{ 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() } },
|
|
9467
11113
|
async (args) => toolText(guarded(root, () => getSkillTool(root, args.id)))
|
|
9468
11114
|
);
|
|
9469
11115
|
let installedSkills = [];
|
|
@@ -9508,7 +11154,7 @@ function createServer(root) {
|
|
|
9508
11154
|
{
|
|
9509
11155
|
title: "Generate knowledge graph",
|
|
9510
11156
|
description: `Regenerate .kaddo/graph.json/.mmd + graph-hints.md/.json. scope: active (default) or all. ${DERIVED_NOTE}`,
|
|
9511
|
-
inputSchema: { scope:
|
|
11157
|
+
inputSchema: { scope: z3.enum(["active", "all"]).optional() }
|
|
9512
11158
|
},
|
|
9513
11159
|
async (args) => generated(root, "generate knowledge graph", () => generateGraph(root, args.scope ?? "active"))
|
|
9514
11160
|
);
|
|
@@ -9518,9 +11164,9 @@ function createServer(root) {
|
|
|
9518
11164
|
title: "Generate impact report",
|
|
9519
11165
|
description: `Write the Knowledge Impact Report under .kaddo/reports/. format: markdown (default) or json; scope: active or all (default all). ${DERIVED_NOTE}`,
|
|
9520
11166
|
inputSchema: {
|
|
9521
|
-
format:
|
|
9522
|
-
scope:
|
|
9523
|
-
output:
|
|
11167
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11168
|
+
scope: z3.enum(["active", "all"]).optional(),
|
|
11169
|
+
output: z3.string().optional()
|
|
9524
11170
|
}
|
|
9525
11171
|
},
|
|
9526
11172
|
async (args) => generated(
|
|
@@ -9535,9 +11181,9 @@ function createServer(root) {
|
|
|
9535
11181
|
title: "Generate savings report",
|
|
9536
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}`,
|
|
9537
11183
|
inputSchema: {
|
|
9538
|
-
format:
|
|
9539
|
-
scope:
|
|
9540
|
-
output:
|
|
11184
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11185
|
+
scope: z3.enum(["active", "all"]).optional(),
|
|
11186
|
+
output: z3.string().optional()
|
|
9541
11187
|
}
|
|
9542
11188
|
},
|
|
9543
11189
|
async (args) => generated(
|
|
@@ -9552,8 +11198,8 @@ function createServer(root) {
|
|
|
9552
11198
|
title: "Generate drift report",
|
|
9553
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}`,
|
|
9554
11200
|
inputSchema: {
|
|
9555
|
-
format:
|
|
9556
|
-
output:
|
|
11201
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11202
|
+
output: z3.string().optional()
|
|
9557
11203
|
}
|
|
9558
11204
|
},
|
|
9559
11205
|
async (args) => generated(
|
|
@@ -9568,8 +11214,8 @@ function createServer(root) {
|
|
|
9568
11214
|
title: "Generate open-questions report",
|
|
9569
11215
|
description: `Write the Open Questions readiness report under .kaddo/reports/ (classifies blocking/important/deferred). Does NOT resolve questions. ${DERIVED_NOTE}`,
|
|
9570
11216
|
inputSchema: {
|
|
9571
|
-
format:
|
|
9572
|
-
output:
|
|
11217
|
+
format: z3.enum(["markdown", "json"]).optional(),
|
|
11218
|
+
output: z3.string().optional()
|
|
9573
11219
|
}
|
|
9574
11220
|
},
|
|
9575
11221
|
async (args) => generated(
|