@kaddo/mcp 3.102.0 → 3.104.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 +205 -47
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -464,7 +464,9 @@ var configSchema = z.object({
|
|
|
464
464
|
guard: z.unknown().optional(),
|
|
465
465
|
scan: z.unknown().optional(),
|
|
466
466
|
telemetry: z.object({
|
|
467
|
-
|
|
467
|
+
consent: z.enum(["enabled", "disabled"]).optional(),
|
|
468
|
+
consentVersion: z.number().optional(),
|
|
469
|
+
enabled: z.boolean().optional()
|
|
468
470
|
}).passthrough().optional()
|
|
469
471
|
}).passthrough();
|
|
470
472
|
function configPathFor(dir) {
|
|
@@ -10813,18 +10815,23 @@ import fs4 from "fs";
|
|
|
10813
10815
|
import matter82 from "gray-matter";
|
|
10814
10816
|
import matter92 from "gray-matter";
|
|
10815
10817
|
import { parse as parseYaml92, stringify as stringifyYaml5 } from "yaml";
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
+
import { parse as parseYaml102, stringify as stringifyYaml6 } from "yaml";
|
|
10819
|
+
function exists2(p) {
|
|
10820
|
+
return fs3.existsSync(p);
|
|
10818
10821
|
}
|
|
10819
|
-
function readFile2(
|
|
10820
|
-
return fs3.readFileSync(
|
|
10822
|
+
function readFile2(p) {
|
|
10823
|
+
return fs3.readFileSync(p, "utf-8");
|
|
10824
|
+
}
|
|
10825
|
+
function writeFile2(filePath, content) {
|
|
10826
|
+
fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
|
|
10827
|
+
fs3.writeFileSync(filePath, content, "utf-8");
|
|
10821
10828
|
}
|
|
10822
10829
|
function readDir2(dirPath) {
|
|
10823
10830
|
if (!exists2(dirPath)) return [];
|
|
10824
10831
|
return fs3.readdirSync(dirPath);
|
|
10825
10832
|
}
|
|
10826
|
-
function isFile2(
|
|
10827
|
-
return exists2(
|
|
10833
|
+
function isFile2(p) {
|
|
10834
|
+
return exists2(p) && fs3.statSync(p).isFile();
|
|
10828
10835
|
}
|
|
10829
10836
|
function join3(...parts) {
|
|
10830
10837
|
return path3.join(...parts);
|
|
@@ -10895,7 +10902,9 @@ var configSchema2 = z3.object({
|
|
|
10895
10902
|
guard: z3.unknown().optional(),
|
|
10896
10903
|
scan: z3.unknown().optional(),
|
|
10897
10904
|
telemetry: z3.object({
|
|
10898
|
-
|
|
10905
|
+
consent: z3.enum(["enabled", "disabled"]).optional(),
|
|
10906
|
+
consentVersion: z3.number().optional(),
|
|
10907
|
+
enabled: z3.boolean().optional()
|
|
10899
10908
|
}).passthrough().optional()
|
|
10900
10909
|
}).passthrough();
|
|
10901
10910
|
function configPathFor2(dir) {
|
|
@@ -11047,8 +11056,8 @@ function isActiveState2(s) {
|
|
|
11047
11056
|
return ACTIVE_STATES3.includes(s);
|
|
11048
11057
|
}
|
|
11049
11058
|
function lifecycleFolderOf2(filePath) {
|
|
11050
|
-
const
|
|
11051
|
-
const m2 =
|
|
11059
|
+
const p = filePath.replace(/\\/g, "/");
|
|
11060
|
+
const m2 = p.match(/\/delivery\/work-items\/([^/]+)\//);
|
|
11052
11061
|
if (m2 && isLifecycleState2(m2[1])) return m2[1];
|
|
11053
11062
|
return null;
|
|
11054
11063
|
}
|
|
@@ -11061,8 +11070,8 @@ function lifecycleStateOf2(item) {
|
|
|
11061
11070
|
return "ready";
|
|
11062
11071
|
}
|
|
11063
11072
|
var ARCH_DIR3 = "knowledge";
|
|
11064
|
-
function toPosix6(
|
|
11065
|
-
return
|
|
11073
|
+
function toPosix6(p) {
|
|
11074
|
+
return p.replace(/\\/g, "/");
|
|
11066
11075
|
}
|
|
11067
11076
|
function relativeTo2(dir, filePath) {
|
|
11068
11077
|
const base = toPosix6(dir).replace(/\/+$/, "");
|
|
@@ -12307,10 +12316,10 @@ ${QUALITY2}
|
|
|
12307
12316
|
`;
|
|
12308
12317
|
var EXTERNAL_PATH2 = ".kaddo/external.yml";
|
|
12309
12318
|
function loadExternalRegistry2(dir) {
|
|
12310
|
-
const
|
|
12311
|
-
if (!exists2(
|
|
12319
|
+
const p = join3(dir, EXTERNAL_PATH2);
|
|
12320
|
+
if (!exists2(p)) return [];
|
|
12312
12321
|
try {
|
|
12313
|
-
const parsed = parseYaml62(readFile2(
|
|
12322
|
+
const parsed = parseYaml62(readFile2(p));
|
|
12314
12323
|
return Array.isArray(parsed?.external) ? parsed.external : [];
|
|
12315
12324
|
} catch {
|
|
12316
12325
|
return [];
|
|
@@ -12322,8 +12331,8 @@ var ALL_STATUSES2 = ["draft", "ready", "in-progress", "blocked", "completed"];
|
|
|
12322
12331
|
function scopeStatuses2(scope) {
|
|
12323
12332
|
return scope === "all" ? { included: ALL_STATUSES2, excluded: ["archived"] } : { included: ACTIVE_STATUSES2, excluded: ["completed", "archived"] };
|
|
12324
12333
|
}
|
|
12325
|
-
function toPosix22(
|
|
12326
|
-
return
|
|
12334
|
+
function toPosix22(p) {
|
|
12335
|
+
return p.replace(/\\/g, "/");
|
|
12327
12336
|
}
|
|
12328
12337
|
function slug3(s) {
|
|
12329
12338
|
return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -12461,8 +12470,8 @@ function buildGraph2(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
12461
12470
|
};
|
|
12462
12471
|
}
|
|
12463
12472
|
var KNOWLEDGE32 = "knowledge";
|
|
12464
|
-
function toPosix32(
|
|
12465
|
-
return
|
|
12473
|
+
function toPosix32(p) {
|
|
12474
|
+
return p.replace(/\\/g, "/");
|
|
12466
12475
|
}
|
|
12467
12476
|
function slug22(s) {
|
|
12468
12477
|
return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -12471,9 +12480,9 @@ function isAdr22(a2) {
|
|
|
12471
12480
|
return toPosix32(a2.filePath).includes("/tech/decisions/") && Boolean(a2.type);
|
|
12472
12481
|
}
|
|
12473
12482
|
function capabilityHeadings2(dir) {
|
|
12474
|
-
const
|
|
12475
|
-
if (!exists2(
|
|
12476
|
-
return readFile2(
|
|
12483
|
+
const p = join3(dir, KNOWLEDGE32, "product", "capabilities.md");
|
|
12484
|
+
if (!exists2(p)) return [];
|
|
12485
|
+
return readFile2(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));
|
|
12477
12486
|
}
|
|
12478
12487
|
function humanMissing2(field) {
|
|
12479
12488
|
switch (field) {
|
|
@@ -15779,7 +15788,7 @@ var AGENT_PROMPTS2 = [
|
|
|
15779
15788
|
// Graph relationship quality (metadata hints → precise front matter — VS-056)
|
|
15780
15789
|
{ fileName: "graph-agent.md", content: GRAPH_AGENT2 }
|
|
15781
15790
|
// Every official prompt ends with its responsibility boundaries + Agent Trace footer.
|
|
15782
|
-
].map((
|
|
15791
|
+
].map((p) => ({ fileName: p.fileName, content: withResponsibilityTrace2(p.fileName, p.content) }));
|
|
15783
15792
|
function withAgentFrontMatter2(fileName, content) {
|
|
15784
15793
|
const name = fileName.replace(/\.md$/, "");
|
|
15785
15794
|
const fm = [
|
|
@@ -16418,8 +16427,8 @@ var TECHNICAL_RELATIONSHIP_TYPES = /* @__PURE__ */ new Set([
|
|
|
16418
16427
|
"implemented-by"
|
|
16419
16428
|
]);
|
|
16420
16429
|
var PROVENANCE = /* @__PURE__ */ new Set(["declared", "derived", "agent-reviewed"]);
|
|
16421
|
-
function isRelative(
|
|
16422
|
-
return typeof
|
|
16430
|
+
function isRelative(p) {
|
|
16431
|
+
return typeof p === "string" && p.trim() !== "" && !/^([a-zA-Z]:[\\/]|\/)/.test(p) && !p.includes("..");
|
|
16423
16432
|
}
|
|
16424
16433
|
function strList(v) {
|
|
16425
16434
|
return Array.isArray(v) ? v.map((x2) => typeof x2 === "string" ? x2.trim() : "").filter(Boolean) : [];
|
|
@@ -16462,9 +16471,9 @@ function parseTopologyContent(raw, dir) {
|
|
|
16462
16471
|
const moduleRaw = typeof e.module === "string" ? e.module.trim() : void 0;
|
|
16463
16472
|
if (moduleRaw && !validModules.has(moduleRaw)) findings.push({ level: "warning", message: `Entity "${id}" references unregistered module "${moduleRaw}".` });
|
|
16464
16473
|
const rawImpl = e.implementation ?? e.implementation_refs;
|
|
16465
|
-
const implementation = strList(rawImpl).filter((
|
|
16466
|
-
if (isRelative(
|
|
16467
|
-
findings.push({ level: "warning", message: `Entity "${id}" implementation ref "${
|
|
16474
|
+
const implementation = strList(rawImpl).filter((p) => {
|
|
16475
|
+
if (isRelative(p)) return true;
|
|
16476
|
+
findings.push({ level: "warning", message: `Entity "${id}" implementation ref "${p}" is not a safe relative path and was dropped.` });
|
|
16468
16477
|
return false;
|
|
16469
16478
|
});
|
|
16470
16479
|
const prov = e.provenance;
|
|
@@ -16672,8 +16681,8 @@ function splitSections(body) {
|
|
|
16672
16681
|
flush();
|
|
16673
16682
|
return sections;
|
|
16674
16683
|
}
|
|
16675
|
-
function isPlaceholder(
|
|
16676
|
-
const t =
|
|
16684
|
+
function isPlaceholder(text22) {
|
|
16685
|
+
const t = text22.trim();
|
|
16677
16686
|
if (!t) return true;
|
|
16678
16687
|
if (/^tbd$/i.test(t)) return true;
|
|
16679
16688
|
if (/^_[^_]*_$/.test(t) && !t.includes("\n")) return true;
|
|
@@ -16700,15 +16709,15 @@ function extractBullets(body) {
|
|
|
16700
16709
|
for (const line of body.split(/\r?\n/)) {
|
|
16701
16710
|
const m2 = line.match(/^\s*[-*+]\s+(.*)$/);
|
|
16702
16711
|
if (!m2) continue;
|
|
16703
|
-
let
|
|
16712
|
+
let text22 = m2[1].trim();
|
|
16704
16713
|
let checked = null;
|
|
16705
|
-
const cb =
|
|
16714
|
+
const cb = text22.match(/^\[([ xX])\]\s*(.*)$/);
|
|
16706
16715
|
if (cb) {
|
|
16707
16716
|
checked = cb[1].toLowerCase() === "x";
|
|
16708
|
-
|
|
16717
|
+
text22 = cb[2].trim();
|
|
16709
16718
|
}
|
|
16710
|
-
if (!
|
|
16711
|
-
out.push({ text:
|
|
16719
|
+
if (!text22 || isPlaceholder(text22)) continue;
|
|
16720
|
+
out.push({ text: text22, checked });
|
|
16712
16721
|
}
|
|
16713
16722
|
return out;
|
|
16714
16723
|
}
|
|
@@ -17453,7 +17462,7 @@ var SECRET_PATTERNS = [
|
|
|
17453
17462
|
/\.pfx$/i
|
|
17454
17463
|
];
|
|
17455
17464
|
function filterSecretPaths(paths) {
|
|
17456
|
-
return paths.filter((
|
|
17465
|
+
return paths.filter((p) => !SECRET_PATTERNS.some((re) => re.test(p)));
|
|
17457
17466
|
}
|
|
17458
17467
|
function collectImplementationEvidence(dir, workItemId, input) {
|
|
17459
17468
|
const artifacts = discoverWorkItems2(dir);
|
|
@@ -18484,6 +18493,92 @@ function createDefaultRegistry() {
|
|
|
18484
18493
|
return registry22;
|
|
18485
18494
|
}
|
|
18486
18495
|
var registry = createDefaultRegistry();
|
|
18496
|
+
var CURRENT_CONSENT_VERSION = 1;
|
|
18497
|
+
var DEFERRAL_DURATION_MS = 24 * 60 * 60 * 1e3;
|
|
18498
|
+
function getConsentState(config) {
|
|
18499
|
+
if (!config) return "unset";
|
|
18500
|
+
const t = config.telemetry;
|
|
18501
|
+
if (!t) return "unset";
|
|
18502
|
+
if (t.consent === "enabled") return "enabled";
|
|
18503
|
+
if (t.consent === "disabled") return "disabled";
|
|
18504
|
+
if (t.consent === void 0) {
|
|
18505
|
+
if (t.enabled === true) return "enabled";
|
|
18506
|
+
if (t.enabled === false) return "disabled";
|
|
18507
|
+
}
|
|
18508
|
+
return "unset";
|
|
18509
|
+
}
|
|
18510
|
+
function persistConsent(dir, consent) {
|
|
18511
|
+
const configPath = join3(dir, ".kaddo", "config.yml");
|
|
18512
|
+
if (!exists2(configPath)) return;
|
|
18513
|
+
const raw = readFile2(configPath);
|
|
18514
|
+
const doc = parseYaml102(raw) ?? {};
|
|
18515
|
+
const prev = doc.telemetry ?? {};
|
|
18516
|
+
delete prev.enabled;
|
|
18517
|
+
doc.telemetry = { ...prev, consent, consentVersion: CURRENT_CONSENT_VERSION };
|
|
18518
|
+
writeFile2(configPath, stringifyYaml6(doc));
|
|
18519
|
+
}
|
|
18520
|
+
function isDeferralActive(dir) {
|
|
18521
|
+
const p = join3(dir, ".kaddo", "telemetry-deferred.json");
|
|
18522
|
+
if (!exists2(p)) return false;
|
|
18523
|
+
try {
|
|
18524
|
+
const data = JSON.parse(readFile2(p));
|
|
18525
|
+
return data.deferredUntil > Date.now();
|
|
18526
|
+
} catch {
|
|
18527
|
+
return false;
|
|
18528
|
+
}
|
|
18529
|
+
}
|
|
18530
|
+
function deferConsent(dir) {
|
|
18531
|
+
const p = join3(dir, ".kaddo", "telemetry-deferred.json");
|
|
18532
|
+
writeFile2(p, JSON.stringify({ deferredUntil: Date.now() + DEFERRAL_DURATION_MS }));
|
|
18533
|
+
}
|
|
18534
|
+
function consentNotice() {
|
|
18535
|
+
return '[Telemetry consent] Anonymous usage telemetry has not been configured.\n Collects: command usage, version, lifecycle events.\n Never collects: source code, knowledge, prompts or PII.\n Use kaddo_set_telemetry_consent to enable, disable, or defer ("not-now").';
|
|
18536
|
+
}
|
|
18537
|
+
var TELEMETRY_DIR = ".kaddo/telemetry";
|
|
18538
|
+
var IDENTITY_FILE = "identity.json";
|
|
18539
|
+
function identityPath(dir) {
|
|
18540
|
+
return join3(dir, TELEMETRY_DIR, IDENTITY_FILE);
|
|
18541
|
+
}
|
|
18542
|
+
function loadIdentity(dir) {
|
|
18543
|
+
const p = identityPath(dir);
|
|
18544
|
+
if (!exists2(p)) return null;
|
|
18545
|
+
try {
|
|
18546
|
+
return JSON.parse(readFile2(p));
|
|
18547
|
+
} catch {
|
|
18548
|
+
return null;
|
|
18549
|
+
}
|
|
18550
|
+
}
|
|
18551
|
+
var TELEMETRY_DIR2 = ".kaddo/telemetry";
|
|
18552
|
+
var BUFFER_FILE = "buffer.json";
|
|
18553
|
+
function bufferPath(dir) {
|
|
18554
|
+
return join3(dir, TELEMETRY_DIR2, BUFFER_FILE);
|
|
18555
|
+
}
|
|
18556
|
+
function readBuffer(dir) {
|
|
18557
|
+
const p = bufferPath(dir);
|
|
18558
|
+
if (!exists2(p)) return [];
|
|
18559
|
+
try {
|
|
18560
|
+
const data = JSON.parse(readFile2(p));
|
|
18561
|
+
return Array.isArray(data) ? data : [];
|
|
18562
|
+
} catch {
|
|
18563
|
+
return [];
|
|
18564
|
+
}
|
|
18565
|
+
}
|
|
18566
|
+
function bufferSize(dir) {
|
|
18567
|
+
return readBuffer(dir).length;
|
|
18568
|
+
}
|
|
18569
|
+
function getStatus(dir) {
|
|
18570
|
+
const config = loadConfig2(dir);
|
|
18571
|
+
const consent = getConsentState(config);
|
|
18572
|
+
const enabled = consent === "enabled";
|
|
18573
|
+
const identity = loadIdentity(dir);
|
|
18574
|
+
return {
|
|
18575
|
+
consent,
|
|
18576
|
+
enabled,
|
|
18577
|
+
registered: identity?.registered ?? false,
|
|
18578
|
+
pendingEvents: enabled ? bufferSize(dir) : 0,
|
|
18579
|
+
lastError: null
|
|
18580
|
+
};
|
|
18581
|
+
}
|
|
18487
18582
|
|
|
18488
18583
|
// src/tools.ts
|
|
18489
18584
|
var ok = (data) => ({ ok: true, data });
|
|
@@ -18715,12 +18810,45 @@ function verifyWorkItemTool(root, args) {
|
|
|
18715
18810
|
return fail("Work Item verification failed.");
|
|
18716
18811
|
}
|
|
18717
18812
|
}
|
|
18813
|
+
function telemetryStatusTool(root) {
|
|
18814
|
+
const status = getStatus(root);
|
|
18815
|
+
const result = {
|
|
18816
|
+
consent: status.consent,
|
|
18817
|
+
registered: status.registered,
|
|
18818
|
+
pendingEvents: status.pendingEvents
|
|
18819
|
+
};
|
|
18820
|
+
if (status.consent === "unset" && !isDeferralActive(root)) {
|
|
18821
|
+
result.notice = consentNotice();
|
|
18822
|
+
}
|
|
18823
|
+
return ok(result);
|
|
18824
|
+
}
|
|
18825
|
+
function setTelemetryConsentTool(root, args) {
|
|
18826
|
+
const valid = ["enabled", "disabled", "not-now"];
|
|
18827
|
+
if (!valid.includes(args.consent)) {
|
|
18828
|
+
return fail(`consent must be one of: ${valid.join(", ")}`);
|
|
18829
|
+
}
|
|
18830
|
+
if (!args.confirm) {
|
|
18831
|
+
const preview = {
|
|
18832
|
+
action: args.consent,
|
|
18833
|
+
effect: args.consent === "enabled" ? "Anonymous usage telemetry will be activated. Kaddo will send command usage, version, and lifecycle events to telemetry.kaddo.org. No source code, knowledge, prompts or PII is ever transmitted." : args.consent === "disabled" ? "Telemetry will be permanently disabled. No data will be sent. Kaddo will not ask again." : "Consent decision deferred for 24 hours. Telemetry remains inactive. Kaddo will remind again after the deferral expires.",
|
|
18834
|
+
instruction: "Call again with confirm=true to apply."
|
|
18835
|
+
};
|
|
18836
|
+
return ok(preview);
|
|
18837
|
+
}
|
|
18838
|
+
if (args.consent === "not-now") {
|
|
18839
|
+
deferConsent(root);
|
|
18840
|
+
return ok({ applied: true, consent: "unset", deferred: true, message: "Consent deferred for 24 hours." });
|
|
18841
|
+
}
|
|
18842
|
+
const consent = args.consent;
|
|
18843
|
+
persistConsent(root, consent);
|
|
18844
|
+
return ok({ applied: true, consent, message: `Telemetry ${consent}.` });
|
|
18845
|
+
}
|
|
18718
18846
|
|
|
18719
18847
|
// src/multirepo.ts
|
|
18720
18848
|
import fs5 from "fs";
|
|
18721
18849
|
import path4 from "path";
|
|
18722
18850
|
import matter12 from "gray-matter";
|
|
18723
|
-
import { parse as parseYaml11, stringify as
|
|
18851
|
+
import { parse as parseYaml11, stringify as stringifyYaml7 } from "yaml";
|
|
18724
18852
|
var ok2 = (data) => ({ ok: true, data });
|
|
18725
18853
|
var fail2 = (message) => ({ ok: false, message });
|
|
18726
18854
|
function moduleRepoPath(m2) {
|
|
@@ -18729,7 +18857,7 @@ function moduleRepoPath(m2) {
|
|
|
18729
18857
|
function loadModulesDescriptor(root) {
|
|
18730
18858
|
return readYaml(root, ".kaddo/modules.yml") ?? { modules: [] };
|
|
18731
18859
|
}
|
|
18732
|
-
function
|
|
18860
|
+
function loadConfig4(root) {
|
|
18733
18861
|
return readYaml(root, ".kaddo/config.yml");
|
|
18734
18862
|
}
|
|
18735
18863
|
function projectRole2(config) {
|
|
@@ -18795,7 +18923,7 @@ function slugify3(s) {
|
|
|
18795
18923
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
18796
18924
|
}
|
|
18797
18925
|
function modulesListTool(root, args) {
|
|
18798
|
-
const config =
|
|
18926
|
+
const config = loadConfig4(root);
|
|
18799
18927
|
if (!config) return fail2("No Kaddo config found. Run `kaddo init` first.");
|
|
18800
18928
|
if (!isCore2(config)) return fail2("kaddo_modules_list can only be called from a core repository (project.role: core).");
|
|
18801
18929
|
const descriptor = loadModulesDescriptor(root);
|
|
@@ -18823,7 +18951,7 @@ function modulesListTool(root, args) {
|
|
|
18823
18951
|
});
|
|
18824
18952
|
}
|
|
18825
18953
|
function getModuleContextTool(root, args) {
|
|
18826
|
-
const config =
|
|
18954
|
+
const config = loadConfig4(root);
|
|
18827
18955
|
if (!config) return fail2("No Kaddo config found.");
|
|
18828
18956
|
const descriptor = loadModulesDescriptor(root);
|
|
18829
18957
|
const mod = (descriptor.modules ?? []).find((m2) => m2.id === args.module);
|
|
@@ -18917,7 +19045,7 @@ function validateWorkItemModulesTool(root, args) {
|
|
|
18917
19045
|
});
|
|
18918
19046
|
}
|
|
18919
19047
|
function getWorkItemContextTool(root, args) {
|
|
18920
|
-
const config =
|
|
19048
|
+
const config = loadConfig4(root);
|
|
18921
19049
|
if (!config) return fail2("No Kaddo config found.");
|
|
18922
19050
|
const items = listWorkItems(root);
|
|
18923
19051
|
const wi = items.find((w3) => w3.id === args.workItemId);
|
|
@@ -19023,7 +19151,7 @@ function suggestBranchStrategyTool(root, args) {
|
|
|
19023
19151
|
});
|
|
19024
19152
|
}
|
|
19025
19153
|
function exportCapsuleTool(root, args) {
|
|
19026
|
-
const config =
|
|
19154
|
+
const config = loadConfig4(root);
|
|
19027
19155
|
if (!config) return fail2("No Kaddo config found.");
|
|
19028
19156
|
const role = projectRole2(config);
|
|
19029
19157
|
const warnings = [];
|
|
@@ -19153,7 +19281,7 @@ function exportCapsuleTool(root, args) {
|
|
|
19153
19281
|
return ok2({ exported: true, type: capsuleType, module: args.module ?? void 0, paths: { json: jsonPath, md: mdPath }, warnings });
|
|
19154
19282
|
}
|
|
19155
19283
|
function modulesDiscoverTool(root, args) {
|
|
19156
|
-
const config =
|
|
19284
|
+
const config = loadConfig4(root);
|
|
19157
19285
|
if (!config) return fail2("No Kaddo config found.");
|
|
19158
19286
|
if (!isCore2(config)) return fail2("Module discovery is only available from a core repository.");
|
|
19159
19287
|
const sysName = config.system?.name ?? config.project?.name ?? "";
|
|
@@ -19210,7 +19338,7 @@ function modulesDiscoverTool(root, args) {
|
|
|
19210
19338
|
descriptor.modules.push({ id: d3.id, name: d3.id, path: d3.path, parent_system: sysName, status: "configured" });
|
|
19211
19339
|
}
|
|
19212
19340
|
}
|
|
19213
|
-
const ymlContent =
|
|
19341
|
+
const ymlContent = stringifyYaml7({ version: descriptor.version ?? 1, system: sysName, workspace_roots: workspaceRoots2, modules: descriptor.modules ?? [] });
|
|
19214
19342
|
writeDerived(root, ".kaddo/modules.yml", ymlContent);
|
|
19215
19343
|
return ok2({ discovered, applied: true });
|
|
19216
19344
|
}
|
|
@@ -19256,7 +19384,7 @@ ${list3(data.owners)}
|
|
|
19256
19384
|
}
|
|
19257
19385
|
|
|
19258
19386
|
// ../cli/src/core/system-topology.ts
|
|
19259
|
-
import { parse as parseYaml12, stringify as
|
|
19387
|
+
import { parse as parseYaml12, stringify as stringifyYaml8 } from "yaml";
|
|
19260
19388
|
import fs6 from "fs";
|
|
19261
19389
|
import path5 from "path";
|
|
19262
19390
|
import crypto from "crypto";
|
|
@@ -19771,7 +19899,7 @@ function systemImpactCandidatesTool(root, args) {
|
|
|
19771
19899
|
|
|
19772
19900
|
// ../cli/src/services/integrations.ts
|
|
19773
19901
|
import matter14 from "gray-matter";
|
|
19774
|
-
import { parse as parseYaml13, stringify as
|
|
19902
|
+
import { parse as parseYaml13, stringify as stringifyYaml9 } from "yaml";
|
|
19775
19903
|
|
|
19776
19904
|
// ../cli/src/core/work-item-write.ts
|
|
19777
19905
|
import fs7 from "fs";
|
|
@@ -22015,7 +22143,16 @@ function createServer(root) {
|
|
|
22015
22143
|
server.registerTool(
|
|
22016
22144
|
"kaddo_project_status",
|
|
22017
22145
|
{ title: "Kaddo project status", description: "Compact project status (state, phase, work items, ownership, graph quality, capsules).", inputSchema: {} },
|
|
22018
|
-
async () =>
|
|
22146
|
+
async () => {
|
|
22147
|
+
const result = guarded(root, () => projectStatus(root));
|
|
22148
|
+
if (result.ok) {
|
|
22149
|
+
const config = loadConfig2(root);
|
|
22150
|
+
if (getConsentState(config) === "unset" && !isDeferralActive(root)) {
|
|
22151
|
+
result.data.telemetryNotice = consentNotice();
|
|
22152
|
+
}
|
|
22153
|
+
}
|
|
22154
|
+
return toolText(result);
|
|
22155
|
+
}
|
|
22019
22156
|
);
|
|
22020
22157
|
server.registerTool(
|
|
22021
22158
|
"kaddo_list_work_items",
|
|
@@ -22340,6 +22477,27 @@ function createServer(root) {
|
|
|
22340
22477
|
},
|
|
22341
22478
|
async (args) => toolText(guarded(root, () => verifyWorkItemTool(root, args)))
|
|
22342
22479
|
);
|
|
22480
|
+
server.registerTool(
|
|
22481
|
+
"kaddo_telemetry_status",
|
|
22482
|
+
{
|
|
22483
|
+
title: "Telemetry status",
|
|
22484
|
+
description: "Read-only telemetry consent state, registration status, and pending events. Includes a consent notice when telemetry has not been configured.",
|
|
22485
|
+
inputSchema: {}
|
|
22486
|
+
},
|
|
22487
|
+
async () => toolText(guarded(root, () => telemetryStatusTool(root)))
|
|
22488
|
+
);
|
|
22489
|
+
server.registerTool(
|
|
22490
|
+
"kaddo_set_telemetry_consent",
|
|
22491
|
+
{
|
|
22492
|
+
title: "Set telemetry consent",
|
|
22493
|
+
description: "Set telemetry consent to enabled, disabled, or not-now (defer 24h). Without confirm=true returns a preview of the action. With confirm=true applies the change. Writes only .kaddo/config.yml (consent field).",
|
|
22494
|
+
inputSchema: {
|
|
22495
|
+
consent: z4.enum(["enabled", "disabled", "not-now"]).describe("Consent decision: enable telemetry, disable it, or defer for 24 hours"),
|
|
22496
|
+
confirm: z4.boolean().optional().describe("Must be true to apply the change")
|
|
22497
|
+
}
|
|
22498
|
+
},
|
|
22499
|
+
async (args) => toolText(guarded(root, () => setTelemetryConsentTool(root, args)))
|
|
22500
|
+
);
|
|
22343
22501
|
let installedSkills = [];
|
|
22344
22502
|
try {
|
|
22345
22503
|
assertKaddoProject(root);
|
package/package.json
CHANGED