@kaddo/mcp 3.104.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.
Files changed (2) hide show
  1. package/dist/index.js +707 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10783,7 +10783,7 @@ function getPrompt(root, name) {
10783
10783
  }
10784
10784
 
10785
10785
  // src/tools.ts
10786
- import matter11 from "gray-matter";
10786
+ import matter12 from "gray-matter";
10787
10787
 
10788
10788
  // ../cli/dist/core.js
10789
10789
  import fs3 from "fs";
@@ -10816,6 +10816,8 @@ import matter82 from "gray-matter";
10816
10816
  import matter92 from "gray-matter";
10817
10817
  import { parse as parseYaml92, stringify as stringifyYaml5 } from "yaml";
10818
10818
  import { parse as parseYaml102, stringify as stringifyYaml6 } from "yaml";
10819
+ import matter102 from "gray-matter";
10820
+ import matter11 from "gray-matter";
10819
10821
  function exists2(p) {
10820
10822
  return fs3.existsSync(p);
10821
10823
  }
@@ -10826,6 +10828,9 @@ function writeFile2(filePath, content) {
10826
10828
  fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
10827
10829
  fs3.writeFileSync(filePath, content, "utf-8");
10828
10830
  }
10831
+ function ensureDir2(dirPath) {
10832
+ fs3.mkdirSync(dirPath, { recursive: true });
10833
+ }
10829
10834
  function readDir2(dirPath) {
10830
10835
  if (!exists2(dirPath)) return [];
10831
10836
  return fs3.readdirSync(dirPath);
@@ -11069,6 +11074,9 @@ function lifecycleStateOf2(item) {
11069
11074
  if (folder) return folder;
11070
11075
  return "ready";
11071
11076
  }
11077
+ function emptyLifecycleCounts2() {
11078
+ return Object.fromEntries(LIFECYCLE_STATES2.map((s) => [s, 0]));
11079
+ }
11072
11080
  var ARCH_DIR3 = "knowledge";
11073
11081
  function toPosix6(p) {
11074
11082
  return p.replace(/\\/g, "/");
@@ -16965,7 +16973,7 @@ function createWorkItem(dir, opts) {
16965
16973
  if (!type) throw new WorkItemWriteError("INVALID_INPUT", `Unknown Work Item type "${opts.type}".`);
16966
16974
  const id = nextWorkItemId(dir);
16967
16975
  const title = intent.split(/\r?\n/)[0].trim().slice(0, 120);
16968
- const today2 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
16976
+ const today22 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
16969
16977
  const source = opts.source ? { ...opts.source, inferred: false } : { type: "manual", inferred: false };
16970
16978
  const data = {
16971
16979
  type,
@@ -16973,7 +16981,7 @@ function createWorkItem(dir, opts) {
16973
16981
  title,
16974
16982
  status: "draft",
16975
16983
  work_type: type,
16976
- created_at: today2,
16984
+ created_at: today22,
16977
16985
  source,
16978
16986
  generated_by: "kaddo-admin",
16979
16987
  affected_modules: [],
@@ -18579,6 +18587,474 @@ function getStatus(dir) {
18579
18587
  lastError: null
18580
18588
  };
18581
18589
  }
18590
+ var INITIATIVES_DIR = "knowledge/delivery/initiatives";
18591
+ var INITIATIVE_STATES = [
18592
+ "candidate",
18593
+ "planned",
18594
+ "in-progress",
18595
+ "completed",
18596
+ "deferred",
18597
+ "cancelled"
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
+ };
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
+ }
18785
+ var WORK_ITEMS_DIR2 = "knowledge/delivery/work-items";
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
+ }
18582
19058
 
18583
19059
  // src/tools.ts
18584
19060
  var ok = (data) => ({ ok: true, data });
@@ -18675,12 +19151,12 @@ function markWorkItemReady(root, id, confirm2) {
18675
19151
  }
18676
19152
  const raw = readText(root, item.path);
18677
19153
  if (!raw) return fail(`Could not read Work Item file: ${item.path}`);
18678
- const parsed = matter11(raw);
19154
+ const parsed = matter12(raw);
18679
19155
  const data = { ...parsed.data };
18680
- const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19156
+ const today3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
18681
19157
  data.status = "ready";
18682
- data.ready_at = today2;
18683
- const newContent = matter11.stringify(parsed.content, data);
19158
+ data.ready_at = today3;
19159
+ const newContent = matter12.stringify(parsed.content, data);
18684
19160
  const posixPath = item.path.replace(/\\/g, "/");
18685
19161
  let newRelPath = item.path;
18686
19162
  if (posixPath.includes("/work-items/draft/")) {
@@ -18696,7 +19172,7 @@ function markWorkItemReady(root, id, confirm2) {
18696
19172
  id: item.id,
18697
19173
  from: "draft",
18698
19174
  to: "ready",
18699
- ready_at: today2,
19175
+ ready_at: today3,
18700
19176
  moved: newRelPath !== item.path ? { from: item.path, to: newRelPath } : void 0,
18701
19177
  ...warnings.length > 0 ? { warnings } : {},
18702
19178
  next: ["Run kaddo context", "Run kaddo understand"]
@@ -18847,7 +19323,7 @@ function setTelemetryConsentTool(root, args) {
18847
19323
  // src/multirepo.ts
18848
19324
  import fs5 from "fs";
18849
19325
  import path4 from "path";
18850
- import matter12 from "gray-matter";
19326
+ import matter13 from "gray-matter";
18851
19327
  import { parse as parseYaml11, stringify as stringifyYaml7 } from "yaml";
18852
19328
  var ok2 = (data) => ({ ok: true, data });
18853
19329
  var fail2 = (message) => ({ ok: false, message });
@@ -18919,7 +19395,7 @@ function firstParagraph3(md) {
18919
19395
  }
18920
19396
  return "";
18921
19397
  }
18922
- function slugify3(s) {
19398
+ function slugify4(s) {
18923
19399
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
18924
19400
  }
18925
19401
  function modulesListTool(root, args) {
@@ -18999,7 +19475,7 @@ function validateWorkItemModulesTool(root, args) {
18999
19475
  if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
19000
19476
  const raw = readText(root, wi.path);
19001
19477
  if (!raw) return fail2(`Could not read Work Item file.`);
19002
- const parsed = matter12(raw);
19478
+ const parsed = matter13(raw);
19003
19479
  const data = parsed.data;
19004
19480
  const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
19005
19481
  const codeEntries = Array.isArray(data.code) ? data.code.filter((c) => typeof c === "object" && c !== null).map((c) => ({ repo: typeof c.repo === "string" ? c.repo : void 0, paths: Array.isArray(c.paths) ? c.paths.map(String) : [] })) : [];
@@ -19052,7 +19528,7 @@ function getWorkItemContextTool(root, args) {
19052
19528
  if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
19053
19529
  const raw = readText(root, wi.path);
19054
19530
  if (!raw) return fail2(`Could not read Work Item file.`);
19055
- const parsed = matter12(raw);
19531
+ const parsed = matter13(raw);
19056
19532
  const data = parsed.data;
19057
19533
  const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
19058
19534
  const codeEntries = Array.isArray(data.code) ? data.code.filter((c) => typeof c === "object" && c !== null).map((c) => ({ repo: typeof c.repo === "string" ? c.repo : void 0, paths: Array.isArray(c.paths) ? c.paths.map(String) : [] })) : [];
@@ -19106,7 +19582,7 @@ function extractSection(content, heading) {
19106
19582
  return out;
19107
19583
  }
19108
19584
  function buildBranchStrategy(wi, affectedModules, codeEntries, descriptor) {
19109
- const slug5 = slugify3(wi.title);
19585
+ const slug5 = slugify4(wi.title);
19110
19586
  const wiLower = wi.id.toLowerCase();
19111
19587
  const coreBranch = `feature/${wiLower}-${slug5}`;
19112
19588
  const moduleBranches = {};
@@ -19138,7 +19614,7 @@ function suggestBranchStrategyTool(root, args) {
19138
19614
  if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
19139
19615
  const raw = readText(root, wi.path);
19140
19616
  if (!raw) return fail2(`Could not read Work Item file.`);
19141
- const parsed = matter12(raw);
19617
+ const parsed = matter13(raw);
19142
19618
  const data = parsed.data;
19143
19619
  const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
19144
19620
  const codeEntries = Array.isArray(data.code) ? data.code.filter((c) => typeof c === "object" && c !== null).map((c) => ({ repo: typeof c.repo === "string" ? c.repo : void 0, paths: Array.isArray(c.paths) ? c.paths.map(String) : [] })) : [];
@@ -19169,7 +19645,7 @@ function exportCapsuleTool(root, args) {
19169
19645
  if (!mc) warnings.push("module-context.md not found for this module.");
19170
19646
  if (mc && isPlaceholder2(mc)) warnings.push("module-context.md contains placeholder sections.");
19171
19647
  capsuleType = "module";
19172
- capsuleName = `${slugify3(config.project?.name ?? "project")}-${args.module}`;
19648
+ capsuleName = `${slugify4(config.project?.name ?? "project")}-${args.module}`;
19173
19649
  capsuleData = {
19174
19650
  type: "knowledge-capsule",
19175
19651
  system: `${config.project?.name ?? "unknown"}/${args.module}`,
@@ -19191,7 +19667,7 @@ function exportCapsuleTool(root, args) {
19191
19667
  if (mc && isPlaceholder2(mc)) warnings.push("module-context.md contains placeholder sections.");
19192
19668
  const modId = config.module?.id ?? args.module;
19193
19669
  capsuleType = "module";
19194
- capsuleName = slugify3(modId);
19670
+ capsuleName = slugify4(modId);
19195
19671
  capsuleData = {
19196
19672
  type: "knowledge-capsule",
19197
19673
  system: `${config.multirepo?.parent_system ?? "unknown"}/${modId}`,
@@ -19219,7 +19695,7 @@ function exportCapsuleTool(root, args) {
19219
19695
  responsibilities.push(mc ? `[${m2.id}] ${firstParagraph3(mc) || m2.name || m2.id}` : `[${m2.id}] ${m2.name || m2.id} (no module-context)`);
19220
19696
  }
19221
19697
  capsuleType = "system";
19222
- capsuleName = `${slugify3(config.project?.name ?? "project")}-system`;
19698
+ capsuleName = `${slugify4(config.project?.name ?? "project")}-system`;
19223
19699
  capsuleData = {
19224
19700
  type: "knowledge-capsule",
19225
19701
  system: config.project?.name ?? "unknown",
@@ -19240,7 +19716,7 @@ function exportCapsuleTool(root, args) {
19240
19716
  if (mc && isPlaceholder2(mc)) warnings.push("module-context.md contains placeholder sections.");
19241
19717
  const modId = config.module?.id ?? "module";
19242
19718
  capsuleType = "module";
19243
- capsuleName = slugify3(modId);
19719
+ capsuleName = slugify4(modId);
19244
19720
  capsuleData = {
19245
19721
  type: "knowledge-capsule",
19246
19722
  system: `${config.multirepo?.parent_system ?? "unknown"}/${modId}`,
@@ -19256,7 +19732,7 @@ function exportCapsuleTool(root, args) {
19256
19732
  };
19257
19733
  } else {
19258
19734
  capsuleType = "project";
19259
- capsuleName = slugify3(config.project?.name ?? "project");
19735
+ capsuleName = slugify4(config.project?.name ?? "project");
19260
19736
  capsuleData = {
19261
19737
  type: "knowledge-capsule",
19262
19738
  system: config.project?.name ?? "unknown",
@@ -19419,7 +19895,7 @@ var PROVENANCE2 = /* @__PURE__ */ new Set(["declared", "derived", "agent-reviewe
19419
19895
  function isRelative2(p) {
19420
19896
  return typeof p === "string" && p.trim() !== "" && !/^([a-zA-Z]:[\\/]|\/)/.test(p) && !p.includes("..");
19421
19897
  }
19422
- function strList2(v) {
19898
+ function strList3(v) {
19423
19899
  return Array.isArray(v) ? v.map((x2) => typeof x2 === "string" ? x2.trim() : "").filter(Boolean) : [];
19424
19900
  }
19425
19901
  function loadSystemTopology2(dir) {
@@ -19460,7 +19936,7 @@ function parseTopologyContent2(raw, dir) {
19460
19936
  const moduleRaw = typeof e.module === "string" ? e.module.trim() : void 0;
19461
19937
  if (moduleRaw && !validModules.has(moduleRaw)) findings.push({ level: "warning", message: `Entity "${id}" references unregistered module "${moduleRaw}".` });
19462
19938
  const rawImpl = e.implementation ?? e.implementation_refs;
19463
- const implementation = strList2(rawImpl).filter((p) => {
19939
+ const implementation = strList3(rawImpl).filter((p) => {
19464
19940
  if (isRelative2(p)) return true;
19465
19941
  findings.push({ level: "warning", message: `Entity "${id}" implementation ref "${p}" is not a safe relative path and was dropped.` });
19466
19942
  return false;
@@ -19468,7 +19944,7 @@ function parseTopologyContent2(raw, dir) {
19468
19944
  const prov = e.provenance;
19469
19945
  const provOrigin = typeof prov === "string" ? prov : prov && typeof prov === "object" && typeof prov.origin === "string" ? String(prov.origin) : void 0;
19470
19946
  const provenance = provOrigin && PROVENANCE2.has(provOrigin) ? provOrigin : void 0;
19471
- const evidence = strList2(e.evidence ?? (prov && typeof prov === "object" ? prov.evidence_refs : void 0)).filter(isRelative2);
19947
+ const evidence = strList3(e.evidence ?? (prov && typeof prov === "object" ? prov.evidence_refs : void 0)).filter(isRelative2);
19472
19948
  seenIds.add(id);
19473
19949
  entities.push({
19474
19950
  id,
@@ -19477,7 +19953,7 @@ function parseTopologyContent2(raw, dir) {
19477
19953
  ...typeof e.purpose === "string" && e.purpose.trim() ? { purpose: e.purpose.trim() } : {},
19478
19954
  ...moduleRaw && validModules.has(moduleRaw) ? { moduleId: moduleRaw } : {},
19479
19955
  implementationRefs: implementation,
19480
- knowledgeRefs: strList2(e.knowledge ?? e.knowledge_refs),
19956
+ knowledgeRefs: strList3(e.knowledge ?? e.knowledge_refs),
19481
19957
  ...provenance ? { provenance } : {},
19482
19958
  evidence
19483
19959
  });
@@ -19511,7 +19987,7 @@ function parseTopologyContent2(raw, dir) {
19511
19987
  }
19512
19988
  seenRels.add(key);
19513
19989
  const prov = r2.provenance;
19514
- relationships.push({ from, to, type, evidence: strList2(r2.evidence ?? prov?.evidence_refs).filter(isRelative2) });
19990
+ relationships.push({ from, to, type, evidence: strList3(r2.evidence ?? prov?.evidence_refs).filter(isRelative2) });
19515
19991
  }
19516
19992
  return { entities, relationships, findings, ...sourceRevision ? { sourceRevision } : {} };
19517
19993
  }
@@ -19898,14 +20374,14 @@ function systemImpactCandidatesTool(root, args) {
19898
20374
  }
19899
20375
 
19900
20376
  // ../cli/src/services/integrations.ts
19901
- import matter14 from "gray-matter";
20377
+ import matter15 from "gray-matter";
19902
20378
  import { parse as parseYaml13, stringify as stringifyYaml9 } from "yaml";
19903
20379
 
19904
20380
  // ../cli/src/core/work-item-write.ts
19905
20381
  import fs7 from "fs";
19906
20382
  import path6 from "path";
19907
20383
  import crypto4 from "crypto";
19908
- import matter13 from "gray-matter";
20384
+ import matter14 from "gray-matter";
19909
20385
  var SECTION_ORDER2 = [
19910
20386
  "Actor",
19911
20387
  "Outcome",
@@ -20953,7 +21429,7 @@ async function integrationsWorkItemTool(root, args) {
20953
21429
  }
20954
21430
 
20955
21431
  // ../cli/src/core/context-pack.ts
20956
- import matter15 from "gray-matter";
21432
+ import matter16 from "gray-matter";
20957
21433
  var CONTEXT_PACK_VERSION = "1";
20958
21434
  var ARCH_DIR4 = "knowledge";
20959
21435
  function readScanJson(dir) {
@@ -20966,7 +21442,7 @@ function readScanJson(dir) {
20966
21442
  }
20967
21443
  }
20968
21444
  function firstParagraph4(markdown) {
20969
- const body = matter15(markdown).content.trim();
21445
+ const body = matter16(markdown).content.trim();
20970
21446
  const para = body.split("\n\n").map((p) => p.trim()).find((p) => p && !p.startsWith("#"));
20971
21447
  return para ?? "";
20972
21448
  }
@@ -22081,6 +22557,123 @@ function generateCapsuleDraft(root) {
22081
22557
  };
22082
22558
  }
22083
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
+
22084
22677
  // src/server.ts
22085
22678
  var SERVER_NAME = "kaddo";
22086
22679
  var require2 = createRequire(import.meta.url);
@@ -22477,6 +23070,92 @@ function createServer(root) {
22477
23070
  },
22478
23071
  async (args) => toolText(guarded(root, () => verifyWorkItemTool(root, args)))
22479
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
+ );
22480
23159
  server.registerTool(
22481
23160
  "kaddo_telemetry_status",
22482
23161
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.104.0",
3
+ "version": "3.106.0",
4
4
  "description": "MCP server for Kaddo project knowledge: read-only resources/tools/prompts plus safe derived generation under .kaddo/.",
5
5
  "license": "MIT",
6
6
  "repository": {