@kaddo/mcp 3.105.0 → 3.106.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 +683 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10828,6 +10828,9 @@ function writeFile2(filePath, content) {
|
|
|
10828
10828
|
fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
|
|
10829
10829
|
fs3.writeFileSync(filePath, content, "utf-8");
|
|
10830
10830
|
}
|
|
10831
|
+
function ensureDir2(dirPath) {
|
|
10832
|
+
fs3.mkdirSync(dirPath, { recursive: true });
|
|
10833
|
+
}
|
|
10831
10834
|
function readDir2(dirPath) {
|
|
10832
10835
|
if (!exists2(dirPath)) return [];
|
|
10833
10836
|
return fs3.readdirSync(dirPath);
|
|
@@ -11071,6 +11074,9 @@ function lifecycleStateOf2(item) {
|
|
|
11071
11074
|
if (folder) return folder;
|
|
11072
11075
|
return "ready";
|
|
11073
11076
|
}
|
|
11077
|
+
function emptyLifecycleCounts2() {
|
|
11078
|
+
return Object.fromEntries(LIFECYCLE_STATES2.map((s) => [s, 0]));
|
|
11079
|
+
}
|
|
11074
11080
|
var ARCH_DIR3 = "knowledge";
|
|
11075
11081
|
function toPosix6(p) {
|
|
11076
11082
|
return p.replace(/\\/g, "/");
|
|
@@ -16967,7 +16973,7 @@ function createWorkItem(dir, opts) {
|
|
|
16967
16973
|
if (!type) throw new WorkItemWriteError("INVALID_INPUT", `Unknown Work Item type "${opts.type}".`);
|
|
16968
16974
|
const id = nextWorkItemId(dir);
|
|
16969
16975
|
const title = intent.split(/\r?\n/)[0].trim().slice(0, 120);
|
|
16970
|
-
const
|
|
16976
|
+
const today22 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
16971
16977
|
const source = opts.source ? { ...opts.source, inferred: false } : { type: "manual", inferred: false };
|
|
16972
16978
|
const data = {
|
|
16973
16979
|
type,
|
|
@@ -16975,7 +16981,7 @@ function createWorkItem(dir, opts) {
|
|
|
16975
16981
|
title,
|
|
16976
16982
|
status: "draft",
|
|
16977
16983
|
work_type: type,
|
|
16978
|
-
created_at:
|
|
16984
|
+
created_at: today22,
|
|
16979
16985
|
source,
|
|
16980
16986
|
generated_by: "kaddo-admin",
|
|
16981
16987
|
affected_modules: [],
|
|
@@ -18581,6 +18587,7 @@ function getStatus(dir) {
|
|
|
18581
18587
|
lastError: null
|
|
18582
18588
|
};
|
|
18583
18589
|
}
|
|
18590
|
+
var INITIATIVES_DIR = "knowledge/delivery/initiatives";
|
|
18584
18591
|
var INITIATIVE_STATES = [
|
|
18585
18592
|
"candidate",
|
|
18586
18593
|
"planned",
|
|
@@ -18589,9 +18596,465 @@ var INITIATIVE_STATES = [
|
|
|
18589
18596
|
"deferred",
|
|
18590
18597
|
"cancelled"
|
|
18591
18598
|
];
|
|
18599
|
+
var INITIATIVE_TRANSITIONS = {
|
|
18600
|
+
candidate: ["planned", "cancelled"],
|
|
18601
|
+
planned: ["in-progress", "deferred", "cancelled"],
|
|
18602
|
+
"in-progress": ["completed", "deferred", "cancelled"],
|
|
18603
|
+
deferred: ["planned", "cancelled"],
|
|
18604
|
+
completed: [],
|
|
18605
|
+
cancelled: []
|
|
18606
|
+
};
|
|
18592
18607
|
var STATUS_SET = new Set(INITIATIVE_STATES);
|
|
18608
|
+
function isValidInitiativeStatus(s) {
|
|
18609
|
+
return STATUS_SET.has(s);
|
|
18610
|
+
}
|
|
18611
|
+
function isValidInitiativeTransition(from, to) {
|
|
18612
|
+
return INITIATIVE_TRANSITIONS[from].includes(to);
|
|
18613
|
+
}
|
|
18614
|
+
function toPosix42(p) {
|
|
18615
|
+
return p.replace(/\\/g, "/");
|
|
18616
|
+
}
|
|
18617
|
+
function optStr32(v) {
|
|
18618
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
18619
|
+
if (typeof v === "number") return String(v);
|
|
18620
|
+
return void 0;
|
|
18621
|
+
}
|
|
18622
|
+
function strList2(v) {
|
|
18623
|
+
if (!Array.isArray(v)) return [];
|
|
18624
|
+
return v.map((x2) => typeof x2 === "string" ? x2.trim() : String(x2)).filter(Boolean);
|
|
18625
|
+
}
|
|
18626
|
+
function parseCandidates(data) {
|
|
18627
|
+
const raw = data.candidates;
|
|
18628
|
+
if (!Array.isArray(raw)) return [];
|
|
18629
|
+
const out = [];
|
|
18630
|
+
for (const entry of raw) {
|
|
18631
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
18632
|
+
const o2 = entry;
|
|
18633
|
+
const id = optStr32(o2.id);
|
|
18634
|
+
const title = optStr32(o2.title);
|
|
18635
|
+
if (!id || !title) continue;
|
|
18636
|
+
out.push({
|
|
18637
|
+
id,
|
|
18638
|
+
title,
|
|
18639
|
+
type: optStr32(o2.type),
|
|
18640
|
+
suggestedKnowledgeLevel: optStr32(o2.suggested_knowledge_level ?? o2.knowledge_level),
|
|
18641
|
+
expectedValue: optStr32(o2.expected_value),
|
|
18642
|
+
notes: optStr32(o2.notes),
|
|
18643
|
+
sourceSignals: strList2(o2.source_signals),
|
|
18644
|
+
dependencies: strList2(o2.dependencies),
|
|
18645
|
+
materializedAs: optStr32(o2.materialized_as) ?? null
|
|
18646
|
+
});
|
|
18647
|
+
}
|
|
18648
|
+
return out;
|
|
18649
|
+
}
|
|
18650
|
+
function parseExternalLinks(data) {
|
|
18651
|
+
const raw = data.external_links;
|
|
18652
|
+
if (!Array.isArray(raw)) return [];
|
|
18653
|
+
const out = [];
|
|
18654
|
+
for (const entry of raw) {
|
|
18655
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
18656
|
+
const o2 = entry;
|
|
18657
|
+
const integration = optStr32(o2.integration);
|
|
18658
|
+
const externalId = optStr32(o2.external_id);
|
|
18659
|
+
if (!integration || !externalId) continue;
|
|
18660
|
+
out.push({
|
|
18661
|
+
integration,
|
|
18662
|
+
externalId,
|
|
18663
|
+
externalType: optStr32(o2.external_type),
|
|
18664
|
+
url: optStr32(o2.url)
|
|
18665
|
+
});
|
|
18666
|
+
}
|
|
18667
|
+
return out;
|
|
18668
|
+
}
|
|
18669
|
+
function parseInitiative(dir, filePath, raw) {
|
|
18670
|
+
let parsed;
|
|
18671
|
+
try {
|
|
18672
|
+
parsed = matter102(raw, {});
|
|
18673
|
+
} catch {
|
|
18674
|
+
return null;
|
|
18675
|
+
}
|
|
18676
|
+
const data = parsed.data;
|
|
18677
|
+
if (optStr32(data.type) !== "initiative") return null;
|
|
18678
|
+
const id = optStr32(data.id);
|
|
18679
|
+
if (!id) return null;
|
|
18680
|
+
const statusRaw = optStr32(data.status) ?? "planned";
|
|
18681
|
+
const status = isValidInitiativeStatus(statusRaw) ? statusRaw : "planned";
|
|
18682
|
+
return {
|
|
18683
|
+
id,
|
|
18684
|
+
title: optStr32(data.title) ?? id,
|
|
18685
|
+
status,
|
|
18686
|
+
horizon: optStr32(data.horizon) ?? null,
|
|
18687
|
+
priority: optStr32(data.priority) ?? null,
|
|
18688
|
+
knowledgeLevel: optStr32(data.knowledge_level) ?? null,
|
|
18689
|
+
domains: strList2(data.domains),
|
|
18690
|
+
relatedCapabilities: strList2(data.related_capabilities),
|
|
18691
|
+
source: optStr32(data.source) ?? null,
|
|
18692
|
+
sourceId: optStr32(data.source_id) ?? null,
|
|
18693
|
+
createdAt: optStr32(data.created_at) ?? null,
|
|
18694
|
+
externalLinks: parseExternalLinks(data),
|
|
18695
|
+
candidates: parseCandidates(data),
|
|
18696
|
+
filePath,
|
|
18697
|
+
relPath: toPosix42(filePath).startsWith(toPosix42(dir) + "/") ? toPosix42(filePath).slice(toPosix42(dir).length + 1) : toPosix42(filePath),
|
|
18698
|
+
body: parsed.content.trim(),
|
|
18699
|
+
rawFrontmatter: data
|
|
18700
|
+
};
|
|
18701
|
+
}
|
|
18702
|
+
function discoverInitiatives(dir) {
|
|
18703
|
+
const iniDir = join3(dir, INITIATIVES_DIR);
|
|
18704
|
+
if (!exists2(iniDir)) return [];
|
|
18705
|
+
const out = [];
|
|
18706
|
+
for (const entry of readDir2(iniDir)) {
|
|
18707
|
+
if (!entry.endsWith(".md")) continue;
|
|
18708
|
+
const full = join3(iniDir, entry);
|
|
18709
|
+
if (!isFile2(full)) continue;
|
|
18710
|
+
const ini = parseInitiative(dir, full, readFile2(full));
|
|
18711
|
+
if (ini) out.push(ini);
|
|
18712
|
+
}
|
|
18713
|
+
return out.sort((a2, b2) => a2.id.localeCompare(b2.id));
|
|
18714
|
+
}
|
|
18715
|
+
function getInitiative(dir, id) {
|
|
18716
|
+
const want = id.trim().toLowerCase();
|
|
18717
|
+
return discoverInitiatives(dir).find((i) => i.id.toLowerCase() === want) ?? null;
|
|
18718
|
+
}
|
|
18719
|
+
function nextInitiativeId(dir) {
|
|
18720
|
+
const iniDir = join3(dir, INITIATIVES_DIR);
|
|
18721
|
+
let max = 0;
|
|
18722
|
+
if (exists2(iniDir)) {
|
|
18723
|
+
for (const entry of readDir2(iniDir)) {
|
|
18724
|
+
const m2 = entry.match(/INI-(\d+)/);
|
|
18725
|
+
if (m2) max = Math.max(max, parseInt(m2[1], 10));
|
|
18726
|
+
}
|
|
18727
|
+
}
|
|
18728
|
+
return `INI-${String(max + 1).padStart(3, "0")}`;
|
|
18729
|
+
}
|
|
18730
|
+
function workItemBelongsToInitiative(workItemInitiative, iniId) {
|
|
18731
|
+
const v = (workItemInitiative ?? "").trim().toLowerCase();
|
|
18732
|
+
return v !== "" && v === iniId.trim().toLowerCase();
|
|
18733
|
+
}
|
|
18734
|
+
function associatedWorkItems(dir, iniId) {
|
|
18735
|
+
return discoverWorkItems2(dir).filter((wi) => workItemBelongsToInitiative(wi.initiative, iniId)).map((wi) => ({
|
|
18736
|
+
id: wi.id,
|
|
18737
|
+
title: wi.title,
|
|
18738
|
+
status: wi.lifecycle ?? "ready"
|
|
18739
|
+
})).sort((a2, b2) => a2.id.localeCompare(b2.id));
|
|
18740
|
+
}
|
|
18741
|
+
function computeInitiativeProgress(dir, ini) {
|
|
18742
|
+
const totalCandidates = ini.candidates.length;
|
|
18743
|
+
const materialized = ini.candidates.filter((c) => c.materializedAs).length;
|
|
18744
|
+
const byState = emptyLifecycleCounts2();
|
|
18745
|
+
const associated = associatedWorkItems(dir, ini.id);
|
|
18746
|
+
for (const wi of associated) byState[wi.status]++;
|
|
18747
|
+
return {
|
|
18748
|
+
initiative: ini.id,
|
|
18749
|
+
status: ini.status,
|
|
18750
|
+
planning: {
|
|
18751
|
+
totalCandidates,
|
|
18752
|
+
materialized,
|
|
18753
|
+
remaining: Math.max(0, totalCandidates - materialized)
|
|
18754
|
+
},
|
|
18755
|
+
delivery: {
|
|
18756
|
+
total: associated.length,
|
|
18757
|
+
byState
|
|
18758
|
+
}
|
|
18759
|
+
};
|
|
18760
|
+
}
|
|
18761
|
+
function getInitiativeContext(dir, ini) {
|
|
18762
|
+
return {
|
|
18763
|
+
initiative: {
|
|
18764
|
+
id: ini.id,
|
|
18765
|
+
title: ini.title,
|
|
18766
|
+
status: ini.status,
|
|
18767
|
+
horizon: ini.horizon,
|
|
18768
|
+
priority: ini.priority,
|
|
18769
|
+
knowledgeLevel: ini.knowledgeLevel,
|
|
18770
|
+
domains: ini.domains,
|
|
18771
|
+
relatedCapabilities: ini.relatedCapabilities,
|
|
18772
|
+
source: ini.source,
|
|
18773
|
+
sourceId: ini.sourceId
|
|
18774
|
+
},
|
|
18775
|
+
progress: computeInitiativeProgress(dir, ini),
|
|
18776
|
+
candidates: {
|
|
18777
|
+
total: ini.candidates.length,
|
|
18778
|
+
materialized: ini.candidates.filter((c) => c.materializedAs),
|
|
18779
|
+
pending: ini.candidates.filter((c) => !c.materializedAs)
|
|
18780
|
+
},
|
|
18781
|
+
workItems: associatedWorkItems(dir, ini.id),
|
|
18782
|
+
externalLinks: ini.externalLinks
|
|
18783
|
+
};
|
|
18784
|
+
}
|
|
18593
18785
|
var WORK_ITEMS_DIR2 = "knowledge/delivery/work-items";
|
|
18594
18786
|
var DRAFT_DIR = `${WORK_ITEMS_DIR2}/draft`;
|
|
18787
|
+
var InitiativeWriteError = class extends Error {
|
|
18788
|
+
constructor(message) {
|
|
18789
|
+
super(message);
|
|
18790
|
+
this.name = "InitiativeWriteError";
|
|
18791
|
+
}
|
|
18792
|
+
};
|
|
18793
|
+
function slugify3(s) {
|
|
18794
|
+
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 50);
|
|
18795
|
+
}
|
|
18796
|
+
function today2() {
|
|
18797
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18798
|
+
}
|
|
18799
|
+
function candidateToData(c) {
|
|
18800
|
+
const out = { id: c.id, title: c.title };
|
|
18801
|
+
if (c.type) out.type = c.type;
|
|
18802
|
+
if (c.suggestedKnowledgeLevel) out.suggested_knowledge_level = c.suggestedKnowledgeLevel;
|
|
18803
|
+
if (c.expectedValue) out.expected_value = c.expectedValue;
|
|
18804
|
+
if (c.notes) out.notes = c.notes;
|
|
18805
|
+
if (c.sourceSignals.length) out.source_signals = c.sourceSignals;
|
|
18806
|
+
if (c.dependencies.length) out.dependencies = c.dependencies;
|
|
18807
|
+
if (c.materializedAs) out.materialized_as = c.materializedAs;
|
|
18808
|
+
return out;
|
|
18809
|
+
}
|
|
18810
|
+
function externalLinkToData(l2) {
|
|
18811
|
+
const out = { integration: l2.integration, external_id: l2.externalId };
|
|
18812
|
+
if (l2.externalType) out.external_type = l2.externalType;
|
|
18813
|
+
if (l2.url) out.url = l2.url;
|
|
18814
|
+
return out;
|
|
18815
|
+
}
|
|
18816
|
+
function normalizeCandidate(input, fallbackId) {
|
|
18817
|
+
return {
|
|
18818
|
+
id: input.id?.trim() || fallbackId,
|
|
18819
|
+
title: input.title.trim(),
|
|
18820
|
+
type: input.type?.trim() || void 0,
|
|
18821
|
+
suggestedKnowledgeLevel: input.suggestedKnowledgeLevel?.trim() || void 0,
|
|
18822
|
+
expectedValue: input.expectedValue?.trim() || void 0,
|
|
18823
|
+
notes: input.notes?.trim() || void 0,
|
|
18824
|
+
sourceSignals: input.sourceSignals ?? [],
|
|
18825
|
+
dependencies: input.dependencies ?? [],
|
|
18826
|
+
materializedAs: input.materializedAs ?? null
|
|
18827
|
+
};
|
|
18828
|
+
}
|
|
18829
|
+
function defaultBody(title) {
|
|
18830
|
+
return [
|
|
18831
|
+
`# ${title}`,
|
|
18832
|
+
"",
|
|
18833
|
+
"## Goal",
|
|
18834
|
+
"",
|
|
18835
|
+
"_What outcome does this Initiative pursue?_",
|
|
18836
|
+
"",
|
|
18837
|
+
"## Expected Value",
|
|
18838
|
+
"",
|
|
18839
|
+
"_Why it matters._",
|
|
18840
|
+
"",
|
|
18841
|
+
"## Scope",
|
|
18842
|
+
"",
|
|
18843
|
+
"_What this Initiative covers._",
|
|
18844
|
+
"",
|
|
18845
|
+
"## Out of Scope",
|
|
18846
|
+
"",
|
|
18847
|
+
"_What it explicitly does not cover._",
|
|
18848
|
+
"",
|
|
18849
|
+
"## Success Criteria",
|
|
18850
|
+
"",
|
|
18851
|
+
'_Observable outcomes that define completion (not just "all Work Items done")._',
|
|
18852
|
+
"",
|
|
18853
|
+
"## Dependencies",
|
|
18854
|
+
"",
|
|
18855
|
+
"_Other Initiatives, modules, or external work this depends on._",
|
|
18856
|
+
"",
|
|
18857
|
+
"## Work Item Candidates",
|
|
18858
|
+
"",
|
|
18859
|
+
"_Candidates live in frontmatter `candidates`; summarize them here as they evolve._",
|
|
18860
|
+
"",
|
|
18861
|
+
"## Open Questions",
|
|
18862
|
+
"",
|
|
18863
|
+
"_Unresolved questions for this Initiative._",
|
|
18864
|
+
"",
|
|
18865
|
+
"## Learning",
|
|
18866
|
+
"",
|
|
18867
|
+
"_Captured on completion: what was delivered, what stayed out of scope, outcome reached._",
|
|
18868
|
+
""
|
|
18869
|
+
].join("\n");
|
|
18870
|
+
}
|
|
18871
|
+
function buildInitiativeContent(id, input) {
|
|
18872
|
+
const status = input.status ?? "planned";
|
|
18873
|
+
if (!isValidInitiativeStatus(status)) {
|
|
18874
|
+
throw new InitiativeWriteError(`Invalid initiative status: ${status}.`);
|
|
18875
|
+
}
|
|
18876
|
+
const candidates = (input.candidates ?? []).map(
|
|
18877
|
+
(c, i) => normalizeCandidate(c, `WI-CANDIDATE-${String(i + 1).padStart(3, "0")}`)
|
|
18878
|
+
);
|
|
18879
|
+
const data = {
|
|
18880
|
+
type: "initiative",
|
|
18881
|
+
id,
|
|
18882
|
+
title: input.title.trim(),
|
|
18883
|
+
status,
|
|
18884
|
+
knowledge_level: input.knowledgeLevel ?? "K2",
|
|
18885
|
+
domains: input.domains ?? [],
|
|
18886
|
+
related_capabilities: input.relatedCapabilities ?? [],
|
|
18887
|
+
created_at: today2(),
|
|
18888
|
+
external_links: (input.externalLinks ?? []).map(externalLinkToData),
|
|
18889
|
+
candidates: candidates.map(candidateToData)
|
|
18890
|
+
};
|
|
18891
|
+
if (input.horizon) data.horizon = input.horizon;
|
|
18892
|
+
if (input.priority) data.priority = input.priority;
|
|
18893
|
+
if (input.source) data.source = input.source;
|
|
18894
|
+
if (input.sourceId) data.source_id = input.sourceId;
|
|
18895
|
+
return matter11.stringify("\n" + (input.body ?? defaultBody(input.title.trim())), data);
|
|
18896
|
+
}
|
|
18897
|
+
function createInitiative(dir, input) {
|
|
18898
|
+
if (!input.title?.trim()) throw new InitiativeWriteError("Initiative title is required.");
|
|
18899
|
+
const id = nextInitiativeId(dir);
|
|
18900
|
+
const fileName = `${id}-${slugify3(input.title)}.md`;
|
|
18901
|
+
const iniDir = join3(dir, INITIATIVES_DIR);
|
|
18902
|
+
ensureDir2(iniDir);
|
|
18903
|
+
const filePath = join3(iniDir, fileName);
|
|
18904
|
+
const content = buildInitiativeContent(id, input);
|
|
18905
|
+
writeFile2(filePath, content);
|
|
18906
|
+
const ini = parseInitiative(dir, filePath, content);
|
|
18907
|
+
if (!ini) throw new InitiativeWriteError("Failed to parse the Initiative just written.");
|
|
18908
|
+
return ini;
|
|
18909
|
+
}
|
|
18910
|
+
function transitionInitiative(dir, id, to) {
|
|
18911
|
+
const ini = getInitiative(dir, id);
|
|
18912
|
+
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
18913
|
+
if (!isValidInitiativeStatus(to)) throw new InitiativeWriteError(`Invalid status: ${to}.`);
|
|
18914
|
+
if (ini.status === to) return ini;
|
|
18915
|
+
if (!isValidInitiativeTransition(ini.status, to)) {
|
|
18916
|
+
throw new InitiativeWriteError(`Invalid transition ${ini.status} \u2192 ${to}.`);
|
|
18917
|
+
}
|
|
18918
|
+
const raw = readFile2(ini.filePath);
|
|
18919
|
+
const { data, content } = matter11(raw, {});
|
|
18920
|
+
data.status = to;
|
|
18921
|
+
if (to === "completed") data.completed_at = today2();
|
|
18922
|
+
const newContent = matter11.stringify(content, data);
|
|
18923
|
+
writeFile2(ini.filePath, newContent);
|
|
18924
|
+
const updated = parseInitiative(dir, ini.filePath, newContent);
|
|
18925
|
+
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after transition.");
|
|
18926
|
+
return updated;
|
|
18927
|
+
}
|
|
18928
|
+
function addCandidate(dir, id, candidate) {
|
|
18929
|
+
const ini = getInitiative(dir, id);
|
|
18930
|
+
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
18931
|
+
const raw = readFile2(ini.filePath);
|
|
18932
|
+
const { data, content } = matter11(raw, {});
|
|
18933
|
+
const existing = Array.isArray(data.candidates) ? data.candidates : [];
|
|
18934
|
+
const fallbackId = `WI-CANDIDATE-${String(existing.length + 1).padStart(3, "0")}`;
|
|
18935
|
+
const normalized = normalizeCandidate(candidate, fallbackId);
|
|
18936
|
+
if (ini.candidates.some((c) => c.id === normalized.id)) {
|
|
18937
|
+
throw new InitiativeWriteError(`Candidate ${normalized.id} already exists in ${id}.`);
|
|
18938
|
+
}
|
|
18939
|
+
data.candidates = [...existing, candidateToData(normalized)];
|
|
18940
|
+
const newContent = matter11.stringify(content, data);
|
|
18941
|
+
writeFile2(ini.filePath, newContent);
|
|
18942
|
+
const updated = parseInitiative(dir, ini.filePath, newContent);
|
|
18943
|
+
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after adding a candidate.");
|
|
18944
|
+
return updated;
|
|
18945
|
+
}
|
|
18946
|
+
function updateInitiative(dir, id, patch) {
|
|
18947
|
+
const ini = getInitiative(dir, id);
|
|
18948
|
+
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
18949
|
+
const raw = readFile2(ini.filePath);
|
|
18950
|
+
const { data, content } = matter11(raw, {});
|
|
18951
|
+
if (patch.title !== void 0) {
|
|
18952
|
+
if (!patch.title.trim()) throw new InitiativeWriteError("Initiative title cannot be empty.");
|
|
18953
|
+
data.title = patch.title.trim();
|
|
18954
|
+
}
|
|
18955
|
+
if (patch.horizon !== void 0) data.horizon = patch.horizon;
|
|
18956
|
+
if (patch.priority !== void 0) data.priority = patch.priority;
|
|
18957
|
+
if (patch.knowledgeLevel !== void 0) data.knowledge_level = patch.knowledgeLevel;
|
|
18958
|
+
if (patch.domains !== void 0) data.domains = patch.domains;
|
|
18959
|
+
if (patch.relatedCapabilities !== void 0) data.related_capabilities = patch.relatedCapabilities;
|
|
18960
|
+
const newContent = matter11.stringify(content, data);
|
|
18961
|
+
writeFile2(ini.filePath, newContent);
|
|
18962
|
+
const updated = parseInitiative(dir, ini.filePath, newContent);
|
|
18963
|
+
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after update.");
|
|
18964
|
+
return updated;
|
|
18965
|
+
}
|
|
18966
|
+
function nextWorkItemId2(dir) {
|
|
18967
|
+
const wiDir = join3(dir, WORK_ITEMS_DIR2);
|
|
18968
|
+
let max = 0;
|
|
18969
|
+
const walk = (d3) => {
|
|
18970
|
+
if (!exists2(d3)) return;
|
|
18971
|
+
for (const entry of readDir2(d3)) {
|
|
18972
|
+
const full = join3(d3, entry);
|
|
18973
|
+
if (isFile2(full)) {
|
|
18974
|
+
const m2 = entry.match(/WI-(\d+)/);
|
|
18975
|
+
if (m2) max = Math.max(max, parseInt(m2[1], 10));
|
|
18976
|
+
} else if (!entry.startsWith(".")) {
|
|
18977
|
+
walk(full);
|
|
18978
|
+
}
|
|
18979
|
+
}
|
|
18980
|
+
};
|
|
18981
|
+
walk(wiDir);
|
|
18982
|
+
return `WI-${String(max + 1).padStart(3, "0")}`;
|
|
18983
|
+
}
|
|
18984
|
+
function buildWorkItemContent(wiId, iniId, candidate) {
|
|
18985
|
+
const data = {
|
|
18986
|
+
type: candidate.type ?? "feature",
|
|
18987
|
+
id: wiId,
|
|
18988
|
+
title: candidate.title,
|
|
18989
|
+
knowledge_level: candidate.suggestedKnowledgeLevel ?? "K2",
|
|
18990
|
+
status: "draft",
|
|
18991
|
+
phase: "now",
|
|
18992
|
+
initiative: iniId,
|
|
18993
|
+
domains: [],
|
|
18994
|
+
code: [],
|
|
18995
|
+
created_at: today2(),
|
|
18996
|
+
source: "initiative",
|
|
18997
|
+
source_id: candidate.id,
|
|
18998
|
+
source_initiative: iniId,
|
|
18999
|
+
affected_modules: []
|
|
19000
|
+
};
|
|
19001
|
+
if (candidate.sourceSignals.length) data.source_signals = candidate.sourceSignals;
|
|
19002
|
+
if (candidate.dependencies.length) data.dependencies = candidate.dependencies;
|
|
19003
|
+
const body = [
|
|
19004
|
+
`# ${candidate.title}`,
|
|
19005
|
+
"",
|
|
19006
|
+
`> Materialized from Initiative ${iniId}, candidate ${candidate.id}.`,
|
|
19007
|
+
"",
|
|
19008
|
+
"## Problem",
|
|
19009
|
+
"",
|
|
19010
|
+
candidate.expectedValue ? `_Expected value:_ ${candidate.expectedValue}` : "_Describe the problem._",
|
|
19011
|
+
"",
|
|
19012
|
+
"## Acceptance Criteria",
|
|
19013
|
+
"",
|
|
19014
|
+
"- [ ] _Define at least one testable criterion._",
|
|
19015
|
+
"",
|
|
19016
|
+
"## Out of scope",
|
|
19017
|
+
"",
|
|
19018
|
+
"_Not included in this Work Item._",
|
|
19019
|
+
"",
|
|
19020
|
+
"## Validation",
|
|
19021
|
+
"",
|
|
19022
|
+
"_How will this be validated?_",
|
|
19023
|
+
"",
|
|
19024
|
+
"## Learning",
|
|
19025
|
+
"",
|
|
19026
|
+
"_What did we learn? Update after completion._",
|
|
19027
|
+
""
|
|
19028
|
+
].join("\n");
|
|
19029
|
+
return matter11.stringify("\n" + body, data);
|
|
19030
|
+
}
|
|
19031
|
+
function materializeCandidate(dir, id, candidateId) {
|
|
19032
|
+
const ini = getInitiative(dir, id);
|
|
19033
|
+
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
19034
|
+
const candidate = ini.candidates.find((c) => c.id === candidateId);
|
|
19035
|
+
if (!candidate) throw new InitiativeWriteError(`Candidate ${candidateId} not found in ${id}.`);
|
|
19036
|
+
if (candidate.materializedAs) {
|
|
19037
|
+
throw new InitiativeWriteError(
|
|
19038
|
+
`Candidate ${candidateId} is already materialized as ${candidate.materializedAs}.`
|
|
19039
|
+
);
|
|
19040
|
+
}
|
|
19041
|
+
const wiId = nextWorkItemId2(dir);
|
|
19042
|
+
const fileName = `${wiId}-${slugify3(candidate.title)}.md`;
|
|
19043
|
+
ensureDir2(join3(dir, DRAFT_DIR));
|
|
19044
|
+
writeFile2(join3(dir, DRAFT_DIR, fileName), buildWorkItemContent(wiId, ini.id, candidate));
|
|
19045
|
+
const raw = readFile2(ini.filePath);
|
|
19046
|
+
const { data, content } = matter11(raw, {});
|
|
19047
|
+
const cands = Array.isArray(data.candidates) ? data.candidates : [];
|
|
19048
|
+
for (const c of cands) {
|
|
19049
|
+
if (c && typeof c === "object" && String(c.id) === candidateId) c.materialized_as = wiId;
|
|
19050
|
+
}
|
|
19051
|
+
data.candidates = cands;
|
|
19052
|
+
const newContent = matter11.stringify(content, data);
|
|
19053
|
+
writeFile2(ini.filePath, newContent);
|
|
19054
|
+
const updated = parseInitiative(dir, ini.filePath, newContent);
|
|
19055
|
+
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after materialization.");
|
|
19056
|
+
return { workItemId: wiId, fileName, initiative: updated };
|
|
19057
|
+
}
|
|
18595
19058
|
|
|
18596
19059
|
// src/tools.ts
|
|
18597
19060
|
var ok = (data) => ({ ok: true, data });
|
|
@@ -18690,9 +19153,9 @@ function markWorkItemReady(root, id, confirm2) {
|
|
|
18690
19153
|
if (!raw) return fail(`Could not read Work Item file: ${item.path}`);
|
|
18691
19154
|
const parsed = matter12(raw);
|
|
18692
19155
|
const data = { ...parsed.data };
|
|
18693
|
-
const
|
|
19156
|
+
const today3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18694
19157
|
data.status = "ready";
|
|
18695
|
-
data.ready_at =
|
|
19158
|
+
data.ready_at = today3;
|
|
18696
19159
|
const newContent = matter12.stringify(parsed.content, data);
|
|
18697
19160
|
const posixPath = item.path.replace(/\\/g, "/");
|
|
18698
19161
|
let newRelPath = item.path;
|
|
@@ -18709,7 +19172,7 @@ function markWorkItemReady(root, id, confirm2) {
|
|
|
18709
19172
|
id: item.id,
|
|
18710
19173
|
from: "draft",
|
|
18711
19174
|
to: "ready",
|
|
18712
|
-
ready_at:
|
|
19175
|
+
ready_at: today3,
|
|
18713
19176
|
moved: newRelPath !== item.path ? { from: item.path, to: newRelPath } : void 0,
|
|
18714
19177
|
...warnings.length > 0 ? { warnings } : {},
|
|
18715
19178
|
next: ["Run kaddo context", "Run kaddo understand"]
|
|
@@ -18932,7 +19395,7 @@ function firstParagraph3(md) {
|
|
|
18932
19395
|
}
|
|
18933
19396
|
return "";
|
|
18934
19397
|
}
|
|
18935
|
-
function
|
|
19398
|
+
function slugify4(s) {
|
|
18936
19399
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
18937
19400
|
}
|
|
18938
19401
|
function modulesListTool(root, args) {
|
|
@@ -19119,7 +19582,7 @@ function extractSection(content, heading) {
|
|
|
19119
19582
|
return out;
|
|
19120
19583
|
}
|
|
19121
19584
|
function buildBranchStrategy(wi, affectedModules, codeEntries, descriptor) {
|
|
19122
|
-
const slug5 =
|
|
19585
|
+
const slug5 = slugify4(wi.title);
|
|
19123
19586
|
const wiLower = wi.id.toLowerCase();
|
|
19124
19587
|
const coreBranch = `feature/${wiLower}-${slug5}`;
|
|
19125
19588
|
const moduleBranches = {};
|
|
@@ -19182,7 +19645,7 @@ function exportCapsuleTool(root, args) {
|
|
|
19182
19645
|
if (!mc) warnings.push("module-context.md not found for this module.");
|
|
19183
19646
|
if (mc && isPlaceholder2(mc)) warnings.push("module-context.md contains placeholder sections.");
|
|
19184
19647
|
capsuleType = "module";
|
|
19185
|
-
capsuleName = `${
|
|
19648
|
+
capsuleName = `${slugify4(config.project?.name ?? "project")}-${args.module}`;
|
|
19186
19649
|
capsuleData = {
|
|
19187
19650
|
type: "knowledge-capsule",
|
|
19188
19651
|
system: `${config.project?.name ?? "unknown"}/${args.module}`,
|
|
@@ -19204,7 +19667,7 @@ function exportCapsuleTool(root, args) {
|
|
|
19204
19667
|
if (mc && isPlaceholder2(mc)) warnings.push("module-context.md contains placeholder sections.");
|
|
19205
19668
|
const modId = config.module?.id ?? args.module;
|
|
19206
19669
|
capsuleType = "module";
|
|
19207
|
-
capsuleName =
|
|
19670
|
+
capsuleName = slugify4(modId);
|
|
19208
19671
|
capsuleData = {
|
|
19209
19672
|
type: "knowledge-capsule",
|
|
19210
19673
|
system: `${config.multirepo?.parent_system ?? "unknown"}/${modId}`,
|
|
@@ -19232,7 +19695,7 @@ function exportCapsuleTool(root, args) {
|
|
|
19232
19695
|
responsibilities.push(mc ? `[${m2.id}] ${firstParagraph3(mc) || m2.name || m2.id}` : `[${m2.id}] ${m2.name || m2.id} (no module-context)`);
|
|
19233
19696
|
}
|
|
19234
19697
|
capsuleType = "system";
|
|
19235
|
-
capsuleName = `${
|
|
19698
|
+
capsuleName = `${slugify4(config.project?.name ?? "project")}-system`;
|
|
19236
19699
|
capsuleData = {
|
|
19237
19700
|
type: "knowledge-capsule",
|
|
19238
19701
|
system: config.project?.name ?? "unknown",
|
|
@@ -19253,7 +19716,7 @@ function exportCapsuleTool(root, args) {
|
|
|
19253
19716
|
if (mc && isPlaceholder2(mc)) warnings.push("module-context.md contains placeholder sections.");
|
|
19254
19717
|
const modId = config.module?.id ?? "module";
|
|
19255
19718
|
capsuleType = "module";
|
|
19256
|
-
capsuleName =
|
|
19719
|
+
capsuleName = slugify4(modId);
|
|
19257
19720
|
capsuleData = {
|
|
19258
19721
|
type: "knowledge-capsule",
|
|
19259
19722
|
system: `${config.multirepo?.parent_system ?? "unknown"}/${modId}`,
|
|
@@ -19269,7 +19732,7 @@ function exportCapsuleTool(root, args) {
|
|
|
19269
19732
|
};
|
|
19270
19733
|
} else {
|
|
19271
19734
|
capsuleType = "project";
|
|
19272
|
-
capsuleName =
|
|
19735
|
+
capsuleName = slugify4(config.project?.name ?? "project");
|
|
19273
19736
|
capsuleData = {
|
|
19274
19737
|
type: "knowledge-capsule",
|
|
19275
19738
|
system: config.project?.name ?? "unknown",
|
|
@@ -19432,7 +19895,7 @@ var PROVENANCE2 = /* @__PURE__ */ new Set(["declared", "derived", "agent-reviewe
|
|
|
19432
19895
|
function isRelative2(p) {
|
|
19433
19896
|
return typeof p === "string" && p.trim() !== "" && !/^([a-zA-Z]:[\\/]|\/)/.test(p) && !p.includes("..");
|
|
19434
19897
|
}
|
|
19435
|
-
function
|
|
19898
|
+
function strList3(v) {
|
|
19436
19899
|
return Array.isArray(v) ? v.map((x2) => typeof x2 === "string" ? x2.trim() : "").filter(Boolean) : [];
|
|
19437
19900
|
}
|
|
19438
19901
|
function loadSystemTopology2(dir) {
|
|
@@ -19473,7 +19936,7 @@ function parseTopologyContent2(raw, dir) {
|
|
|
19473
19936
|
const moduleRaw = typeof e.module === "string" ? e.module.trim() : void 0;
|
|
19474
19937
|
if (moduleRaw && !validModules.has(moduleRaw)) findings.push({ level: "warning", message: `Entity "${id}" references unregistered module "${moduleRaw}".` });
|
|
19475
19938
|
const rawImpl = e.implementation ?? e.implementation_refs;
|
|
19476
|
-
const implementation =
|
|
19939
|
+
const implementation = strList3(rawImpl).filter((p) => {
|
|
19477
19940
|
if (isRelative2(p)) return true;
|
|
19478
19941
|
findings.push({ level: "warning", message: `Entity "${id}" implementation ref "${p}" is not a safe relative path and was dropped.` });
|
|
19479
19942
|
return false;
|
|
@@ -19481,7 +19944,7 @@ function parseTopologyContent2(raw, dir) {
|
|
|
19481
19944
|
const prov = e.provenance;
|
|
19482
19945
|
const provOrigin = typeof prov === "string" ? prov : prov && typeof prov === "object" && typeof prov.origin === "string" ? String(prov.origin) : void 0;
|
|
19483
19946
|
const provenance = provOrigin && PROVENANCE2.has(provOrigin) ? provOrigin : void 0;
|
|
19484
|
-
const evidence =
|
|
19947
|
+
const evidence = strList3(e.evidence ?? (prov && typeof prov === "object" ? prov.evidence_refs : void 0)).filter(isRelative2);
|
|
19485
19948
|
seenIds.add(id);
|
|
19486
19949
|
entities.push({
|
|
19487
19950
|
id,
|
|
@@ -19490,7 +19953,7 @@ function parseTopologyContent2(raw, dir) {
|
|
|
19490
19953
|
...typeof e.purpose === "string" && e.purpose.trim() ? { purpose: e.purpose.trim() } : {},
|
|
19491
19954
|
...moduleRaw && validModules.has(moduleRaw) ? { moduleId: moduleRaw } : {},
|
|
19492
19955
|
implementationRefs: implementation,
|
|
19493
|
-
knowledgeRefs:
|
|
19956
|
+
knowledgeRefs: strList3(e.knowledge ?? e.knowledge_refs),
|
|
19494
19957
|
...provenance ? { provenance } : {},
|
|
19495
19958
|
evidence
|
|
19496
19959
|
});
|
|
@@ -19524,7 +19987,7 @@ function parseTopologyContent2(raw, dir) {
|
|
|
19524
19987
|
}
|
|
19525
19988
|
seenRels.add(key);
|
|
19526
19989
|
const prov = r2.provenance;
|
|
19527
|
-
relationships.push({ from, to, type, evidence:
|
|
19990
|
+
relationships.push({ from, to, type, evidence: strList3(r2.evidence ?? prov?.evidence_refs).filter(isRelative2) });
|
|
19528
19991
|
}
|
|
19529
19992
|
return { entities, relationships, findings, ...sourceRevision ? { sourceRevision } : {} };
|
|
19530
19993
|
}
|
|
@@ -22094,6 +22557,123 @@ function generateCapsuleDraft(root) {
|
|
|
22094
22557
|
};
|
|
22095
22558
|
}
|
|
22096
22559
|
|
|
22560
|
+
// src/initiatives.ts
|
|
22561
|
+
var ok5 = (data) => ({ ok: true, data });
|
|
22562
|
+
var fail4 = (message) => ({ ok: false, message });
|
|
22563
|
+
function listInitiativesTool(root) {
|
|
22564
|
+
const all = discoverInitiatives(root).map((ini) => {
|
|
22565
|
+
const p = computeInitiativeProgress(root, ini);
|
|
22566
|
+
return {
|
|
22567
|
+
id: ini.id,
|
|
22568
|
+
title: ini.title,
|
|
22569
|
+
status: ini.status,
|
|
22570
|
+
planning: p.planning,
|
|
22571
|
+
delivery: p.delivery
|
|
22572
|
+
};
|
|
22573
|
+
});
|
|
22574
|
+
return ok5(all);
|
|
22575
|
+
}
|
|
22576
|
+
function getInitiativeTool(root, id) {
|
|
22577
|
+
const ini = getInitiative(root, id);
|
|
22578
|
+
if (!ini) return fail4(`Initiative ${id} not found.`);
|
|
22579
|
+
return ok5({
|
|
22580
|
+
id: ini.id,
|
|
22581
|
+
title: ini.title,
|
|
22582
|
+
status: ini.status,
|
|
22583
|
+
horizon: ini.horizon,
|
|
22584
|
+
priority: ini.priority,
|
|
22585
|
+
knowledgeLevel: ini.knowledgeLevel,
|
|
22586
|
+
domains: ini.domains,
|
|
22587
|
+
relatedCapabilities: ini.relatedCapabilities,
|
|
22588
|
+
source: ini.source,
|
|
22589
|
+
sourceId: ini.sourceId,
|
|
22590
|
+
externalLinks: ini.externalLinks,
|
|
22591
|
+
candidates: ini.candidates,
|
|
22592
|
+
body: ini.body
|
|
22593
|
+
});
|
|
22594
|
+
}
|
|
22595
|
+
function getInitiativeContextTool(root, id) {
|
|
22596
|
+
const ini = getInitiative(root, id);
|
|
22597
|
+
if (!ini) return fail4(`Initiative ${id} not found.`);
|
|
22598
|
+
return ok5(getInitiativeContext(root, ini));
|
|
22599
|
+
}
|
|
22600
|
+
function getInitiativeProgressTool(root, id) {
|
|
22601
|
+
const ini = getInitiative(root, id);
|
|
22602
|
+
if (!ini) return fail4(`Initiative ${id} not found.`);
|
|
22603
|
+
return ok5(computeInitiativeProgress(root, ini));
|
|
22604
|
+
}
|
|
22605
|
+
function previewOrApply(confirm2, action, effect, apply) {
|
|
22606
|
+
if (!confirm2) {
|
|
22607
|
+
return ok5({ action, effect, instruction: "Call again with confirm=true to apply." });
|
|
22608
|
+
}
|
|
22609
|
+
try {
|
|
22610
|
+
return ok5({ applied: true, result: apply() });
|
|
22611
|
+
} catch (err) {
|
|
22612
|
+
if (err instanceof InitiativeWriteError) return fail4(err.message);
|
|
22613
|
+
throw err;
|
|
22614
|
+
}
|
|
22615
|
+
}
|
|
22616
|
+
function createInitiativeTool(root, args) {
|
|
22617
|
+
if (!args.title?.trim()) return fail4("title is required.");
|
|
22618
|
+
return previewOrApply(
|
|
22619
|
+
args.confirm,
|
|
22620
|
+
"create-initiative",
|
|
22621
|
+
`A new Initiative "${args.title.trim()}" will be created under knowledge/delivery/initiatives/.`,
|
|
22622
|
+
() => createInitiative(root, {
|
|
22623
|
+
title: args.title,
|
|
22624
|
+
domains: args.domains,
|
|
22625
|
+
relatedCapabilities: args.relatedCapabilities,
|
|
22626
|
+
horizon: args.horizon,
|
|
22627
|
+
priority: args.priority
|
|
22628
|
+
})
|
|
22629
|
+
);
|
|
22630
|
+
}
|
|
22631
|
+
function updateInitiativeTool(root, args) {
|
|
22632
|
+
if (!getInitiative(root, args.id)) return fail4(`Initiative ${args.id} not found.`);
|
|
22633
|
+
const changingStatus = typeof args.status === "string";
|
|
22634
|
+
const effect = changingStatus ? `Initiative ${args.id} status will transition to "${args.status}" (valid transitions only).` : `Initiative ${args.id} fields will be updated.`;
|
|
22635
|
+
return previewOrApply(args.confirm, "update-initiative", effect, () => {
|
|
22636
|
+
if (changingStatus) {
|
|
22637
|
+
return transitionInitiative(root, args.id, args.status);
|
|
22638
|
+
}
|
|
22639
|
+
return updateInitiative(root, args.id, {
|
|
22640
|
+
title: args.title,
|
|
22641
|
+
horizon: args.horizon,
|
|
22642
|
+
priority: args.priority,
|
|
22643
|
+
domains: args.domains,
|
|
22644
|
+
relatedCapabilities: args.relatedCapabilities
|
|
22645
|
+
});
|
|
22646
|
+
});
|
|
22647
|
+
}
|
|
22648
|
+
function addInitiativeCandidateTool(root, args) {
|
|
22649
|
+
if (!args.title?.trim()) return fail4("candidate title is required.");
|
|
22650
|
+
if (!getInitiative(root, args.id)) return fail4(`Initiative ${args.id} not found.`);
|
|
22651
|
+
return previewOrApply(
|
|
22652
|
+
args.confirm,
|
|
22653
|
+
"add-initiative-candidate",
|
|
22654
|
+
`A Work Item candidate "${args.title.trim()}" will be added to ${args.id}.`,
|
|
22655
|
+
() => addCandidate(root, args.id, {
|
|
22656
|
+
title: args.title,
|
|
22657
|
+
type: args.type,
|
|
22658
|
+
suggestedKnowledgeLevel: args.suggestedKnowledgeLevel,
|
|
22659
|
+
expectedValue: args.expectedValue,
|
|
22660
|
+
notes: args.notes
|
|
22661
|
+
})
|
|
22662
|
+
);
|
|
22663
|
+
}
|
|
22664
|
+
function materializeInitiativeCandidateTool(root, args) {
|
|
22665
|
+
const ini = getInitiative(root, args.id);
|
|
22666
|
+
if (!ini) return fail4(`Initiative ${args.id} not found.`);
|
|
22667
|
+
const candidate = ini.candidates.find((c) => c.id === args.candidateId);
|
|
22668
|
+
if (!candidate) return fail4(`Candidate ${args.candidateId} not found in ${args.id}.`);
|
|
22669
|
+
return previewOrApply(
|
|
22670
|
+
args.confirm,
|
|
22671
|
+
"materialize-initiative-candidate",
|
|
22672
|
+
`Candidate ${args.candidateId} ("${candidate.title}") will be materialized into a draft Work Item associated to ${args.id}.`,
|
|
22673
|
+
() => materializeCandidate(root, args.id, args.candidateId)
|
|
22674
|
+
);
|
|
22675
|
+
}
|
|
22676
|
+
|
|
22097
22677
|
// src/server.ts
|
|
22098
22678
|
var SERVER_NAME = "kaddo";
|
|
22099
22679
|
var require2 = createRequire(import.meta.url);
|
|
@@ -22490,6 +23070,92 @@ function createServer(root) {
|
|
|
22490
23070
|
},
|
|
22491
23071
|
async (args) => toolText(guarded(root, () => verifyWorkItemTool(root, args)))
|
|
22492
23072
|
);
|
|
23073
|
+
const INITIATIVE_READ_NOTE = "Read-only. Initiatives are an optional outcome/traceability layer over Work Items; a Work Item never requires one.";
|
|
23074
|
+
server.registerTool(
|
|
23075
|
+
"kaddo_list_initiatives",
|
|
23076
|
+
{ title: "List initiatives", description: `List initiatives with planning coverage and delivery progress. ${INITIATIVE_READ_NOTE}`, inputSchema: {} },
|
|
23077
|
+
async () => toolText(guarded(root, () => listInitiativesTool(root)))
|
|
23078
|
+
);
|
|
23079
|
+
server.registerTool(
|
|
23080
|
+
"kaddo_get_initiative",
|
|
23081
|
+
{ title: "Get initiative", description: `Get one initiative: metadata, candidates and body. ${INITIATIVE_READ_NOTE}`, inputSchema: { id: z4.string() } },
|
|
23082
|
+
async (args) => toolText(guarded(root, () => getInitiativeTool(root, args.id)))
|
|
23083
|
+
);
|
|
23084
|
+
server.registerTool(
|
|
23085
|
+
"kaddo_get_initiative_context",
|
|
23086
|
+
{
|
|
23087
|
+
title: "Get initiative context",
|
|
23088
|
+
description: `Focused, initiative-scoped context for analysis: the initiative, progress, candidates (materialized/pending), associated Work Items and external links. Does NOT load the whole project. ${INITIATIVE_READ_NOTE}`,
|
|
23089
|
+
inputSchema: { id: z4.string() }
|
|
23090
|
+
},
|
|
23091
|
+
async (args) => toolText(guarded(root, () => getInitiativeContextTool(root, args.id)))
|
|
23092
|
+
);
|
|
23093
|
+
server.registerTool(
|
|
23094
|
+
"kaddo_get_initiative_progress",
|
|
23095
|
+
{ title: "Get initiative progress", description: `Planning coverage (candidates materialized/total) and delivery progress (Work Items by lifecycle state). ${INITIATIVE_READ_NOTE}`, inputSchema: { id: z4.string() } },
|
|
23096
|
+
async (args) => toolText(guarded(root, () => getInitiativeProgressTool(root, args.id)))
|
|
23097
|
+
);
|
|
23098
|
+
const INITIATIVE_WRITE_NOTE = "Without confirm=true returns a preview. With confirm=true applies the change. Writes only under knowledge/delivery/.";
|
|
23099
|
+
server.registerTool(
|
|
23100
|
+
"kaddo_create_initiative",
|
|
23101
|
+
{
|
|
23102
|
+
title: "Create initiative",
|
|
23103
|
+
description: `Create a new initiative. ${INITIATIVE_WRITE_NOTE}`,
|
|
23104
|
+
inputSchema: {
|
|
23105
|
+
title: z4.string(),
|
|
23106
|
+
domains: z4.array(z4.string()).optional(),
|
|
23107
|
+
relatedCapabilities: z4.array(z4.string()).optional(),
|
|
23108
|
+
horizon: z4.string().optional(),
|
|
23109
|
+
priority: z4.string().optional(),
|
|
23110
|
+
confirm: z4.boolean().optional()
|
|
23111
|
+
}
|
|
23112
|
+
},
|
|
23113
|
+
async (args) => toolText(guarded(root, () => createInitiativeTool(root, args)))
|
|
23114
|
+
);
|
|
23115
|
+
server.registerTool(
|
|
23116
|
+
"kaddo_update_initiative",
|
|
23117
|
+
{
|
|
23118
|
+
title: "Update initiative",
|
|
23119
|
+
description: `Update an initiative's status (valid lifecycle transitions only) or non-lifecycle fields. ${INITIATIVE_WRITE_NOTE}`,
|
|
23120
|
+
inputSchema: {
|
|
23121
|
+
id: z4.string(),
|
|
23122
|
+
status: z4.enum(["planned", "in-progress", "completed", "deferred", "cancelled"]).optional(),
|
|
23123
|
+
title: z4.string().optional(),
|
|
23124
|
+
horizon: z4.string().optional(),
|
|
23125
|
+
priority: z4.string().optional(),
|
|
23126
|
+
domains: z4.array(z4.string()).optional(),
|
|
23127
|
+
relatedCapabilities: z4.array(z4.string()).optional(),
|
|
23128
|
+
confirm: z4.boolean().optional()
|
|
23129
|
+
}
|
|
23130
|
+
},
|
|
23131
|
+
async (args) => toolText(guarded(root, () => updateInitiativeTool(root, args)))
|
|
23132
|
+
);
|
|
23133
|
+
server.registerTool(
|
|
23134
|
+
"kaddo_add_initiative_candidate",
|
|
23135
|
+
{
|
|
23136
|
+
title: "Add initiative candidate",
|
|
23137
|
+
description: `Add a Work Item candidate to an initiative (not yet materialized). ${INITIATIVE_WRITE_NOTE}`,
|
|
23138
|
+
inputSchema: {
|
|
23139
|
+
id: z4.string(),
|
|
23140
|
+
title: z4.string(),
|
|
23141
|
+
type: z4.string().optional(),
|
|
23142
|
+
suggestedKnowledgeLevel: z4.string().optional(),
|
|
23143
|
+
expectedValue: z4.string().optional(),
|
|
23144
|
+
notes: z4.string().optional(),
|
|
23145
|
+
confirm: z4.boolean().optional()
|
|
23146
|
+
}
|
|
23147
|
+
},
|
|
23148
|
+
async (args) => toolText(guarded(root, () => addInitiativeCandidateTool(root, args)))
|
|
23149
|
+
);
|
|
23150
|
+
server.registerTool(
|
|
23151
|
+
"kaddo_materialize_initiative_candidate",
|
|
23152
|
+
{
|
|
23153
|
+
title: "Materialize initiative candidate",
|
|
23154
|
+
description: `Materialize an initiative candidate into a draft Work Item associated via \`initiative: INI-xxx\`. ${INITIATIVE_WRITE_NOTE}`,
|
|
23155
|
+
inputSchema: { id: z4.string(), candidateId: z4.string(), confirm: z4.boolean().optional() }
|
|
23156
|
+
},
|
|
23157
|
+
async (args) => toolText(guarded(root, () => materializeInitiativeCandidateTool(root, args)))
|
|
23158
|
+
);
|
|
22493
23159
|
server.registerTool(
|
|
22494
23160
|
"kaddo_telemetry_status",
|
|
22495
23161
|
{
|
package/package.json
CHANGED