@kaddo/mcp 3.90.2 → 3.91.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 +68 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10472,6 +10472,7 @@ import path32 from "path";
|
|
|
10472
10472
|
import crypto2 from "crypto";
|
|
10473
10473
|
import matter72 from "gray-matter";
|
|
10474
10474
|
import crypto3 from "crypto";
|
|
10475
|
+
import fs4 from "fs";
|
|
10475
10476
|
import matter82 from "gray-matter";
|
|
10476
10477
|
import matter92 from "gray-matter";
|
|
10477
10478
|
import { parse as parseYaml92, stringify as stringifyYaml5 } from "yaml";
|
|
@@ -16581,6 +16582,12 @@ function findDuplicateByHash(dir, hash) {
|
|
|
16581
16582
|
}
|
|
16582
16583
|
return void 0;
|
|
16583
16584
|
}
|
|
16585
|
+
function findExistingById(dir, id) {
|
|
16586
|
+
const items = discoverWorkItems2(dir);
|
|
16587
|
+
const match = items.find((item) => (item.id || item.title) === id);
|
|
16588
|
+
if (!match) return void 0;
|
|
16589
|
+
return { workItemId: match.id || match.title, path: match.relPath, filePath: match.filePath };
|
|
16590
|
+
}
|
|
16584
16591
|
function importWorkItem(dir, opts) {
|
|
16585
16592
|
const content = opts.content;
|
|
16586
16593
|
if (!content?.trim()) throw new ImportError("EMPTY_INPUT", "Import content is empty.");
|
|
@@ -16609,6 +16616,31 @@ function importWorkItem(dir, opts) {
|
|
|
16609
16616
|
sourceHash,
|
|
16610
16617
|
sourceFormat: parsed.format
|
|
16611
16618
|
});
|
|
16619
|
+
const importedId = typeof parsed.candidateFields.id === "string" ? parsed.candidateFields.id.trim() : void 0;
|
|
16620
|
+
let replacedWorkItem;
|
|
16621
|
+
if (importedId && /^WI-\d+$/.test(importedId)) {
|
|
16622
|
+
const existing = findExistingById(dir, importedId);
|
|
16623
|
+
if (existing) {
|
|
16624
|
+
if (!opts.onConflict) {
|
|
16625
|
+
return {
|
|
16626
|
+
created: false,
|
|
16627
|
+
workItemId: existing.workItemId,
|
|
16628
|
+
path: existing.path,
|
|
16629
|
+
status: "draft",
|
|
16630
|
+
source: opts.source,
|
|
16631
|
+
sourceFormat: parsed.format,
|
|
16632
|
+
sourceHash,
|
|
16633
|
+
executed: false,
|
|
16634
|
+
conflict: { importedId, existingPath: existing.path },
|
|
16635
|
+
...normalized.discardedFields.length > 0 ? { discardedFields: normalized.discardedFields } : {}
|
|
16636
|
+
};
|
|
16637
|
+
}
|
|
16638
|
+
if (opts.onConflict === "replace") {
|
|
16639
|
+
fs4.rmSync(existing.filePath, { force: true });
|
|
16640
|
+
replacedWorkItem = existing.workItemId;
|
|
16641
|
+
}
|
|
16642
|
+
}
|
|
16643
|
+
}
|
|
16612
16644
|
const result = createWorkItem(dir, {
|
|
16613
16645
|
intent: normalized.intent,
|
|
16614
16646
|
type: normalized.type,
|
|
@@ -16630,7 +16662,8 @@ function importWorkItem(dir, opts) {
|
|
|
16630
16662
|
sourceHash,
|
|
16631
16663
|
executed: false,
|
|
16632
16664
|
refinementHandoff,
|
|
16633
|
-
...normalized.discardedFields.length > 0 ? { discardedFields: normalized.discardedFields } : {}
|
|
16665
|
+
...normalized.discardedFields.length > 0 ? { discardedFields: normalized.discardedFields } : {},
|
|
16666
|
+
...replacedWorkItem ? { replacedWorkItem } : {}
|
|
16634
16667
|
};
|
|
16635
16668
|
}
|
|
16636
16669
|
var ImportError = class extends Error {
|
|
@@ -17396,12 +17429,24 @@ function listGraphHints(root, filter = {}) {
|
|
|
17396
17429
|
}
|
|
17397
17430
|
function importWorkItemTool(root, args) {
|
|
17398
17431
|
const source = args.source === "cli" || args.source === "admin" ? args.source : "chat";
|
|
17432
|
+
const onConflict = args.onConflict === "replace" || args.onConflict === "new-id" ? args.onConflict : void 0;
|
|
17399
17433
|
try {
|
|
17400
17434
|
const result = importWorkItem(root, {
|
|
17401
17435
|
content: args.content,
|
|
17402
17436
|
source,
|
|
17403
|
-
type: args.type
|
|
17437
|
+
type: args.type,
|
|
17438
|
+
onConflict
|
|
17404
17439
|
});
|
|
17440
|
+
if (result.conflict) {
|
|
17441
|
+
return ok({
|
|
17442
|
+
created: false,
|
|
17443
|
+
conflict: true,
|
|
17444
|
+
importedId: result.conflict.importedId,
|
|
17445
|
+
existingPath: result.conflict.existingPath,
|
|
17446
|
+
message: `The imported content has id "${result.conflict.importedId}" which already exists. Call again with onConflict: "replace" to delete the existing Work Item and create the new one, or onConflict: "new-id" to assign a new consecutive ID.`,
|
|
17447
|
+
executed: false
|
|
17448
|
+
});
|
|
17449
|
+
}
|
|
17405
17450
|
return ok({
|
|
17406
17451
|
created: result.created,
|
|
17407
17452
|
workItemId: result.workItemId,
|
|
@@ -17412,7 +17457,8 @@ function importWorkItemTool(root, args) {
|
|
|
17412
17457
|
duplicateOf: result.duplicateOf,
|
|
17413
17458
|
executed: false,
|
|
17414
17459
|
refinementHandoff: result.refinementHandoff ? { agent: result.refinementHandoff.recommendedAgent, skill: result.refinementHandoff.recommendedSkill, text: result.refinementHandoff.text } : void 0,
|
|
17415
|
-
...result.discardedFields?.length ? { discardedFields: result.discardedFields } : {}
|
|
17460
|
+
...result.discardedFields?.length ? { discardedFields: result.discardedFields } : {},
|
|
17461
|
+
...result.replacedWorkItem ? { replacedWorkItem: result.replacedWorkItem } : {}
|
|
17416
17462
|
});
|
|
17417
17463
|
} catch (err) {
|
|
17418
17464
|
if (err instanceof ImportError) return fail(`[${err.code}] ${err.message}`);
|
|
@@ -17421,7 +17467,7 @@ function importWorkItemTool(root, args) {
|
|
|
17421
17467
|
}
|
|
17422
17468
|
|
|
17423
17469
|
// src/multirepo.ts
|
|
17424
|
-
import
|
|
17470
|
+
import fs5 from "fs";
|
|
17425
17471
|
import path4 from "path";
|
|
17426
17472
|
import matter12 from "gray-matter";
|
|
17427
17473
|
import { parse as parseYaml11, stringify as stringifyYaml6 } from "yaml";
|
|
@@ -17446,21 +17492,21 @@ function readModuleFile(root, repoPath, relFile) {
|
|
|
17446
17492
|
const moduleDir = path4.resolve(root, repoPath);
|
|
17447
17493
|
const abs = path4.resolve(moduleDir, relFile);
|
|
17448
17494
|
if (!abs.startsWith(moduleDir)) return null;
|
|
17449
|
-
if (!
|
|
17450
|
-
return
|
|
17495
|
+
if (!fs5.existsSync(abs) || !fs5.statSync(abs).isFile()) return null;
|
|
17496
|
+
return fs5.readFileSync(abs, "utf-8");
|
|
17451
17497
|
}
|
|
17452
17498
|
function detectModuleStatus2(root, repoPath) {
|
|
17453
17499
|
const moduleDir = path4.resolve(root, repoPath);
|
|
17454
|
-
if (!
|
|
17500
|
+
if (!fs5.existsSync(moduleDir)) {
|
|
17455
17501
|
return { status: "missing", configured: false, moduleContext: false, currentState: false, codebase: false, warning: `Directory \`${repoPath}\` does not exist.` };
|
|
17456
17502
|
}
|
|
17457
17503
|
const configPath = path4.join(moduleDir, ".kaddo", "config.yml");
|
|
17458
|
-
if (!
|
|
17504
|
+
if (!fs5.existsSync(configPath)) {
|
|
17459
17505
|
return { status: "not_configured", configured: false, moduleContext: false, currentState: false, codebase: false, warning: `Run \`kaddo init\` inside \`${repoPath}\` and select multirepo \u2192 module.` };
|
|
17460
17506
|
}
|
|
17461
17507
|
let parsed = null;
|
|
17462
17508
|
try {
|
|
17463
|
-
parsed = parseYaml11(
|
|
17509
|
+
parsed = parseYaml11(fs5.readFileSync(configPath, "utf-8"));
|
|
17464
17510
|
} catch {
|
|
17465
17511
|
}
|
|
17466
17512
|
const role = parsed?.project?.role ?? parsed?.multirepo?.role;
|
|
@@ -17471,14 +17517,14 @@ function detectModuleStatus2(root, repoPath) {
|
|
|
17471
17517
|
status: "configured",
|
|
17472
17518
|
configured: true,
|
|
17473
17519
|
role: "module",
|
|
17474
|
-
moduleContext:
|
|
17475
|
-
currentState:
|
|
17476
|
-
codebase:
|
|
17520
|
+
moduleContext: fs5.existsSync(path4.join(moduleDir, "knowledge", "tech", "module", "module-context.md")) || fs5.existsSync(path4.join(moduleDir, "knowledge", "module", "module-context.md")),
|
|
17521
|
+
currentState: fs5.existsSync(path4.join(moduleDir, "knowledge", "tech", "current-state.md")),
|
|
17522
|
+
codebase: fs5.existsSync(path4.join(moduleDir, "knowledge", "tech", "codebase.md"))
|
|
17477
17523
|
};
|
|
17478
17524
|
}
|
|
17479
17525
|
function resolveModuleContextPath(root, repoPath) {
|
|
17480
17526
|
const moduleDir = path4.resolve(root, repoPath);
|
|
17481
|
-
if (
|
|
17527
|
+
if (fs5.existsSync(path4.join(moduleDir, "knowledge", "tech", "module", "module-context.md"))) {
|
|
17482
17528
|
return "knowledge/tech/module/module-context.md";
|
|
17483
17529
|
}
|
|
17484
17530
|
return "knowledge/module/module-context.md";
|
|
@@ -17867,27 +17913,27 @@ function modulesDiscoverTool(root, args) {
|
|
|
17867
17913
|
const discovered = [];
|
|
17868
17914
|
for (const wr of workspaceRoots2) {
|
|
17869
17915
|
const rootAbs = path4.resolve(root, wr);
|
|
17870
|
-
if (!
|
|
17916
|
+
if (!fs5.existsSync(rootAbs) || !fs5.statSync(rootAbs).isDirectory()) continue;
|
|
17871
17917
|
let entries;
|
|
17872
17918
|
try {
|
|
17873
|
-
entries =
|
|
17919
|
+
entries = fs5.readdirSync(rootAbs);
|
|
17874
17920
|
} catch {
|
|
17875
17921
|
continue;
|
|
17876
17922
|
}
|
|
17877
17923
|
for (const entry of entries) {
|
|
17878
17924
|
if (IGNORED.has(entry)) continue;
|
|
17879
17925
|
const candidateAbs = path4.resolve(rootAbs, entry);
|
|
17880
|
-
if (!
|
|
17926
|
+
if (!fs5.statSync(candidateAbs).isDirectory()) continue;
|
|
17881
17927
|
if (candidateAbs === coreAbs) continue;
|
|
17882
17928
|
const relPath = path4.relative(root, candidateAbs).replace(/\\/g, "/");
|
|
17883
17929
|
const cfgPath = path4.join(candidateAbs, ".kaddo", "config.yml");
|
|
17884
|
-
if (!
|
|
17930
|
+
if (!fs5.existsSync(cfgPath)) {
|
|
17885
17931
|
discovered.push({ id: entry, path: relPath, status: "not_configured", eligibleForMapping: false });
|
|
17886
17932
|
continue;
|
|
17887
17933
|
}
|
|
17888
17934
|
let parsed = null;
|
|
17889
17935
|
try {
|
|
17890
|
-
parsed = parseYaml11(
|
|
17936
|
+
parsed = parseYaml11(fs5.readFileSync(cfgPath, "utf-8"));
|
|
17891
17937
|
} catch {
|
|
17892
17938
|
}
|
|
17893
17939
|
const role = parsed?.project?.role ?? parsed?.multirepo?.role;
|
|
@@ -17961,7 +18007,7 @@ ${list3(data.owners)}
|
|
|
17961
18007
|
|
|
17962
18008
|
// ../cli/src/core/system-topology.ts
|
|
17963
18009
|
import { parse as parseYaml12, stringify as stringifyYaml7 } from "yaml";
|
|
17964
|
-
import
|
|
18010
|
+
import fs6 from "fs";
|
|
17965
18011
|
import path5 from "path";
|
|
17966
18012
|
import crypto from "crypto";
|
|
17967
18013
|
var TOPOLOGY_FILE2 = "knowledge/tech/system-topology.yml";
|
|
@@ -18478,7 +18524,7 @@ import matter14 from "gray-matter";
|
|
|
18478
18524
|
import { parse as parseYaml13, stringify as stringifyYaml8 } from "yaml";
|
|
18479
18525
|
|
|
18480
18526
|
// ../cli/src/core/work-item-write.ts
|
|
18481
|
-
import
|
|
18527
|
+
import fs7 from "fs";
|
|
18482
18528
|
import path6 from "path";
|
|
18483
18529
|
import crypto4 from "crypto";
|
|
18484
18530
|
import matter13 from "gray-matter";
|
|
@@ -20974,7 +21020,8 @@ function createServer(root) {
|
|
|
20974
21020
|
inputSchema: {
|
|
20975
21021
|
content: z4.string().describe("The Work Item content \u2014 plain text, Markdown, or Kaddo-format Markdown with frontmatter"),
|
|
20976
21022
|
type: z4.string().optional().describe("Kaddo Work Item type (feature/bugfix/hotfix/spike/chore). Defaults to feature if not detectable."),
|
|
20977
|
-
source: z4.string().optional().describe("Import origin: chat (default), cli, admin")
|
|
21023
|
+
source: z4.string().optional().describe("Import origin: chat (default), cli, admin"),
|
|
21024
|
+
onConflict: z4.string().optional().describe('ID conflict resolution: "replace" deletes the existing WI and creates the new one; "new-id" assigns a new consecutive ID. Required when the imported content has an id that already exists.')
|
|
20978
21025
|
}
|
|
20979
21026
|
},
|
|
20980
21027
|
async (args) => toolText(guarded(root, () => importWorkItemTool(root, args)))
|
package/package.json
CHANGED