@swarmvaultai/engine 0.1.13 → 0.1.15

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 CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  uniqueBy,
22
22
  writeFileIfChanged,
23
23
  writeJsonFile
24
- } from "./chunk-MZSUYTSL.js";
24
+ } from "./chunk-EEWB4WGH.js";
25
25
 
26
26
  // src/agents.ts
27
27
  import fs from "fs/promises";
@@ -30,10 +30,10 @@ var managedStart = "<!-- swarmvault:managed:start -->";
30
30
  var managedEnd = "<!-- swarmvault:managed:end -->";
31
31
  var legacyManagedStart = "<!-- vault:managed:start -->";
32
32
  var legacyManagedEnd = "<!-- vault:managed:end -->";
33
- function buildManagedBlock(agent) {
33
+ function buildManagedBlock(target) {
34
34
  const body = [
35
35
  managedStart,
36
- `# SwarmVault Rules (${agent})`,
36
+ "# SwarmVault Rules",
37
37
  "",
38
38
  "- Read `swarmvault.schema.md` before compile or query style work. It is the canonical schema path.",
39
39
  "- Treat `raw/` as immutable source input.",
@@ -45,11 +45,27 @@ function buildManagedBlock(agent) {
45
45
  managedEnd,
46
46
  ""
47
47
  ].join("\n");
48
- if (agent === "cursor") {
48
+ if (target === "cursor") {
49
49
  return body;
50
50
  }
51
51
  return body;
52
52
  }
53
+ function targetPathForAgent(rootDir, agent) {
54
+ switch (agent) {
55
+ case "codex":
56
+ case "goose":
57
+ case "pi":
58
+ return path.join(rootDir, "AGENTS.md");
59
+ case "claude":
60
+ return path.join(rootDir, "CLAUDE.md");
61
+ case "gemini":
62
+ return path.join(rootDir, "GEMINI.md");
63
+ case "cursor":
64
+ return path.join(rootDir, ".cursor", "rules", "swarmvault.mdc");
65
+ default:
66
+ throw new Error(`Unsupported agent ${String(agent)}`);
67
+ }
68
+ }
53
69
  async function upsertManagedBlock(filePath, block) {
54
70
  const existing = await fileExists(filePath) ? await fs.readFile(filePath, "utf8") : "";
55
71
  if (!existing) {
@@ -72,23 +88,25 @@ ${block}
72
88
  }
73
89
  async function installAgent(rootDir, agent) {
74
90
  await initWorkspace(rootDir);
75
- const block = buildManagedBlock(agent);
91
+ const target = targetPathForAgent(rootDir, agent);
76
92
  switch (agent) {
77
- case "codex": {
78
- const target = path.join(rootDir, "AGENTS.md");
79
- await upsertManagedBlock(target, block);
93
+ case "codex":
94
+ case "goose":
95
+ case "pi":
96
+ await upsertManagedBlock(target, buildManagedBlock("agents"));
80
97
  return target;
81
- }
82
98
  case "claude": {
83
- const target = path.join(rootDir, "CLAUDE.md");
84
- await upsertManagedBlock(target, block);
99
+ await upsertManagedBlock(target, buildManagedBlock("claude"));
100
+ return target;
101
+ }
102
+ case "gemini": {
103
+ await upsertManagedBlock(target, buildManagedBlock("gemini"));
85
104
  return target;
86
105
  }
87
106
  case "cursor": {
88
- const rulesDir = path.join(rootDir, ".cursor", "rules");
107
+ const rulesDir = path.dirname(target);
89
108
  await ensureDir(rulesDir);
90
- const target = path.join(rulesDir, "swarmvault.mdc");
91
- await fs.writeFile(target, `${block}
109
+ await fs.writeFile(target, `${buildManagedBlock("cursor")}
92
110
  `, "utf8");
93
111
  return target;
94
112
  }
@@ -98,7 +116,14 @@ async function installAgent(rootDir, agent) {
98
116
  }
99
117
  async function installConfiguredAgents(rootDir) {
100
118
  const { config } = await initWorkspace(rootDir);
101
- return Promise.all(config.agents.map((agent) => installAgent(rootDir, agent)));
119
+ const dedupedTargets = /* @__PURE__ */ new Map();
120
+ for (const agent of config.agents) {
121
+ const target = targetPathForAgent(rootDir, agent);
122
+ if (!dedupedTargets.has(target)) {
123
+ dedupedTargets.set(target, agent);
124
+ }
125
+ }
126
+ return Promise.all([...dedupedTargets.values()].map((agent) => installAgent(rootDir, agent)));
102
127
  }
103
128
 
104
129
  // src/ingest.ts
@@ -125,7 +150,7 @@ function scriptKindFor(language) {
125
150
  }
126
151
  }
127
152
  function isRelativeSpecifier(specifier) {
128
- return specifier.startsWith("./") || specifier.startsWith("../");
153
+ return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith(".");
129
154
  }
130
155
  function formatDiagnosticCategory(category) {
131
156
  switch (category) {
@@ -177,6 +202,22 @@ function collectCallNames(root, availableNames, selfName) {
177
202
  visit(root);
178
203
  return uniqueBy(names, (name) => name);
179
204
  }
205
+ function collectCallNamesFromText(text, availableNames, selfName) {
206
+ if (!text) {
207
+ return [];
208
+ }
209
+ const names = [];
210
+ for (const name of availableNames) {
211
+ if (name === selfName) {
212
+ continue;
213
+ }
214
+ const pattern = new RegExp(`\\b${escapeRegExp(name)}\\s*\\(`, "g");
215
+ if (pattern.test(text)) {
216
+ names.push(name);
217
+ }
218
+ }
219
+ return uniqueBy(names, (name) => name);
220
+ }
180
221
  function heritageNames(clauses, token) {
181
222
  return uniqueBy(
182
223
  (clauses ?? []).filter((clause) => clause.token === token).flatMap(
@@ -277,7 +318,689 @@ function codeQuestions(manifest, code) {
277
318
  function resolveVariableKind(statement) {
278
319
  return statement.declarationList.flags & ts.NodeFlags.Const ? "variable" : "variable";
279
320
  }
280
- function analyzeTopLevelCode(manifest, content) {
321
+ function splitLines(content) {
322
+ return content.split(/\r?\n/);
323
+ }
324
+ function leadingIndent(line) {
325
+ const match = line.match(/^[ \t]*/);
326
+ return match ? match[0].replace(/\t/g, " ").length : 0;
327
+ }
328
+ function normalizeSymbolReference(value) {
329
+ const withoutGenerics = value.replace(/<[^>]*>/g, "");
330
+ const withoutDecorators = withoutGenerics.replace(/['"&*()[\]{}]/g, " ");
331
+ const trimmed = withoutDecorators.trim();
332
+ const lastSegment = trimmed.split(/::|\./).filter(Boolean).at(-1) ?? trimmed;
333
+ return lastSegment.replace(/[,:;]+$/g, "").trim();
334
+ }
335
+ function singleLineSignature(line) {
336
+ return truncate(
337
+ normalizeWhitespace(
338
+ line.replace(/\{\s*$/, "").replace(/:\s*$/, ":").trim()
339
+ ),
340
+ 180
341
+ );
342
+ }
343
+ function buildDiagnostic(code, message, line, column = 1, category = "warning") {
344
+ return { code, category, message, line, column };
345
+ }
346
+ function finalizeCodeAnalysis(manifest, language, imports, draftSymbols, exportLabels, diagnostics) {
347
+ const topLevelNames = new Set(draftSymbols.map((symbol) => symbol.name));
348
+ for (const symbol of draftSymbols) {
349
+ if (symbol.callNames.length === 0 && symbol.bodyText) {
350
+ symbol.callNames = collectCallNamesFromText(symbol.bodyText, topLevelNames, symbol.name);
351
+ }
352
+ }
353
+ const seenSymbolIds = /* @__PURE__ */ new Map();
354
+ const symbols = draftSymbols.map((symbol) => ({
355
+ id: makeSymbolId(manifest.sourceId, symbol.name, seenSymbolIds),
356
+ name: symbol.name,
357
+ kind: symbol.kind,
358
+ signature: symbol.signature,
359
+ exported: symbol.exported,
360
+ calls: uniqueBy(symbol.callNames, (name) => name),
361
+ extends: uniqueBy(symbol.extendsNames.map((name) => normalizeSymbolReference(name)).filter(Boolean), (name) => name),
362
+ implements: uniqueBy(symbol.implementsNames.map((name) => normalizeSymbolReference(name)).filter(Boolean), (name) => name)
363
+ }));
364
+ return {
365
+ moduleId: `module:${manifest.sourceId}`,
366
+ language,
367
+ imports,
368
+ dependencies: uniqueBy(
369
+ imports.filter((item) => item.isExternal).map((item) => item.specifier),
370
+ (specifier) => specifier
371
+ ),
372
+ symbols,
373
+ exports: uniqueBy([...symbols.filter((symbol) => symbol.exported).map((symbol) => symbol.name), ...exportLabels], (label) => label),
374
+ diagnostics
375
+ };
376
+ }
377
+ function collectPythonBlock(lines, startIndex) {
378
+ const startIndent = leadingIndent(lines[startIndex] ?? "");
379
+ const parts = [];
380
+ for (let index = startIndex + 1; index < lines.length; index += 1) {
381
+ const line = lines[index] ?? "";
382
+ const trimmed = line.trim();
383
+ if (!trimmed) {
384
+ parts.push(line);
385
+ continue;
386
+ }
387
+ if (leadingIndent(line) <= startIndent) {
388
+ break;
389
+ }
390
+ parts.push(line);
391
+ }
392
+ return parts.join("\n");
393
+ }
394
+ function parsePythonImportList(value) {
395
+ return value.split(",").map((item) => item.trim()).filter(Boolean).map((item) => {
396
+ const [rawSpecifier, rawAlias] = item.split(/\s+as\s+/i);
397
+ return {
398
+ specifier: rawSpecifier.trim(),
399
+ alias: rawAlias?.trim()
400
+ };
401
+ });
402
+ }
403
+ function parsePythonAllExportList(value) {
404
+ const match = value.match(/\[(.*)\]/);
405
+ if (!match) {
406
+ return [];
407
+ }
408
+ return uniqueBy(
409
+ match[1].split(",").map((item) => item.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean),
410
+ (item) => item
411
+ );
412
+ }
413
+ function analyzePythonCode(manifest, content) {
414
+ const lines = splitLines(content);
415
+ const imports = [];
416
+ const draftSymbols = [];
417
+ const exportLabels = [];
418
+ const diagnostics = [];
419
+ let explicitExports = [];
420
+ for (let index = 0; index < lines.length; index += 1) {
421
+ const rawLine = lines[index] ?? "";
422
+ const trimmed = rawLine.trim();
423
+ if (!trimmed || trimmed.startsWith("#") || leadingIndent(rawLine) > 0) {
424
+ continue;
425
+ }
426
+ const importMatch = trimmed.match(/^import\s+(.+)$/);
427
+ if (importMatch) {
428
+ for (const item of parsePythonImportList(importMatch[1])) {
429
+ imports.push({
430
+ specifier: item.specifier,
431
+ importedSymbols: [],
432
+ namespaceImport: item.alias,
433
+ isExternal: !isRelativeSpecifier(item.specifier),
434
+ reExport: false
435
+ });
436
+ }
437
+ continue;
438
+ }
439
+ const fromImportMatch = trimmed.match(/^from\s+([.\w]+)\s+import\s+(.+)$/);
440
+ if (fromImportMatch) {
441
+ const importedSymbols = fromImportMatch[2].split(",").map((item) => item.trim()).filter(Boolean);
442
+ imports.push({
443
+ specifier: fromImportMatch[1],
444
+ importedSymbols,
445
+ isExternal: !isRelativeSpecifier(fromImportMatch[1]),
446
+ reExport: false
447
+ });
448
+ continue;
449
+ }
450
+ const classMatch = trimmed.match(/^class\s+([A-Za-z_]\w*)\s*(?:\(([^)]*)\))?\s*:/);
451
+ if (classMatch) {
452
+ const baseNames = classMatch[2] ? classMatch[2].split(",").map((item) => normalizeSymbolReference(item)).filter(Boolean) : [];
453
+ draftSymbols.push({
454
+ name: classMatch[1],
455
+ kind: "class",
456
+ signature: singleLineSignature(trimmed),
457
+ exported: !classMatch[1].startsWith("_"),
458
+ callNames: [],
459
+ extendsNames: baseNames,
460
+ implementsNames: [],
461
+ bodyText: collectPythonBlock(lines, index)
462
+ });
463
+ continue;
464
+ }
465
+ if (trimmed.startsWith("class ")) {
466
+ diagnostics.push(buildDiagnostic(1001, "Python class declaration is missing a trailing colon.", index + 1));
467
+ continue;
468
+ }
469
+ const functionMatch = trimmed.match(/^(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(/);
470
+ if (functionMatch) {
471
+ draftSymbols.push({
472
+ name: functionMatch[1],
473
+ kind: "function",
474
+ signature: singleLineSignature(trimmed),
475
+ exported: !functionMatch[1].startsWith("_"),
476
+ callNames: [],
477
+ extendsNames: [],
478
+ implementsNames: [],
479
+ bodyText: collectPythonBlock(lines, index)
480
+ });
481
+ continue;
482
+ }
483
+ if (trimmed.startsWith("def ") || trimmed.startsWith("async def ")) {
484
+ diagnostics.push(buildDiagnostic(1002, "Python function declaration is missing a trailing colon.", index + 1));
485
+ continue;
486
+ }
487
+ const allMatch = trimmed.match(/^__all__\s*=\s*\[(.*)\]\s*$/);
488
+ if (allMatch) {
489
+ explicitExports = parsePythonAllExportList(trimmed);
490
+ continue;
491
+ }
492
+ const variableMatch = trimmed.match(/^([A-Za-z_]\w*)\s*(?::[^=]+)?=\s*(.+)$/);
493
+ if (variableMatch && !["True", "False", "None"].includes(variableMatch[1])) {
494
+ draftSymbols.push({
495
+ name: variableMatch[1],
496
+ kind: "variable",
497
+ signature: singleLineSignature(trimmed),
498
+ exported: !variableMatch[1].startsWith("_"),
499
+ callNames: [],
500
+ extendsNames: [],
501
+ implementsNames: [],
502
+ bodyText: variableMatch[2]
503
+ });
504
+ }
505
+ }
506
+ if (explicitExports.length > 0) {
507
+ const explicitExportSet = new Set(explicitExports);
508
+ for (const symbol of draftSymbols) {
509
+ symbol.exported = explicitExportSet.has(symbol.name);
510
+ }
511
+ exportLabels.push(...explicitExports);
512
+ }
513
+ return finalizeCodeAnalysis(manifest, "python", imports, draftSymbols, exportLabels, diagnostics);
514
+ }
515
+ function collectBracedBlock(lines, startIndex) {
516
+ const parts = [];
517
+ let depth = 0;
518
+ let started = false;
519
+ for (let index = startIndex; index < lines.length; index += 1) {
520
+ const line = lines[index] ?? "";
521
+ parts.push(line);
522
+ for (const character of line) {
523
+ if (character === "{") {
524
+ depth += 1;
525
+ started = true;
526
+ } else if (character === "}") {
527
+ depth -= 1;
528
+ }
529
+ }
530
+ if (started && depth <= 0) {
531
+ return { text: parts.join("\n"), endIndex: index };
532
+ }
533
+ }
534
+ return {
535
+ text: parts.join("\n"),
536
+ endIndex: started ? lines.length - 1 : startIndex
537
+ };
538
+ }
539
+ function exportedByCapitalization(name) {
540
+ return /^[A-Z]/.test(name);
541
+ }
542
+ function parseGoImportLine(line) {
543
+ const match = line.trim().match(/^(?:([._A-Za-z]\w*)\s+)?"([^"]+)"$/);
544
+ if (!match) {
545
+ return void 0;
546
+ }
547
+ return {
548
+ specifier: match[2],
549
+ importedSymbols: [],
550
+ namespaceImport: match[1] && ![".", "_"].includes(match[1]) ? match[1] : void 0,
551
+ isExternal: !isRelativeSpecifier(match[2]),
552
+ reExport: false
553
+ };
554
+ }
555
+ function receiverTypeName(receiver) {
556
+ const tokens = receiver.replace(/[()*]/g, " ").split(/\s+/).map((item) => item.trim()).filter(Boolean);
557
+ return normalizeSymbolReference(tokens.at(-1) ?? "");
558
+ }
559
+ function analyzeGoCode(manifest, content) {
560
+ const lines = splitLines(content);
561
+ const imports = [];
562
+ const draftSymbols = [];
563
+ const exportLabels = [];
564
+ const diagnostics = [];
565
+ let inImportBlock = false;
566
+ for (let index = 0; index < lines.length; index += 1) {
567
+ const rawLine = lines[index] ?? "";
568
+ const trimmed = rawLine.trim();
569
+ if (!trimmed || trimmed.startsWith("//")) {
570
+ continue;
571
+ }
572
+ if (inImportBlock) {
573
+ if (trimmed === ")") {
574
+ inImportBlock = false;
575
+ continue;
576
+ }
577
+ const parsed = parseGoImportLine(trimmed);
578
+ if (parsed) {
579
+ imports.push(parsed);
580
+ }
581
+ continue;
582
+ }
583
+ const importBlockMatch = trimmed.match(/^import\s+\($/);
584
+ if (importBlockMatch) {
585
+ inImportBlock = true;
586
+ continue;
587
+ }
588
+ const singleImportMatch = trimmed.match(/^import\s+(.+)$/);
589
+ if (singleImportMatch) {
590
+ const parsed = parseGoImportLine(singleImportMatch[1]);
591
+ if (parsed) {
592
+ imports.push(parsed);
593
+ }
594
+ continue;
595
+ }
596
+ const typeMatch = trimmed.match(/^type\s+([A-Za-z_]\w*)\s+(struct|interface)\b/);
597
+ if (typeMatch) {
598
+ const exported = exportedByCapitalization(typeMatch[1]);
599
+ draftSymbols.push({
600
+ name: typeMatch[1],
601
+ kind: typeMatch[2] === "interface" ? "interface" : "class",
602
+ signature: singleLineSignature(trimmed),
603
+ exported,
604
+ callNames: [],
605
+ extendsNames: [],
606
+ implementsNames: [],
607
+ bodyText: collectBracedBlock(lines, index).text
608
+ });
609
+ if (exported) {
610
+ exportLabels.push(typeMatch[1]);
611
+ }
612
+ continue;
613
+ }
614
+ const aliasTypeMatch = trimmed.match(/^type\s+([A-Za-z_]\w*)\b(?!\s+(?:struct|interface)\b)/);
615
+ if (aliasTypeMatch) {
616
+ const exported = exportedByCapitalization(aliasTypeMatch[1]);
617
+ draftSymbols.push({
618
+ name: aliasTypeMatch[1],
619
+ kind: "type_alias",
620
+ signature: singleLineSignature(trimmed),
621
+ exported,
622
+ callNames: [],
623
+ extendsNames: [],
624
+ implementsNames: [],
625
+ bodyText: trimmed
626
+ });
627
+ if (exported) {
628
+ exportLabels.push(aliasTypeMatch[1]);
629
+ }
630
+ continue;
631
+ }
632
+ const funcMatch = trimmed.match(/^func\s+(?:\(([^)]*)\)\s*)?([A-Za-z_]\w*)\s*\(/);
633
+ if (funcMatch) {
634
+ const receiverType = funcMatch[1] ? receiverTypeName(funcMatch[1]) : "";
635
+ const symbolName = receiverType ? `${receiverType}.${funcMatch[2]}` : funcMatch[2];
636
+ const exported = exportedByCapitalization(funcMatch[2]);
637
+ const block = collectBracedBlock(lines, index);
638
+ draftSymbols.push({
639
+ name: symbolName,
640
+ kind: "function",
641
+ signature: singleLineSignature(trimmed),
642
+ exported,
643
+ callNames: [],
644
+ extendsNames: [],
645
+ implementsNames: [],
646
+ bodyText: block.text
647
+ });
648
+ if (exported) {
649
+ exportLabels.push(symbolName);
650
+ }
651
+ index = block.endIndex;
652
+ continue;
653
+ }
654
+ const variableMatch = trimmed.match(/^(?:var|const)\s+([A-Za-z_]\w*)\b/);
655
+ if (variableMatch) {
656
+ const exported = exportedByCapitalization(variableMatch[1]);
657
+ draftSymbols.push({
658
+ name: variableMatch[1],
659
+ kind: "variable",
660
+ signature: singleLineSignature(trimmed),
661
+ exported,
662
+ callNames: [],
663
+ extendsNames: [],
664
+ implementsNames: [],
665
+ bodyText: trimmed
666
+ });
667
+ if (exported) {
668
+ exportLabels.push(variableMatch[1]);
669
+ }
670
+ }
671
+ }
672
+ return finalizeCodeAnalysis(manifest, "go", imports, draftSymbols, exportLabels, diagnostics);
673
+ }
674
+ function analyzeRustUseStatement(statement) {
675
+ const cleaned = statement.replace(/^pub\s+/, "").replace(/^use\s+/, "").replace(/;$/, "").trim();
676
+ const aliasMatch = cleaned.match(/\s+as\s+([A-Za-z_]\w*)$/);
677
+ const withoutAlias = aliasMatch ? cleaned.slice(0, aliasMatch.index).trim() : cleaned;
678
+ const braceMatch = withoutAlias.match(/^(.*)::\{(.+)\}$/);
679
+ const importedSymbols = braceMatch ? braceMatch[2].split(",").map((item) => item.trim()).filter(Boolean) : [aliasMatch ? `${normalizeSymbolReference(withoutAlias)} as ${aliasMatch[1]}` : normalizeSymbolReference(withoutAlias)].filter(
680
+ Boolean
681
+ );
682
+ const specifier = braceMatch ? braceMatch[1].trim() : withoutAlias;
683
+ return {
684
+ specifier,
685
+ importedSymbols,
686
+ isExternal: !/^(crate|self|super)::/.test(specifier),
687
+ reExport: statement.trim().startsWith("pub use ")
688
+ };
689
+ }
690
+ function rustVisibilityPrefix(trimmed) {
691
+ return /^(pub(?:\([^)]*\))?\s+)/.test(trimmed);
692
+ }
693
+ function analyzeRustCode(manifest, content) {
694
+ const lines = splitLines(content);
695
+ const imports = [];
696
+ const draftSymbols = [];
697
+ const exportLabels = [];
698
+ const diagnostics = [];
699
+ const symbolByName = /* @__PURE__ */ new Map();
700
+ for (let index = 0; index < lines.length; index += 1) {
701
+ const rawLine = lines[index] ?? "";
702
+ const trimmed = rawLine.trim();
703
+ if (!trimmed || trimmed.startsWith("//")) {
704
+ continue;
705
+ }
706
+ const useMatch = trimmed.match(/^(?:pub\s+)?use\s+.+;$/);
707
+ if (useMatch) {
708
+ imports.push(analyzeRustUseStatement(trimmed));
709
+ continue;
710
+ }
711
+ const functionMatch = trimmed.match(/^(?:pub(?:\([^)]*\))?\s+)?fn\s+([A-Za-z_]\w*)\s*\(/);
712
+ if (functionMatch) {
713
+ const exported = rustVisibilityPrefix(trimmed);
714
+ const block = collectBracedBlock(lines, index);
715
+ const symbol = {
716
+ name: functionMatch[1],
717
+ kind: "function",
718
+ signature: singleLineSignature(trimmed),
719
+ exported,
720
+ callNames: [],
721
+ extendsNames: [],
722
+ implementsNames: [],
723
+ bodyText: block.text
724
+ };
725
+ draftSymbols.push(symbol);
726
+ symbolByName.set(symbol.name, symbol);
727
+ if (exported) {
728
+ exportLabels.push(symbol.name);
729
+ }
730
+ index = block.endIndex;
731
+ continue;
732
+ }
733
+ const structMatch = trimmed.match(/^(?:pub(?:\([^)]*\))?\s+)?struct\s+([A-Za-z_]\w*)\b/);
734
+ if (structMatch) {
735
+ const exported = rustVisibilityPrefix(trimmed);
736
+ const block = collectBracedBlock(lines, index);
737
+ const symbol = {
738
+ name: structMatch[1],
739
+ kind: "class",
740
+ signature: singleLineSignature(trimmed),
741
+ exported,
742
+ callNames: [],
743
+ extendsNames: [],
744
+ implementsNames: [],
745
+ bodyText: block.text
746
+ };
747
+ draftSymbols.push(symbol);
748
+ symbolByName.set(symbol.name, symbol);
749
+ if (exported) {
750
+ exportLabels.push(symbol.name);
751
+ }
752
+ index = block.endIndex;
753
+ continue;
754
+ }
755
+ const enumMatch = trimmed.match(/^(?:pub(?:\([^)]*\))?\s+)?enum\s+([A-Za-z_]\w*)\b/);
756
+ if (enumMatch) {
757
+ const exported = rustVisibilityPrefix(trimmed);
758
+ const block = collectBracedBlock(lines, index);
759
+ const symbol = {
760
+ name: enumMatch[1],
761
+ kind: "enum",
762
+ signature: singleLineSignature(trimmed),
763
+ exported,
764
+ callNames: [],
765
+ extendsNames: [],
766
+ implementsNames: [],
767
+ bodyText: block.text
768
+ };
769
+ draftSymbols.push(symbol);
770
+ symbolByName.set(symbol.name, symbol);
771
+ if (exported) {
772
+ exportLabels.push(symbol.name);
773
+ }
774
+ index = block.endIndex;
775
+ continue;
776
+ }
777
+ const traitMatch = trimmed.match(/^(?:pub(?:\([^)]*\))?\s+)?trait\s+([A-Za-z_]\w*)\b/);
778
+ if (traitMatch) {
779
+ const exported = rustVisibilityPrefix(trimmed);
780
+ const block = collectBracedBlock(lines, index);
781
+ const symbol = {
782
+ name: traitMatch[1],
783
+ kind: "interface",
784
+ signature: singleLineSignature(trimmed),
785
+ exported,
786
+ callNames: [],
787
+ extendsNames: [],
788
+ implementsNames: [],
789
+ bodyText: block.text
790
+ };
791
+ draftSymbols.push(symbol);
792
+ symbolByName.set(symbol.name, symbol);
793
+ if (exported) {
794
+ exportLabels.push(symbol.name);
795
+ }
796
+ index = block.endIndex;
797
+ continue;
798
+ }
799
+ const aliasMatch = trimmed.match(/^(?:pub(?:\([^)]*\))?\s+)?type\s+([A-Za-z_]\w*)\s*=/);
800
+ if (aliasMatch) {
801
+ const exported = rustVisibilityPrefix(trimmed);
802
+ const symbol = {
803
+ name: aliasMatch[1],
804
+ kind: "type_alias",
805
+ signature: singleLineSignature(trimmed),
806
+ exported,
807
+ callNames: [],
808
+ extendsNames: [],
809
+ implementsNames: [],
810
+ bodyText: trimmed
811
+ };
812
+ draftSymbols.push(symbol);
813
+ symbolByName.set(symbol.name, symbol);
814
+ if (exported) {
815
+ exportLabels.push(symbol.name);
816
+ }
817
+ continue;
818
+ }
819
+ const variableMatch = trimmed.match(/^(?:pub(?:\([^)]*\))?\s+)?(?:const|static)\s+([A-Za-z_]\w*)\b/);
820
+ if (variableMatch) {
821
+ const exported = rustVisibilityPrefix(trimmed);
822
+ const symbol = {
823
+ name: variableMatch[1],
824
+ kind: "variable",
825
+ signature: singleLineSignature(trimmed),
826
+ exported,
827
+ callNames: [],
828
+ extendsNames: [],
829
+ implementsNames: [],
830
+ bodyText: trimmed
831
+ };
832
+ draftSymbols.push(symbol);
833
+ symbolByName.set(symbol.name, symbol);
834
+ if (exported) {
835
+ exportLabels.push(symbol.name);
836
+ }
837
+ continue;
838
+ }
839
+ const implMatch = trimmed.match(/^impl(?:<[^>]+>)?\s+(.+?)\s+for\s+([A-Za-z_][\w:<>]*)/);
840
+ if (implMatch) {
841
+ const traitName = normalizeSymbolReference(implMatch[1]);
842
+ const typeName = normalizeSymbolReference(implMatch[2]);
843
+ const symbol = symbolByName.get(typeName);
844
+ if (symbol && traitName) {
845
+ symbol.implementsNames.push(traitName);
846
+ }
847
+ }
848
+ }
849
+ for (const rawLine of lines) {
850
+ const trimmed = rawLine.trim();
851
+ const traitMatch = trimmed.match(/^(?:pub(?:\([^)]*\))?\s+)?trait\s+([A-Za-z_]\w*)\b/);
852
+ if (!traitMatch || symbolByName.has(traitMatch[1])) {
853
+ continue;
854
+ }
855
+ const exported = rustVisibilityPrefix(trimmed);
856
+ const symbol = {
857
+ name: traitMatch[1],
858
+ kind: "interface",
859
+ signature: singleLineSignature(trimmed),
860
+ exported,
861
+ callNames: [],
862
+ extendsNames: [],
863
+ implementsNames: [],
864
+ bodyText: trimmed
865
+ };
866
+ draftSymbols.push(symbol);
867
+ symbolByName.set(symbol.name, symbol);
868
+ if (exported) {
869
+ exportLabels.push(symbol.name);
870
+ }
871
+ }
872
+ return finalizeCodeAnalysis(manifest, "rust", imports, draftSymbols, exportLabels, diagnostics);
873
+ }
874
+ function analyzeJavaImport(statement) {
875
+ const cleaned = statement.replace(/^import\s+/, "").replace(/^static\s+/, "").replace(/;$/, "").trim();
876
+ const symbolName = normalizeSymbolReference(cleaned.replace(/\.\*$/, ""));
877
+ return {
878
+ specifier: cleaned.replace(/\.\*$/, ""),
879
+ importedSymbols: symbolName ? [symbolName] : [],
880
+ isExternal: true,
881
+ reExport: false
882
+ };
883
+ }
884
+ function parseJavaImplements(value) {
885
+ return (value ?? "").split(",").map((item) => normalizeSymbolReference(item)).filter(Boolean);
886
+ }
887
+ function analyzeJavaCode(manifest, content) {
888
+ const lines = splitLines(content);
889
+ const imports = [];
890
+ const draftSymbols = [];
891
+ const exportLabels = [];
892
+ const diagnostics = [];
893
+ let depth = 0;
894
+ for (let index = 0; index < lines.length; index += 1) {
895
+ const rawLine = lines[index] ?? "";
896
+ const trimmed = rawLine.trim();
897
+ const lineDepth = depth;
898
+ if (lineDepth === 0 && trimmed.startsWith("import ")) {
899
+ imports.push(analyzeJavaImport(trimmed));
900
+ }
901
+ if (lineDepth === 0) {
902
+ const classMatch = trimmed.match(
903
+ /^(public\s+)?(?:abstract\s+|final\s+|sealed\s+|non-sealed\s+)*class\s+([A-Za-z_]\w*)\b(?:\s+extends\s+([A-Za-z_][\w.<>]*))?(?:\s+implements\s+([A-Za-z_][\w.,<>\s]*))?/
904
+ );
905
+ if (classMatch) {
906
+ const exported = Boolean(classMatch[1]);
907
+ const block = collectBracedBlock(lines, index);
908
+ draftSymbols.push({
909
+ name: classMatch[2],
910
+ kind: "class",
911
+ signature: singleLineSignature(trimmed),
912
+ exported,
913
+ callNames: [],
914
+ extendsNames: classMatch[3] ? [classMatch[3]] : [],
915
+ implementsNames: parseJavaImplements(classMatch[4]),
916
+ bodyText: block.text
917
+ });
918
+ if (exported) {
919
+ exportLabels.push(classMatch[2]);
920
+ }
921
+ index = block.endIndex;
922
+ depth = 0;
923
+ continue;
924
+ }
925
+ const interfaceMatch = trimmed.match(
926
+ /^(public\s+)?(?:sealed\s+|non-sealed\s+)?interface\s+([A-Za-z_]\w*)\b(?:\s+extends\s+([A-Za-z_][\w.,<>\s]*))?/
927
+ );
928
+ if (interfaceMatch) {
929
+ const exported = Boolean(interfaceMatch[1]);
930
+ const block = collectBracedBlock(lines, index);
931
+ draftSymbols.push({
932
+ name: interfaceMatch[2],
933
+ kind: "interface",
934
+ signature: singleLineSignature(trimmed),
935
+ exported,
936
+ callNames: [],
937
+ extendsNames: parseJavaImplements(interfaceMatch[3]),
938
+ implementsNames: [],
939
+ bodyText: block.text
940
+ });
941
+ if (exported) {
942
+ exportLabels.push(interfaceMatch[2]);
943
+ }
944
+ index = block.endIndex;
945
+ depth = 0;
946
+ continue;
947
+ }
948
+ const enumMatch = trimmed.match(/^(public\s+)?enum\s+([A-Za-z_]\w*)\b(?:\s+implements\s+([A-Za-z_][\w.,<>\s]*))?/);
949
+ if (enumMatch) {
950
+ const exported = Boolean(enumMatch[1]);
951
+ const block = collectBracedBlock(lines, index);
952
+ draftSymbols.push({
953
+ name: enumMatch[2],
954
+ kind: "enum",
955
+ signature: singleLineSignature(trimmed),
956
+ exported,
957
+ callNames: [],
958
+ extendsNames: [],
959
+ implementsNames: parseJavaImplements(enumMatch[3]),
960
+ bodyText: block.text
961
+ });
962
+ if (exported) {
963
+ exportLabels.push(enumMatch[2]);
964
+ }
965
+ index = block.endIndex;
966
+ depth = 0;
967
+ continue;
968
+ }
969
+ const recordMatch = trimmed.match(
970
+ /^(public\s+)?record\s+([A-Za-z_]\w*)\b(?:\s*\([^)]*\))?(?:\s+implements\s+([A-Za-z_][\w.,<>\s]*))?/
971
+ );
972
+ if (recordMatch) {
973
+ const exported = Boolean(recordMatch[1]);
974
+ const block = collectBracedBlock(lines, index);
975
+ draftSymbols.push({
976
+ name: recordMatch[2],
977
+ kind: "class",
978
+ signature: singleLineSignature(trimmed),
979
+ exported,
980
+ callNames: [],
981
+ extendsNames: [],
982
+ implementsNames: parseJavaImplements(recordMatch[3]),
983
+ bodyText: block.text
984
+ });
985
+ if (exported) {
986
+ exportLabels.push(recordMatch[2]);
987
+ }
988
+ index = block.endIndex;
989
+ depth = 0;
990
+ continue;
991
+ }
992
+ }
993
+ for (const character of rawLine) {
994
+ if (character === "{") {
995
+ depth += 1;
996
+ } else if (character === "}") {
997
+ depth -= 1;
998
+ }
999
+ }
1000
+ }
1001
+ return finalizeCodeAnalysis(manifest, "java", imports, draftSymbols, exportLabels, diagnostics);
1002
+ }
1003
+ function analyzeTypeScriptLikeCode(manifest, content) {
281
1004
  const language = manifest.language ?? inferCodeLanguage(manifest.originalPath ?? manifest.storedPath, manifest.mimeType) ?? "typescript";
282
1005
  const sourceFile = ts.createSourceFile(
283
1006
  manifest.originalPath ?? manifest.storedPath,
@@ -478,17 +1201,6 @@ function analyzeTopLevelCode(manifest, content) {
478
1201
  }
479
1202
  }
480
1203
  }
481
- const seenSymbolIds = /* @__PURE__ */ new Map();
482
- const symbols = draftSymbols.map((symbol) => ({
483
- id: makeSymbolId(manifest.sourceId, symbol.name, seenSymbolIds),
484
- name: symbol.name,
485
- kind: symbol.kind,
486
- signature: symbol.signature,
487
- exported: symbol.exported || localExportNames.has(symbol.name),
488
- calls: symbol.callNames,
489
- extends: symbol.extendsNames,
490
- implements: symbol.implementsNames
491
- }));
492
1204
  const parseDiagnostics = sourceFile.parseDiagnostics ?? [];
493
1205
  const diagnostics = parseDiagnostics.map((diagnostic) => {
494
1206
  const position = diagnostic.start !== void 0 ? sourceFile.getLineAndCharacterOfPosition(diagnostic.start) : void 0;
@@ -500,22 +1212,11 @@ function analyzeTopLevelCode(manifest, content) {
500
1212
  column: (position?.character ?? 0) + 1
501
1213
  };
502
1214
  });
503
- return {
504
- moduleId: `module:${manifest.sourceId}`,
505
- language,
506
- imports,
507
- dependencies: uniqueBy(
508
- imports.filter((item) => item.isExternal).map((item) => item.specifier),
509
- (specifier) => specifier
510
- ),
511
- symbols,
512
- exports: uniqueBy([...symbols.filter((symbol) => symbol.exported).map((symbol) => symbol.name), ...exportLabels], (label) => label),
513
- diagnostics
514
- };
1215
+ return finalizeCodeAnalysis(manifest, language, imports, draftSymbols, exportLabels, diagnostics);
515
1216
  }
516
1217
  function inferCodeLanguage(filePath, mimeType = "") {
517
1218
  const extension = path2.extname(filePath).toLowerCase();
518
- if (extension === ".ts") {
1219
+ if (extension === ".ts" || extension === ".mts" || extension === ".cts") {
519
1220
  return "typescript";
520
1221
  }
521
1222
  if (extension === ".tsx") {
@@ -524,35 +1225,92 @@ function inferCodeLanguage(filePath, mimeType = "") {
524
1225
  if (extension === ".jsx") {
525
1226
  return "jsx";
526
1227
  }
527
- if (extension === ".js" || mimeType.includes("javascript")) {
1228
+ if (extension === ".js" || extension === ".mjs" || extension === ".cjs" || mimeType.includes("javascript")) {
528
1229
  return "javascript";
529
1230
  }
1231
+ if (extension === ".py") {
1232
+ return "python";
1233
+ }
1234
+ if (extension === ".go") {
1235
+ return "go";
1236
+ }
1237
+ if (extension === ".rs") {
1238
+ return "rust";
1239
+ }
1240
+ if (extension === ".java") {
1241
+ return "java";
1242
+ }
530
1243
  return void 0;
531
1244
  }
532
1245
  function modulePageTitle(manifest) {
533
1246
  return `${manifest.title} module`;
534
1247
  }
535
- function importResolutionCandidates(basePath, specifier) {
1248
+ function importResolutionCandidates(basePath, specifier, extensions) {
536
1249
  const resolved = path2.resolve(path2.dirname(basePath), specifier);
537
1250
  if (path2.extname(resolved)) {
538
1251
  return [path2.normalize(resolved)];
539
1252
  }
540
- const extensions = [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts", ".mjs", ".cjs"];
541
1253
  const direct = extensions.map((extension) => path2.normalize(`${resolved}${extension}`));
542
1254
  const indexFiles = extensions.map((extension) => path2.normalize(path2.join(resolved, `index${extension}`)));
543
1255
  return uniqueBy([path2.normalize(resolved), ...direct, ...indexFiles], (candidate) => candidate);
544
1256
  }
545
- function resolveCodeImportSourceId(manifest, specifier, manifests) {
1257
+ function resolveJsLikeImportSourceId(manifest, specifier, manifests) {
546
1258
  if (manifest.originType !== "file" || !manifest.originalPath || !isRelativeSpecifier(specifier)) {
547
1259
  return void 0;
548
1260
  }
549
- const candidates = new Set(importResolutionCandidates(manifest.originalPath, specifier));
1261
+ const candidates = new Set(
1262
+ importResolutionCandidates(manifest.originalPath, specifier, [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts", ".mjs", ".cjs"])
1263
+ );
550
1264
  return manifests.find(
551
1265
  (candidate) => candidate.sourceKind === "code" && candidate.originalPath && candidates.has(path2.normalize(candidate.originalPath))
552
1266
  )?.sourceId;
553
1267
  }
1268
+ function resolvePythonImportSourceId(manifest, specifier, manifests) {
1269
+ if (manifest.originType !== "file" || !manifest.originalPath) {
1270
+ return void 0;
1271
+ }
1272
+ if (specifier.startsWith(".")) {
1273
+ const dotMatch = specifier.match(/^\.+/);
1274
+ const depth = dotMatch ? dotMatch[0].length : 0;
1275
+ const relativeModule = specifier.slice(depth).replace(/\./g, "/");
1276
+ const baseDir = path2.dirname(manifest.originalPath);
1277
+ const parentDir = path2.resolve(baseDir, ...Array(Math.max(depth - 1, 0)).fill(".."));
1278
+ const moduleBase = relativeModule ? path2.join(parentDir, relativeModule) : parentDir;
1279
+ const candidates = /* @__PURE__ */ new Set([path2.normalize(`${moduleBase}.py`), path2.normalize(path2.join(moduleBase, "__init__.py"))]);
1280
+ return manifests.find(
1281
+ (candidate) => candidate.sourceKind === "code" && candidate.originalPath && candidates.has(path2.normalize(candidate.originalPath))
1282
+ )?.sourceId;
1283
+ }
1284
+ const modulePath = specifier.replace(/\./g, "/");
1285
+ const suffixes = [`/${modulePath}.py`, `/${modulePath}/__init__.py`];
1286
+ return manifests.find((candidate) => {
1287
+ if (candidate.sourceKind !== "code" || !candidate.originalPath) {
1288
+ return false;
1289
+ }
1290
+ const normalizedOriginalPath = path2.normalize(candidate.originalPath);
1291
+ return suffixes.some((suffix) => normalizedOriginalPath.endsWith(path2.normalize(suffix)));
1292
+ })?.sourceId;
1293
+ }
1294
+ function resolveCodeImportSourceId(manifest, specifier, manifests) {
1295
+ const language = manifest.language ?? inferCodeLanguage(manifest.originalPath ?? manifest.storedPath, manifest.mimeType);
1296
+ switch (language) {
1297
+ case "javascript":
1298
+ case "jsx":
1299
+ case "typescript":
1300
+ case "tsx":
1301
+ return resolveJsLikeImportSourceId(manifest, specifier, manifests);
1302
+ case "python":
1303
+ return resolvePythonImportSourceId(manifest, specifier, manifests);
1304
+ default:
1305
+ return void 0;
1306
+ }
1307
+ }
1308
+ function escapeRegExp(value) {
1309
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1310
+ }
554
1311
  function analyzeCodeSource(manifest, extractedText, schemaHash) {
555
- const code = analyzeTopLevelCode(manifest, extractedText);
1312
+ const language = manifest.language ?? inferCodeLanguage(manifest.originalPath ?? manifest.storedPath, manifest.mimeType) ?? "typescript";
1313
+ const code = language === "python" ? analyzePythonCode(manifest, extractedText) : language === "go" ? analyzeGoCode(manifest, extractedText) : language === "rust" ? analyzeRustCode(manifest, extractedText) : language === "java" ? analyzeJavaCode(manifest, extractedText) : analyzeTypeScriptLikeCode(manifest, extractedText);
556
1314
  return {
557
1315
  sourceId: manifest.sourceId,
558
1316
  sourceHash: manifest.contentHash,
@@ -2432,7 +3190,7 @@ function buildModulePage(input) {
2432
3190
  ]);
2433
3191
  const callsSection = code.symbols.flatMap((symbol) => symbol.calls.map((target) => `- \`${symbol.name}\` calls \`${target}\``));
2434
3192
  const diagnosticsSection = code.diagnostics.length ? code.diagnostics.map(
2435
- (diagnostic) => `- ${diagnostic.category} TS${diagnostic.code} at ${diagnostic.line}:${diagnostic.column}: ${diagnostic.message}`
3193
+ (diagnostic) => `- ${diagnostic.category} diagnostic ${diagnostic.code} at ${diagnostic.line}:${diagnostic.column}: ${diagnostic.message}`
2436
3194
  ) : ["- No parser diagnostics."];
2437
3195
  const frontmatter = {
2438
3196
  page_id: pageId,
@@ -3827,7 +4585,7 @@ async function resolveImageGenerationProvider(rootDir) {
3827
4585
  if (!providerConfig) {
3828
4586
  throw new Error(`No provider configured with id "${preferredProviderId}" for task "imageProvider".`);
3829
4587
  }
3830
- const { createProvider: createProvider2 } = await import("./registry-2XHXZDGH.js");
4588
+ const { createProvider: createProvider2 } = await import("./registry-YDXVCE4Q.js");
3831
4589
  return createProvider2(preferredProviderId, providerConfig, rootDir);
3832
4590
  }
3833
4591
  async function generateOutputArtifacts(rootDir, input) {
@@ -6766,7 +7524,7 @@ async function bootstrapDemo(rootDir, input) {
6766
7524
  }
6767
7525
 
6768
7526
  // src/mcp.ts
6769
- var SERVER_VERSION = "0.1.13";
7527
+ var SERVER_VERSION = "0.1.15";
6770
7528
  async function createMcpServer(rootDir) {
6771
7529
  const server = new McpServer({
6772
7530
  name: "swarmvault",