@swarmvaultai/engine 0.11.0 → 0.12.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 CHANGED
@@ -8379,15 +8379,15 @@ function sourceTypeForNode(node, pagesById) {
8379
8379
  return pagesById.get(node.pageId)?.sourceType;
8380
8380
  }
8381
8381
  function supportingPathDetails(graph, edge) {
8382
- const path31 = shortestGraphPath(graph, edge.source, edge.target);
8382
+ const path32 = shortestGraphPath(graph, edge.source, edge.target);
8383
8383
  const edgesById = new Map(graph.edges.map((item) => [item.id, item]));
8384
- const pathEdges = path31.edgeIds.map((edgeId) => edgesById.get(edgeId)).filter((item) => Boolean(item));
8384
+ const pathEdges = path32.edgeIds.map((edgeId) => edgesById.get(edgeId)).filter((item) => Boolean(item));
8385
8385
  return {
8386
- pathNodeIds: path31.nodeIds,
8387
- pathEdgeIds: path31.edgeIds,
8386
+ pathNodeIds: path32.nodeIds,
8387
+ pathEdgeIds: path32.edgeIds,
8388
8388
  pathRelations: pathEdges.map((item) => item.relation),
8389
8389
  pathEvidenceClasses: pathEdges.map((item) => item.evidenceClass),
8390
- pathSummary: path31.summary
8390
+ pathSummary: path32.summary
8391
8391
  };
8392
8392
  }
8393
8393
  function surpriseScore(edge, graph, pagesById, hyperedgesByNodeId) {
@@ -8456,7 +8456,7 @@ function topSurprisingConnections(graph, pagesById) {
8456
8456
  }).map((edge) => {
8457
8457
  const source = nodesById.get(edge.source);
8458
8458
  const target = nodesById.get(edge.target);
8459
- const path31 = supportingPathDetails(graph, edge);
8459
+ const path32 = supportingPathDetails(graph, edge);
8460
8460
  const scored = surpriseScore(edge, graph, pagesById, hyperedgesByNodeId);
8461
8461
  return {
8462
8462
  id: edge.id,
@@ -8467,11 +8467,11 @@ function topSurprisingConnections(graph, pagesById) {
8467
8467
  relation: edge.relation,
8468
8468
  evidenceClass: edge.evidenceClass,
8469
8469
  confidence: edge.confidence,
8470
- pathNodeIds: path31.pathNodeIds,
8471
- pathEdgeIds: path31.pathEdgeIds,
8472
- pathRelations: path31.pathRelations,
8473
- pathEvidenceClasses: path31.pathEvidenceClasses,
8474
- pathSummary: path31.pathSummary,
8470
+ pathNodeIds: path32.pathNodeIds,
8471
+ pathEdgeIds: path32.pathEdgeIds,
8472
+ pathRelations: path32.pathRelations,
8473
+ pathEvidenceClasses: path32.pathEvidenceClasses,
8474
+ pathSummary: path32.pathSummary,
8475
8475
  why: scored.why,
8476
8476
  explanation: scored.explanation,
8477
8477
  surpriseScore: scored.score
@@ -18646,20 +18646,271 @@ async function readExtractionArtifact(rootDir, manifest) {
18646
18646
  }
18647
18647
 
18648
18648
  // src/mcp.ts
18649
- import fs23 from "fs/promises";
18650
- import path27 from "path";
18649
+ import fs24 from "fs/promises";
18650
+ import path28 from "path";
18651
18651
  import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
18652
18652
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18653
18653
  import { z as z8 } from "zod";
18654
18654
 
18655
- // src/schema.ts
18655
+ // src/migrate.ts
18656
18656
  import fs16 from "fs/promises";
18657
18657
  import path17 from "path";
18658
+ import matter9 from "gray-matter";
18659
+ var VAULT_VERSION_FILENAME = "vault-version.json";
18660
+ async function walkMarkdownFiles(dir) {
18661
+ const results = [];
18662
+ let entries;
18663
+ try {
18664
+ entries = await fs16.readdir(dir, { withFileTypes: true });
18665
+ } catch {
18666
+ return results;
18667
+ }
18668
+ for (const entry of entries) {
18669
+ const full = path17.join(dir, entry.name);
18670
+ if (entry.isDirectory()) {
18671
+ results.push(...await walkMarkdownFiles(full));
18672
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
18673
+ results.push(full);
18674
+ }
18675
+ }
18676
+ return results;
18677
+ }
18678
+ async function readFrontmatterFile(filePath) {
18679
+ try {
18680
+ const raw = await fs16.readFile(filePath, "utf8");
18681
+ const parsed = matter9(raw);
18682
+ const data = parsed.data ?? {};
18683
+ return { data, content: parsed.content };
18684
+ } catch {
18685
+ return null;
18686
+ }
18687
+ }
18688
+ async function writeFrontmatterFile(filePath, data, content) {
18689
+ await fs16.writeFile(filePath, matter9.stringify(content, data), "utf8");
18690
+ }
18691
+ function relFromRoot(rootDir, filePath) {
18692
+ return path17.relative(rootDir, filePath) || filePath;
18693
+ }
18694
+ var MIGRATION_ADD_DECAY_FIELDS = {
18695
+ id: "0.9-to-0.10-add-decay-fields",
18696
+ fromVersion: "0.9.0",
18697
+ toVersion: "0.10.0",
18698
+ description: "Add decay_score and last_confirmed_at frontmatter to pages missing them.",
18699
+ async apply(ctx, options) {
18700
+ const changed = [];
18701
+ const files = await walkMarkdownFiles(ctx.paths.wikiDir);
18702
+ for (const filePath of files) {
18703
+ const parsed = await readFrontmatterFile(filePath);
18704
+ if (!parsed) continue;
18705
+ const { data, content } = parsed;
18706
+ if (!data.page_id) continue;
18707
+ let mutated = false;
18708
+ if (data.decay_score === void 0) {
18709
+ data.decay_score = 1;
18710
+ mutated = true;
18711
+ }
18712
+ if (data.last_confirmed_at === void 0) {
18713
+ data.last_confirmed_at = data.updated_at ?? (/* @__PURE__ */ new Date()).toISOString();
18714
+ mutated = true;
18715
+ }
18716
+ if (mutated) {
18717
+ if (!options.dryRun) {
18718
+ await writeFrontmatterFile(filePath, data, content);
18719
+ }
18720
+ changed.push(relFromRoot(ctx.rootDir, filePath));
18721
+ }
18722
+ }
18723
+ return { changed };
18724
+ }
18725
+ };
18726
+ var MIGRATION_ADD_TIER_DEFAULT = {
18727
+ id: "0.9-to-0.10-add-tier-default",
18728
+ fromVersion: "0.9.0",
18729
+ toVersion: "0.10.0",
18730
+ description: 'Tag insight pages with tier: "working" when the field is absent.',
18731
+ async apply(ctx, options) {
18732
+ const changed = [];
18733
+ const insightsDir = path17.join(ctx.paths.wikiDir, "insights");
18734
+ const files = await walkMarkdownFiles(insightsDir);
18735
+ for (const filePath of files) {
18736
+ const parsed = await readFrontmatterFile(filePath);
18737
+ if (!parsed) continue;
18738
+ const { data, content } = parsed;
18739
+ if (data.kind !== "insight") continue;
18740
+ if (data.tier !== void 0) continue;
18741
+ data.tier = "working";
18742
+ if (!options.dryRun) {
18743
+ await writeFrontmatterFile(filePath, data, content);
18744
+ }
18745
+ changed.push(relFromRoot(ctx.rootDir, filePath));
18746
+ }
18747
+ return { changed };
18748
+ }
18749
+ };
18750
+ var MIGRATION_ADD_TAGS_FIELD = {
18751
+ id: "0.10-to-0.11-add-tags-field",
18752
+ fromVersion: "0.10.0",
18753
+ toVersion: "0.11.0",
18754
+ description: 'Add default tags: ["<kind>"] to derived concept and entity pages missing a tags array.',
18755
+ async apply(ctx, options) {
18756
+ const changed = [];
18757
+ const files = await walkMarkdownFiles(ctx.paths.wikiDir);
18758
+ for (const filePath of files) {
18759
+ const parsed = await readFrontmatterFile(filePath);
18760
+ if (!parsed) continue;
18761
+ const { data, content } = parsed;
18762
+ const kind = data.kind;
18763
+ if (kind !== "concept" && kind !== "entity") continue;
18764
+ if (Array.isArray(data.tags) && data.tags.length > 0) continue;
18765
+ data.tags = [kind];
18766
+ if (!options.dryRun) {
18767
+ await writeFrontmatterFile(filePath, data, content);
18768
+ }
18769
+ changed.push(relFromRoot(ctx.rootDir, filePath));
18770
+ }
18771
+ return { changed };
18772
+ }
18773
+ };
18774
+ var MIGRATION_NOTE_WATCH_BLOCK = {
18775
+ id: "0.10-to-0.11-normalize-config-watch-absence",
18776
+ fromVersion: "0.10.0",
18777
+ toVersion: "0.11.0",
18778
+ description: "Record that swarmvault.config.json watch block is optional in 0.11 (no file changes).",
18779
+ async apply() {
18780
+ return { changed: [] };
18781
+ }
18782
+ };
18783
+ var MIGRATION_REBUILD_SEARCH_INDEX = {
18784
+ id: "any-to-any-rebuild-search-index",
18785
+ fromVersion: "0.9.0",
18786
+ toVersion: "0.11.0",
18787
+ description: "Mark state/search.sqlite as stale so the next compile regenerates it.",
18788
+ async apply(ctx, options) {
18789
+ const changed = [];
18790
+ const searchPath = path17.join(ctx.paths.stateDir, "search.sqlite");
18791
+ try {
18792
+ await fs16.access(searchPath);
18793
+ if (!options.dryRun) {
18794
+ await fs16.rm(searchPath, { force: true });
18795
+ }
18796
+ changed.push(relFromRoot(ctx.rootDir, searchPath));
18797
+ } catch {
18798
+ }
18799
+ return { changed };
18800
+ }
18801
+ };
18802
+ var ALL_MIGRATIONS = [
18803
+ MIGRATION_ADD_DECAY_FIELDS,
18804
+ MIGRATION_ADD_TIER_DEFAULT,
18805
+ MIGRATION_ADD_TAGS_FIELD,
18806
+ MIGRATION_NOTE_WATCH_BLOCK,
18807
+ MIGRATION_REBUILD_SEARCH_INDEX
18808
+ ];
18809
+ function compareSemver(a, b) {
18810
+ const pa = a.split(".").map((part) => Number.parseInt(part, 10));
18811
+ const pb = b.split(".").map((part) => Number.parseInt(part, 10));
18812
+ for (let i = 0; i < 3; i += 1) {
18813
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
18814
+ if (diff !== 0) return diff > 0 ? 1 : -1;
18815
+ }
18816
+ return 0;
18817
+ }
18818
+ async function readVaultVersionRecord(stateDir) {
18819
+ const filePath = path17.join(stateDir, VAULT_VERSION_FILENAME);
18820
+ try {
18821
+ const raw = await fs16.readFile(filePath, "utf8");
18822
+ const parsed = JSON.parse(raw);
18823
+ if (typeof parsed.version === "string") return parsed;
18824
+ return null;
18825
+ } catch {
18826
+ return null;
18827
+ }
18828
+ }
18829
+ async function readGraphVersion(stateDir) {
18830
+ const filePath = path17.join(stateDir, "graph.json");
18831
+ try {
18832
+ const raw = await fs16.readFile(filePath, "utf8");
18833
+ const parsed = JSON.parse(raw);
18834
+ const version = parsed?.generatedBy?.version;
18835
+ return typeof version === "string" ? version : null;
18836
+ } catch {
18837
+ return null;
18838
+ }
18839
+ }
18840
+ async function detectVaultVersion(rootDir) {
18841
+ const { paths } = await initWorkspace(rootDir);
18842
+ const record = await readVaultVersionRecord(paths.stateDir);
18843
+ if (record) return record.version;
18844
+ const graphVersion = await readGraphVersion(paths.stateDir);
18845
+ if (graphVersion) return graphVersion;
18846
+ return null;
18847
+ }
18848
+ async function currentPackageVersion() {
18849
+ try {
18850
+ const raw = await fs16.readFile(new URL("../package.json", import.meta.url), "utf8");
18851
+ const parsed = JSON.parse(raw);
18852
+ return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version : "0.0.0";
18853
+ } catch {
18854
+ return "0.0.0";
18855
+ }
18856
+ }
18857
+ async function planMigration(rootDir, targetVersion) {
18858
+ const fromVersion = await detectVaultVersion(rootDir);
18859
+ const toVersion = targetVersion ?? await currentPackageVersion();
18860
+ const steps = ALL_MIGRATIONS.filter((step) => compareSemver(step.toVersion, toVersion) <= 0).filter((step) => {
18861
+ if (!fromVersion) return true;
18862
+ return compareSemver(step.toVersion, fromVersion) > 0;
18863
+ });
18864
+ return { fromVersion, toVersion, steps };
18865
+ }
18866
+ async function writeVaultVersionRecord(stateDir, record) {
18867
+ await fs16.mkdir(stateDir, { recursive: true });
18868
+ await fs16.writeFile(path17.join(stateDir, VAULT_VERSION_FILENAME), `${JSON.stringify(record, null, 2)}
18869
+ `, "utf8");
18870
+ }
18871
+ async function runMigration(rootDir, options = {}) {
18872
+ const dryRun = options.dryRun ?? true;
18873
+ const { paths } = await initWorkspace(rootDir);
18874
+ const plan = await planMigration(rootDir, options.targetVersion);
18875
+ const applied = [];
18876
+ const skipped = [];
18877
+ const ctx = {
18878
+ rootDir,
18879
+ paths: { wikiDir: paths.wikiDir, stateDir: paths.stateDir, rootDir }
18880
+ };
18881
+ for (const step of plan.steps) {
18882
+ const { changed } = await step.apply(ctx, { dryRun });
18883
+ if (changed.length === 0) {
18884
+ skipped.push({ id: step.id, reason: "No changes required." });
18885
+ } else {
18886
+ applied.push({ id: step.id, changed });
18887
+ }
18888
+ }
18889
+ if (!dryRun && applied.length > 0) {
18890
+ await writeVaultVersionRecord(paths.stateDir, {
18891
+ version: plan.toVersion,
18892
+ migratedAt: (/* @__PURE__ */ new Date()).toISOString(),
18893
+ appliedSteps: applied.map((entry) => entry.id)
18894
+ });
18895
+ }
18896
+ return {
18897
+ planned: plan.steps.length,
18898
+ applied,
18899
+ skipped,
18900
+ dryRun,
18901
+ fromVersion: plan.fromVersion,
18902
+ toVersion: plan.toVersion
18903
+ };
18904
+ }
18905
+
18906
+ // src/schema.ts
18907
+ import fs17 from "fs/promises";
18908
+ import path18 from "path";
18658
18909
  function normalizeSchemaContent(content) {
18659
18910
  return content.trim() ? content.trim() : defaultVaultSchema().trim();
18660
18911
  }
18661
18912
  async function readSchemaFile(schemaPath, fallback = defaultVaultSchema()) {
18662
- const content = await fileExists(schemaPath) ? await fs16.readFile(schemaPath, "utf8") : fallback;
18913
+ const content = await fileExists(schemaPath) ? await fs17.readFile(schemaPath, "utf8") : fallback;
18663
18914
  const normalized = normalizeSchemaContent(content);
18664
18915
  return {
18665
18916
  path: schemaPath,
@@ -18668,7 +18919,7 @@ async function readSchemaFile(schemaPath, fallback = defaultVaultSchema()) {
18668
18919
  };
18669
18920
  }
18670
18921
  function resolveProjectSchemaPath(rootDir, schemaPath) {
18671
- return path17.resolve(rootDir, schemaPath);
18922
+ return path18.resolve(rootDir, schemaPath);
18672
18923
  }
18673
18924
  function composeVaultSchema(root, projectSchemas = []) {
18674
18925
  if (!projectSchemas.length) {
@@ -18684,7 +18935,7 @@ function composeVaultSchema(root, projectSchemas = []) {
18684
18935
  (schema) => [
18685
18936
  `## Project Schema`,
18686
18937
  "",
18687
- `Path: ${toPosix(path17.relative(path17.dirname(root.path), schema.path) || schema.path)}`,
18938
+ `Path: ${toPosix(path18.relative(path18.dirname(root.path), schema.path) || schema.path)}`,
18688
18939
  "",
18689
18940
  schema.content
18690
18941
  ].join("\n")
@@ -18760,15 +19011,15 @@ function buildSchemaPrompt(schema, instruction) {
18760
19011
  }
18761
19012
 
18762
19013
  // src/vault.ts
18763
- import fs21 from "fs/promises";
18764
- import path25 from "path";
19014
+ import fs22 from "fs/promises";
19015
+ import path26 from "path";
18765
19016
  import Graph from "graphology";
18766
19017
  import louvain from "graphology-communities-louvain";
18767
- import matter12 from "gray-matter";
19018
+ import matter13 from "gray-matter";
18768
19019
  import { z as z7 } from "zod";
18769
19020
 
18770
19021
  // src/analysis.ts
18771
- import path18 from "path";
19022
+ import path19 from "path";
18772
19023
  import nlp2 from "compromise";
18773
19024
  import { z as z2 } from "zod";
18774
19025
 
@@ -18857,7 +19108,7 @@ var MARKDOWN_RATIONALE_KINDS = /* @__PURE__ */ new Set([
18857
19108
  var PLAIN_TEXT_RATIONALE_KINDS = /* @__PURE__ */ new Set(["text", "transcript", "chat_export", "email", "calendar"]);
18858
19109
  function filenameStemForSource(manifest) {
18859
19110
  const candidate = manifest.repoRelativePath ?? manifest.originalPath ?? manifest.storedPath;
18860
- const base = path18.basename(candidate);
19111
+ const base = path19.basename(candidate);
18861
19112
  const stem = base.replace(/\.[^.]+$/, "");
18862
19113
  return stem || manifest.title;
18863
19114
  }
@@ -19137,7 +19388,7 @@ function extractionWarningSummary(manifest, extraction) {
19137
19388
  return `Imported ${manifest.sourceKind} source. Text extraction is not yet available for this source.`;
19138
19389
  }
19139
19390
  async function analyzeSource(manifest, extractedText, provider, paths, schema) {
19140
- const cachePath = path18.join(paths.analysesDir, `${manifest.sourceId}.json`);
19391
+ const cachePath = path19.join(paths.analysesDir, `${manifest.sourceId}.json`);
19141
19392
  const cached = await readJsonFile(cachePath);
19142
19393
  if (cached && cached.analysisVersion === ANALYSIS_FORMAT_VERSION && (cached.semanticHash ?? cached.sourceHash) === manifest.semanticHash && cached.extractionHash === manifest.extractionHash && cached.schemaHash === schema.hash) {
19143
19394
  const normalizedCached = normalizeSourceAnalysis(manifest, cached);
@@ -19240,9 +19491,9 @@ function conflictConfidence(claimA, claimB) {
19240
19491
  }
19241
19492
 
19242
19493
  // src/deep-lint.ts
19243
- import fs17 from "fs/promises";
19244
- import path21 from "path";
19245
- import matter9 from "gray-matter";
19494
+ import fs18 from "fs/promises";
19495
+ import path22 from "path";
19496
+ import matter10 from "gray-matter";
19246
19497
  import { z as z5 } from "zod";
19247
19498
 
19248
19499
  // src/findings.ts
@@ -19262,7 +19513,7 @@ function normalizeFindingSeverity(value) {
19262
19513
 
19263
19514
  // src/orchestration.ts
19264
19515
  import { spawn } from "child_process";
19265
- import path19 from "path";
19516
+ import path20 from "path";
19266
19517
  import { z as z3 } from "zod";
19267
19518
  var orchestrationRoleResultSchema = z3.object({
19268
19519
  summary: z3.string().optional(),
@@ -19355,7 +19606,7 @@ async function runProviderRole(rootDir, role, roleConfig, input) {
19355
19606
  }
19356
19607
  async function runCommandRole(rootDir, role, executor, input) {
19357
19608
  const [command, ...args] = executor.command;
19358
- const cwd = executor.cwd ? path19.resolve(rootDir, executor.cwd) : rootDir;
19609
+ const cwd = executor.cwd ? path20.resolve(rootDir, executor.cwd) : rootDir;
19359
19610
  const child = spawn(command, args, {
19360
19611
  cwd,
19361
19612
  env: {
@@ -19449,7 +19700,7 @@ function summarizeRoleQuestions(results) {
19449
19700
  }
19450
19701
 
19451
19702
  // src/web-search/registry.ts
19452
- import path20 from "path";
19703
+ import path21 from "path";
19453
19704
  import { pathToFileURL as pathToFileURL2 } from "url";
19454
19705
  import { z as z4 } from "zod";
19455
19706
 
@@ -19547,7 +19798,7 @@ async function createWebSearchAdapter(id, config, rootDir) {
19547
19798
  if (!config.module) {
19548
19799
  throw new Error(`Web search provider ${id} is type "custom" but no module path was configured.`);
19549
19800
  }
19550
- const resolvedModule = path20.isAbsolute(config.module) ? config.module : path20.resolve(rootDir, config.module);
19801
+ const resolvedModule = path21.isAbsolute(config.module) ? config.module : path21.resolve(rootDir, config.module);
19551
19802
  const loaded = await import(pathToFileURL2(resolvedModule).href);
19552
19803
  const parsed = customWebSearchModuleSchema.parse(loaded);
19553
19804
  return parsed.createAdapter(id, config, rootDir);
@@ -19617,9 +19868,9 @@ async function loadContextPages(rootDir, graph) {
19617
19868
  );
19618
19869
  return Promise.all(
19619
19870
  contextPages.slice(0, 18).map(async (page) => {
19620
- const absolutePath = path21.join(paths.wikiDir, page.path);
19621
- const raw = await fs17.readFile(absolutePath, "utf8").catch(() => "");
19622
- const parsed = matter9(raw);
19871
+ const absolutePath = path22.join(paths.wikiDir, page.path);
19872
+ const raw = await fs18.readFile(absolutePath, "utf8").catch(() => "");
19873
+ const parsed = matter10(raw);
19623
19874
  return {
19624
19875
  id: page.id,
19625
19876
  title: page.title,
@@ -19666,7 +19917,7 @@ function heuristicDeepFindings(contextPages, structuralFindings, graph) {
19666
19917
  code: "missing_citation",
19667
19918
  message: finding.message,
19668
19919
  pagePath: finding.pagePath,
19669
- suggestedQuery: finding.pagePath ? `Which sources support the claims in ${path21.basename(finding.pagePath, ".md")}?` : void 0
19920
+ suggestedQuery: finding.pagePath ? `Which sources support the claims in ${path22.basename(finding.pagePath, ".md")}?` : void 0
19670
19921
  });
19671
19922
  }
19672
19923
  for (const page of contextPages.filter((item) => item.kind === "source").slice(0, 3)) {
@@ -20039,9 +20290,9 @@ function buildOutputAssetManifest(input) {
20039
20290
  }
20040
20291
 
20041
20292
  // src/outputs.ts
20042
- import fs18 from "fs/promises";
20043
- import path22 from "path";
20044
- import matter10 from "gray-matter";
20293
+ import fs19 from "fs/promises";
20294
+ import path23 from "path";
20295
+ import matter11 from "gray-matter";
20045
20296
  function relationRank(outputPage, targetPage) {
20046
20297
  if (outputPage.relatedPageIds.includes(targetPage.id)) {
20047
20298
  return 3;
@@ -20058,19 +20309,19 @@ function relatedOutputsForPage(targetPage, outputPages) {
20058
20309
  return outputPages.map((page) => ({ page, rank: relationRank(page, targetPage) })).filter((item) => item.rank > 0).sort((left, right) => right.rank - left.rank || left.page.title.localeCompare(right.page.title)).map((item) => item.page);
20059
20310
  }
20060
20311
  async function resolveUniqueOutputSlug(wikiDir, baseSlug) {
20061
- const outputsDir = path22.join(wikiDir, "outputs");
20312
+ const outputsDir = path23.join(wikiDir, "outputs");
20062
20313
  const root = baseSlug || "output";
20063
20314
  let candidate = root;
20064
20315
  let counter = 2;
20065
- while (await fileExists(path22.join(outputsDir, `${candidate}.md`))) {
20316
+ while (await fileExists(path23.join(outputsDir, `${candidate}.md`))) {
20066
20317
  candidate = `${root}-${counter}`;
20067
20318
  counter++;
20068
20319
  }
20069
20320
  return candidate;
20070
20321
  }
20071
20322
  async function loadSavedOutputPages(wikiDir) {
20072
- const outputsDir = path22.join(wikiDir, "outputs");
20073
- const entries = await fs18.readdir(outputsDir, { withFileTypes: true }).catch(() => []);
20323
+ const outputsDir = path23.join(wikiDir, "outputs");
20324
+ const entries = await fs19.readdir(outputsDir, { withFileTypes: true }).catch(() => []);
20074
20325
  const outputs = [];
20075
20326
  const queue = [{ absoluteDir: outputsDir, relativeDir: "outputs" }];
20076
20327
  while (queue.length > 0) {
@@ -20078,24 +20329,24 @@ async function loadSavedOutputPages(wikiDir) {
20078
20329
  if (!current) {
20079
20330
  continue;
20080
20331
  }
20081
- const currentEntries = current.absoluteDir === outputsDir ? entries : await fs18.readdir(current.absoluteDir, { withFileTypes: true }).catch(() => []);
20332
+ const currentEntries = current.absoluteDir === outputsDir ? entries : await fs19.readdir(current.absoluteDir, { withFileTypes: true }).catch(() => []);
20082
20333
  for (const entry of currentEntries) {
20083
20334
  if (entry.isDirectory()) {
20084
20335
  queue.push({
20085
- absoluteDir: path22.join(current.absoluteDir, entry.name),
20086
- relativeDir: path22.posix.join(current.relativeDir, entry.name)
20336
+ absoluteDir: path23.join(current.absoluteDir, entry.name),
20337
+ relativeDir: path23.posix.join(current.relativeDir, entry.name)
20087
20338
  });
20088
20339
  continue;
20089
20340
  }
20090
20341
  if (!entry.isFile() || !entry.name.endsWith(".md") || entry.name === "index.md") {
20091
20342
  continue;
20092
20343
  }
20093
- const relativePath = path22.posix.join(current.relativeDir, entry.name);
20094
- const absolutePath = path22.join(current.absoluteDir, entry.name);
20095
- const content = await fs18.readFile(absolutePath, "utf8");
20096
- const parsed = matter10(content);
20344
+ const relativePath = path23.posix.join(current.relativeDir, entry.name);
20345
+ const absolutePath = path23.join(current.absoluteDir, entry.name);
20346
+ const content = await fs19.readFile(absolutePath, "utf8");
20347
+ const parsed = matter11(content);
20097
20348
  const slug = relativePath.replace(/^outputs\//, "").replace(/\.md$/, "");
20098
- const title = typeof parsed.data.title === "string" ? parsed.data.title : path22.basename(slug);
20349
+ const title = typeof parsed.data.title === "string" ? parsed.data.title : path23.basename(slug);
20099
20350
  const pageId = typeof parsed.data.page_id === "string" ? parsed.data.page_id : `output:${slug}`;
20100
20351
  const sourceIds = normalizeStringArray(parsed.data.source_ids);
20101
20352
  const projectIds = normalizeProjectIds(parsed.data.project_ids);
@@ -20105,7 +20356,7 @@ async function loadSavedOutputPages(wikiDir) {
20105
20356
  const relatedSourceIds = normalizeStringArray(parsed.data.related_source_ids);
20106
20357
  const backlinks = normalizeStringArray(parsed.data.backlinks);
20107
20358
  const compiledFrom = normalizeStringArray(parsed.data.compiled_from);
20108
- const stats = await fs18.stat(absolutePath);
20359
+ const stats = await fs19.stat(absolutePath);
20109
20360
  const createdAt = typeof parsed.data.created_at === "string" ? parsed.data.created_at : stats.birthtimeMs > 0 ? stats.birthtime.toISOString() : stats.mtime.toISOString();
20110
20361
  const updatedAt = typeof parsed.data.updated_at === "string" ? parsed.data.updated_at : stats.mtime.toISOString();
20111
20362
  outputs.push({
@@ -20145,9 +20396,9 @@ async function loadSavedOutputPages(wikiDir) {
20145
20396
  }
20146
20397
 
20147
20398
  // src/search.ts
20148
- import fs19 from "fs/promises";
20149
- import path23 from "path";
20150
- import matter11 from "gray-matter";
20399
+ import fs20 from "fs/promises";
20400
+ import path24 from "path";
20401
+ import matter12 from "gray-matter";
20151
20402
  function warningMessage(warning) {
20152
20403
  return warning instanceof Error ? warning.message : String(warning);
20153
20404
  }
@@ -20200,7 +20451,7 @@ function normalizeSourceClass2(value) {
20200
20451
  return value === "first_party" || value === "third_party" || value === "resource" || value === "generated" ? value : void 0;
20201
20452
  }
20202
20453
  async function rebuildSearchIndex(dbPath, pages, wikiDir) {
20203
- await ensureDir(path23.dirname(dbPath));
20454
+ await ensureDir(path24.dirname(dbPath));
20204
20455
  const DatabaseSync = getDatabaseSync();
20205
20456
  const db = withSuppressedSqliteExperimentalWarning(() => new DatabaseSync(dbPath));
20206
20457
  db.exec("PRAGMA journal_mode = WAL;");
@@ -20231,21 +20482,21 @@ async function rebuildSearchIndex(dbPath, pages, wikiDir) {
20231
20482
  const insertPage = db.prepare(
20232
20483
  "INSERT INTO pages (id, path, title, body, kind, status, source_type, source_class, project_ids, project_key) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
20233
20484
  );
20234
- const rootDir = path23.dirname(wikiDir);
20485
+ const rootDir = path24.dirname(wikiDir);
20235
20486
  for (const page of pages) {
20236
- const absolutePath = path23.join(wikiDir, page.path);
20237
- const content = await fs19.readFile(absolutePath, "utf8");
20238
- const parsed = matter11(content);
20487
+ const absolutePath = path24.join(wikiDir, page.path);
20488
+ const content = await fs20.readFile(absolutePath, "utf8");
20489
+ const parsed = matter12(content);
20239
20490
  let body = parsed.content;
20240
20491
  const primarySourceId = Array.isArray(parsed.data.source_ids) && typeof parsed.data.source_ids[0] === "string" ? parsed.data.source_ids[0] : page.sourceIds[0];
20241
20492
  if ((page.kind === "source" || page.kind === "module") && primarySourceId) {
20242
20493
  try {
20243
20494
  const manifest = JSON.parse(
20244
- await fs19.readFile(path23.join(rootDir, "state", "manifests", `${primarySourceId}.json`), "utf8")
20495
+ await fs20.readFile(path24.join(rootDir, "state", "manifests", `${primarySourceId}.json`), "utf8")
20245
20496
  );
20246
20497
  const excerptPath = manifest.extractedTextPath ?? manifest.storedPath;
20247
20498
  if (excerptPath) {
20248
- const excerpt = await fs19.readFile(path23.join(rootDir, excerptPath), "utf8");
20499
+ const excerpt = await fs20.readFile(path24.join(rootDir, excerptPath), "utf8");
20249
20500
  if (excerpt.trim()) {
20250
20501
  body = `${body}
20251
20502
 
@@ -20401,16 +20652,16 @@ function searchPages(dbPath, query, limitOrOptions = 5) {
20401
20652
  }
20402
20653
 
20403
20654
  // src/source-sessions.ts
20404
- import fs20 from "fs/promises";
20405
- import path24 from "path";
20655
+ import fs21 from "fs/promises";
20656
+ import path25 from "path";
20406
20657
  function sessionStatePathFor(paths, sessionId) {
20407
- return path24.join(paths.sourceSessionsDir, `${sessionId}.json`);
20658
+ return path25.join(paths.sourceSessionsDir, `${sessionId}.json`);
20408
20659
  }
20409
20660
  async function listGuidedSourceSessions(rootDir) {
20410
20661
  const { paths } = await loadVaultConfig(rootDir);
20411
- const entries = await fs20.readdir(paths.sourceSessionsDir, { withFileTypes: true }).catch(() => []);
20662
+ const entries = await fs21.readdir(paths.sourceSessionsDir, { withFileTypes: true }).catch(() => []);
20412
20663
  const sessions = await Promise.all(
20413
- entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => await readJsonFile(path24.join(paths.sourceSessionsDir, entry.name)))
20664
+ entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => await readJsonFile(path25.join(paths.sourceSessionsDir, entry.name)))
20414
20665
  );
20415
20666
  return sessions.filter((session) => Boolean(session)).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
20416
20667
  }
@@ -20430,7 +20681,7 @@ async function writeGuidedSourceSession(rootDir, session) {
20430
20681
  updatedAt: session.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
20431
20682
  };
20432
20683
  const filePath = sessionStatePathFor(paths, session.sessionId);
20433
- await fs20.writeFile(filePath, `${JSON.stringify(next, null, 2)}
20684
+ await fs21.writeFile(filePath, `${JSON.stringify(next, null, 2)}
20434
20685
  `, "utf8");
20435
20686
  return filePath;
20436
20687
  }
@@ -20506,7 +20757,7 @@ function outputFormatInstruction(format) {
20506
20757
  }
20507
20758
  }
20508
20759
  function outputAssetPath(slug, fileName) {
20509
- return toPosix(path25.join("outputs", "assets", slug, fileName));
20760
+ return toPosix(path26.join("outputs", "assets", slug, fileName));
20510
20761
  }
20511
20762
  function outputAssetId(slug, role) {
20512
20763
  return `output:${slug}:asset:${role}`;
@@ -20844,7 +21095,7 @@ async function generateOutputArtifacts(rootDir, input) {
20844
21095
  };
20845
21096
  }
20846
21097
  function normalizeProjectRoot(root) {
20847
- const normalized = toPosix(path25.posix.normalize(root.replace(/\\/g, "/"))).replace(/^\.\/+/, "").replace(/\/+$/, "");
21098
+ const normalized = toPosix(path26.posix.normalize(root.replace(/\\/g, "/"))).replace(/^\.\/+/, "").replace(/\/+$/, "");
20848
21099
  return normalized;
20849
21100
  }
20850
21101
  function projectEntries(config) {
@@ -20870,10 +21121,10 @@ function manifestPathForProject(rootDir, manifest) {
20870
21121
  if (!rawPath) {
20871
21122
  return toPosix(manifest.storedPath);
20872
21123
  }
20873
- if (!path25.isAbsolute(rawPath)) {
21124
+ if (!path26.isAbsolute(rawPath)) {
20874
21125
  return normalizeProjectRoot(rawPath);
20875
21126
  }
20876
- const relative = toPosix(path25.relative(rootDir, rawPath));
21127
+ const relative = toPosix(path26.relative(rootDir, rawPath));
20877
21128
  return relative.startsWith("..") ? toPosix(rawPath) : normalizeProjectRoot(relative);
20878
21129
  }
20879
21130
  function prefixMatches(value, prefix) {
@@ -21050,7 +21301,7 @@ function pageHashes(pages) {
21050
21301
  return Object.fromEntries(pages.map((page) => [page.page.id, page.contentHash]));
21051
21302
  }
21052
21303
  async function buildManagedGraphPage(absolutePath, defaults, build) {
21053
- const existingContent = await fileExists(absolutePath) ? await fs21.readFile(absolutePath, "utf8") : null;
21304
+ const existingContent = await fileExists(absolutePath) ? await fs22.readFile(absolutePath, "utf8") : null;
21054
21305
  let carriedContent = existingContent;
21055
21306
  let existing = await loadExistingManagedPageState(absolutePath, {
21056
21307
  status: defaults.status ?? "active",
@@ -21066,7 +21317,7 @@ async function buildManagedGraphPage(absolutePath, defaults, build) {
21066
21317
  status: defaults.status ?? "active",
21067
21318
  managedBy: defaults.managedBy
21068
21319
  });
21069
- carriedContent = await fs21.readFile(candidatePath, "utf8");
21320
+ carriedContent = await fs22.readFile(candidatePath, "utf8");
21070
21321
  usedFallbackState = true;
21071
21322
  break;
21072
21323
  }
@@ -21090,7 +21341,7 @@ async function buildManagedGraphPage(absolutePath, defaults, build) {
21090
21341
  return built;
21091
21342
  }
21092
21343
  async function buildManagedContent(absolutePath, defaults, build) {
21093
- const existingContent = await fileExists(absolutePath) ? await fs21.readFile(absolutePath, "utf8") : null;
21344
+ const existingContent = await fileExists(absolutePath) ? await fs22.readFile(absolutePath, "utf8") : null;
21094
21345
  let existing = await loadExistingManagedPageState(absolutePath, {
21095
21346
  status: defaults.status ?? "active",
21096
21347
  managedBy: defaults.managedBy
@@ -21132,7 +21383,7 @@ function manifestDetailValue(manifest, key) {
21132
21383
  }
21133
21384
  async function loadAnalysesBySourceIds(paths, sourceIds) {
21134
21385
  const analyses = await Promise.all(
21135
- sourceIds.map(async (sourceId) => await readJsonFile(path25.join(paths.analysesDir, `${sourceId}.json`)))
21386
+ sourceIds.map(async (sourceId) => await readJsonFile(path26.join(paths.analysesDir, `${sourceId}.json`)))
21136
21387
  );
21137
21388
  return analyses.filter((analysis) => Boolean(analysis?.sourceId));
21138
21389
  }
@@ -21157,7 +21408,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21157
21408
  ).slice(0, 20);
21158
21409
  const sourceSessions = await listGuidedSourceSessions(paths.rootDir);
21159
21410
  const stagedGuideBundles = (await Promise.all(
21160
- (await fs21.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => await readApprovalManifest(paths, entry.name).catch(() => null))
21411
+ (await fs22.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => await readApprovalManifest(paths, entry.name).catch(() => null))
21161
21412
  )).filter((manifest) => Boolean(manifest)).filter((manifest) => manifest.bundleType === "guided-source" || manifest.bundleType === "guided-session").sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, 12);
21162
21413
  const readerFocusPages = uniqueBy([...guidePages, ...briefPages, ...conceptPages, ...entityPages], (page) => page.id).slice(0, 8);
21163
21414
  const diligenceSessions = sourceSessions.filter((session) => session.status === "staged" || session.status === "awaiting_input").slice(0, 8);
@@ -21165,7 +21416,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21165
21416
  {
21166
21417
  relativePath: "dashboards/index.md",
21167
21418
  title: "Dashboards",
21168
- content: (metadata) => matter12.stringify(
21419
+ content: (metadata) => matter13.stringify(
21169
21420
  [
21170
21421
  "# Dashboards",
21171
21422
  "",
@@ -21217,7 +21468,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21217
21468
  {
21218
21469
  relativePath: "dashboards/recent-sources.md",
21219
21470
  title: "Recent Sources",
21220
- content: (metadata) => matter12.stringify(
21471
+ content: (metadata) => matter13.stringify(
21221
21472
  [
21222
21473
  "# Recent Sources",
21223
21474
  "",
@@ -21260,7 +21511,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21260
21511
  {
21261
21512
  relativePath: "dashboards/reading-log.md",
21262
21513
  title: "Reading Log",
21263
- content: (metadata) => matter12.stringify(
21514
+ content: (metadata) => matter13.stringify(
21264
21515
  [
21265
21516
  "# Reading Log",
21266
21517
  "",
@@ -21320,7 +21571,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21320
21571
  {
21321
21572
  relativePath: "dashboards/timeline.md",
21322
21573
  title: "Timeline",
21323
- content: (metadata) => matter12.stringify(
21574
+ content: (metadata) => matter13.stringify(
21324
21575
  [
21325
21576
  "# Timeline",
21326
21577
  "",
@@ -21366,7 +21617,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21366
21617
  {
21367
21618
  relativePath: "dashboards/source-sessions.md",
21368
21619
  title: "Source Sessions",
21369
- content: (metadata) => matter12.stringify(
21620
+ content: (metadata) => matter13.stringify(
21370
21621
  [
21371
21622
  "# Source Sessions",
21372
21623
  "",
@@ -21423,7 +21674,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21423
21674
  {
21424
21675
  relativePath: "dashboards/source-guides.md",
21425
21676
  title: "Source Guides",
21426
- content: (metadata) => matter12.stringify(
21677
+ content: (metadata) => matter13.stringify(
21427
21678
  [
21428
21679
  "# Source Guides",
21429
21680
  "",
@@ -21476,7 +21727,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21476
21727
  {
21477
21728
  relativePath: "dashboards/research-map.md",
21478
21729
  title: "Research Map",
21479
- content: (metadata) => matter12.stringify(
21730
+ content: (metadata) => matter13.stringify(
21480
21731
  [
21481
21732
  "# Research Map",
21482
21733
  "",
@@ -21540,7 +21791,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21540
21791
  {
21541
21792
  relativePath: "dashboards/contradictions.md",
21542
21793
  title: "Contradictions",
21543
- content: (metadata) => matter12.stringify(
21794
+ content: (metadata) => matter13.stringify(
21544
21795
  [
21545
21796
  "# Contradictions",
21546
21797
  "",
@@ -21599,7 +21850,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21599
21850
  {
21600
21851
  relativePath: "dashboards/open-questions.md",
21601
21852
  title: "Open Questions",
21602
- content: (metadata) => matter12.stringify(
21853
+ content: (metadata) => matter13.stringify(
21603
21854
  [
21604
21855
  "# Open Questions",
21605
21856
  "",
@@ -21645,7 +21896,7 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
21645
21896
  ];
21646
21897
  const records = [];
21647
21898
  for (const dashboard of dashboards) {
21648
- const absolutePath = path25.join(paths.wikiDir, dashboard.relativePath);
21899
+ const absolutePath = path26.join(paths.wikiDir, dashboard.relativePath);
21649
21900
  const compiledFrom = dashboard.relativePath === "dashboards/recent-sources.md" ? recentSourcePages.flatMap((page) => page.sourceIds) : [];
21650
21901
  const content = await buildManagedContent(
21651
21902
  absolutePath,
@@ -21808,7 +22059,7 @@ function resetGraphNodeMetrics(nodes) {
21808
22059
  );
21809
22060
  }
21810
22061
  function manifestRepoPath(manifest) {
21811
- return toPosix(manifest.repoRelativePath ?? path25.basename(manifest.originalPath ?? manifest.storedPath));
22062
+ return toPosix(manifest.repoRelativePath ?? path26.basename(manifest.originalPath ?? manifest.storedPath));
21812
22063
  }
21813
22064
  function goPackageScopeKey(manifest, analysis) {
21814
22065
  if (analysis.code?.language !== "go") {
@@ -21818,7 +22069,7 @@ function goPackageScopeKey(manifest, analysis) {
21818
22069
  if (!packageName) {
21819
22070
  return null;
21820
22071
  }
21821
- return `${packageName}:${path25.posix.dirname(manifestRepoPath(manifest))}`;
22072
+ return `${packageName}:${path26.posix.dirname(manifestRepoPath(manifest))}`;
21822
22073
  }
21823
22074
  function buildGoPackageSymbolLookups(analyses, manifestsById) {
21824
22075
  const lookups = /* @__PURE__ */ new Map();
@@ -22343,7 +22594,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
22343
22594
  const benchmark = await readJsonFile(paths.benchmarkPath);
22344
22595
  const communityRecords = [];
22345
22596
  for (const community of graph.communities ?? []) {
22346
- const absolutePath = path25.join(paths.wikiDir, "graph", "communities", `${community.id.replace(/^community:/, "")}.md`);
22597
+ const absolutePath = path26.join(paths.wikiDir, "graph", "communities", `${community.id.replace(/^community:/, "")}.md`);
22347
22598
  communityRecords.push(
22348
22599
  await buildManagedGraphPage(
22349
22600
  absolutePath,
@@ -22373,7 +22624,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
22373
22624
  contradictions,
22374
22625
  config
22375
22626
  });
22376
- const reportAbsolutePath = path25.join(paths.wikiDir, "graph", "report.md");
22627
+ const reportAbsolutePath = path26.join(paths.wikiDir, "graph", "report.md");
22377
22628
  const reportRecord = await buildManagedGraphPage(
22378
22629
  reportAbsolutePath,
22379
22630
  {
@@ -22394,7 +22645,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
22394
22645
  };
22395
22646
  }
22396
22647
  async function writePage(wikiDir, relativePath, content, changedPages) {
22397
- const absolutePath = path25.resolve(wikiDir, relativePath);
22648
+ const absolutePath = path26.resolve(wikiDir, relativePath);
22398
22649
  const changed = await writeFileIfChanged(absolutePath, content);
22399
22650
  if (changed) {
22400
22651
  changedPages.push(relativePath);
@@ -22460,29 +22711,29 @@ async function requiredCompileArtifactsExist(paths) {
22460
22711
  paths.graphPath,
22461
22712
  paths.codeIndexPath,
22462
22713
  paths.searchDbPath,
22463
- path25.join(paths.wikiDir, "index.md"),
22464
- path25.join(paths.wikiDir, "sources", "index.md"),
22465
- path25.join(paths.wikiDir, "code", "index.md"),
22466
- path25.join(paths.wikiDir, "concepts", "index.md"),
22467
- path25.join(paths.wikiDir, "entities", "index.md"),
22468
- path25.join(paths.wikiDir, "outputs", "index.md"),
22469
- path25.join(paths.wikiDir, "projects", "index.md"),
22470
- path25.join(paths.wikiDir, "candidates", "index.md")
22714
+ path26.join(paths.wikiDir, "index.md"),
22715
+ path26.join(paths.wikiDir, "sources", "index.md"),
22716
+ path26.join(paths.wikiDir, "code", "index.md"),
22717
+ path26.join(paths.wikiDir, "concepts", "index.md"),
22718
+ path26.join(paths.wikiDir, "entities", "index.md"),
22719
+ path26.join(paths.wikiDir, "outputs", "index.md"),
22720
+ path26.join(paths.wikiDir, "projects", "index.md"),
22721
+ path26.join(paths.wikiDir, "candidates", "index.md")
22471
22722
  ];
22472
22723
  const checks = await Promise.all(requiredPaths.map((filePath) => fileExists(filePath)));
22473
22724
  return checks.every(Boolean);
22474
22725
  }
22475
22726
  async function loadAvailableCachedAnalyses(paths, manifests) {
22476
22727
  const analyses = await Promise.all(
22477
- manifests.map(async (manifest) => readJsonFile(path25.join(paths.analysesDir, `${manifest.sourceId}.json`)))
22728
+ manifests.map(async (manifest) => readJsonFile(path26.join(paths.analysesDir, `${manifest.sourceId}.json`)))
22478
22729
  );
22479
22730
  return analyses.filter((analysis) => Boolean(analysis));
22480
22731
  }
22481
22732
  function approvalManifestPath(paths, approvalId) {
22482
- return path25.join(paths.approvalsDir, approvalId, "manifest.json");
22733
+ return path26.join(paths.approvalsDir, approvalId, "manifest.json");
22483
22734
  }
22484
22735
  function approvalGraphPath(paths, approvalId) {
22485
- return path25.join(paths.approvalsDir, approvalId, "state", "graph.json");
22736
+ return path26.join(paths.approvalsDir, approvalId, "state", "graph.json");
22486
22737
  }
22487
22738
  function normalizeApprovalBundleType(raw) {
22488
22739
  if (!raw) return void 0;
@@ -22503,7 +22754,7 @@ async function readApprovalManifest(paths, approvalId) {
22503
22754
  return manifest;
22504
22755
  }
22505
22756
  async function writeApprovalManifest(paths, manifest) {
22506
- await fs21.writeFile(approvalManifestPath(paths, manifest.approvalId), `${JSON.stringify(manifest, null, 2)}
22757
+ await fs22.writeFile(approvalManifestPath(paths, manifest.approvalId), `${JSON.stringify(manifest, null, 2)}
22507
22758
  `, "utf8");
22508
22759
  }
22509
22760
  async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousGraph, graph, labelsByPath = /* @__PURE__ */ new Map()) {
@@ -22518,7 +22769,7 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
22518
22769
  continue;
22519
22770
  }
22520
22771
  const previousPage = previousPagesById.get(nextPage.id);
22521
- const currentExists = await fileExists(path25.join(paths.wikiDir, file.relativePath));
22772
+ const currentExists = await fileExists(path26.join(paths.wikiDir, file.relativePath));
22522
22773
  if (previousPage && previousPage.path !== nextPage.path) {
22523
22774
  entries.push({
22524
22775
  pageId: nextPage.id,
@@ -22553,7 +22804,7 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
22553
22804
  const previousPage = previousPagesByPath.get(deletedPath);
22554
22805
  entries.push({
22555
22806
  pageId: previousPage?.id ?? `page:${slugify(deletedPath)}`,
22556
- title: previousPage?.title ?? path25.basename(deletedPath, ".md"),
22807
+ title: previousPage?.title ?? path26.basename(deletedPath, ".md"),
22557
22808
  kind: previousPage?.kind ?? "index",
22558
22809
  changeType: "delete",
22559
22810
  status: "pending",
@@ -22566,16 +22817,16 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
22566
22817
  }
22567
22818
  async function stageApprovalBundle(paths, changedFiles, deletedPaths, previousGraph, graph) {
22568
22819
  const approvalId = `compile-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
22569
- const approvalDir = path25.join(paths.approvalsDir, approvalId);
22820
+ const approvalDir = path26.join(paths.approvalsDir, approvalId);
22570
22821
  await ensureDir(approvalDir);
22571
- await ensureDir(path25.join(approvalDir, "wiki"));
22572
- await ensureDir(path25.join(approvalDir, "state"));
22822
+ await ensureDir(path26.join(approvalDir, "wiki"));
22823
+ await ensureDir(path26.join(approvalDir, "state"));
22573
22824
  for (const file of changedFiles) {
22574
- const targetPath = path25.join(approvalDir, "wiki", file.relativePath);
22575
- await ensureDir(path25.dirname(targetPath));
22576
- await fs21.writeFile(targetPath, file.content, "utf8");
22825
+ const targetPath = path26.join(approvalDir, "wiki", file.relativePath);
22826
+ await ensureDir(path26.dirname(targetPath));
22827
+ await fs22.writeFile(targetPath, file.content, "utf8");
22577
22828
  }
22578
- await fs21.writeFile(path25.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
22829
+ await fs22.writeFile(path26.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
22579
22830
  await writeApprovalManifest(paths, {
22580
22831
  approvalId,
22581
22832
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -22641,7 +22892,7 @@ async function syncVaultArtifacts(rootDir, input) {
22641
22892
  confidence: 1
22642
22893
  });
22643
22894
  const sourceRecord = await buildManagedGraphPage(
22644
- path25.join(paths.wikiDir, preview.path),
22895
+ path26.join(paths.wikiDir, preview.path),
22645
22896
  {
22646
22897
  managedBy: "system",
22647
22898
  confidence: 1,
@@ -22688,7 +22939,7 @@ async function syncVaultArtifacts(rootDir, input) {
22688
22939
  );
22689
22940
  records.push(
22690
22941
  await buildManagedGraphPage(
22691
- path25.join(paths.wikiDir, modulePreview.path),
22942
+ path26.join(paths.wikiDir, modulePreview.path),
22692
22943
  {
22693
22944
  managedBy: "system",
22694
22945
  confidence: 1,
@@ -22722,8 +22973,8 @@ async function syncVaultArtifacts(rootDir, input) {
22722
22973
  const relativePath = promoted ? activeAggregatePath(itemKind, slug) : candidatePagePathFor(itemKind, slug);
22723
22974
  const aggregateSourceClass2 = aggregateManifestSourceClass(input.manifests, sourceIds);
22724
22975
  const fallbackPaths = [
22725
- path25.join(paths.wikiDir, activeAggregatePath(itemKind, slug)),
22726
- path25.join(paths.wikiDir, candidatePagePathFor(itemKind, slug))
22976
+ path26.join(paths.wikiDir, activeAggregatePath(itemKind, slug)),
22977
+ path26.join(paths.wikiDir, candidatePagePathFor(itemKind, slug))
22727
22978
  ];
22728
22979
  const confidence = nodeConfidence(aggregate.sourceAnalyses.length);
22729
22980
  const preview = emptyGraphPage({
@@ -22741,7 +22992,7 @@ async function syncVaultArtifacts(rootDir, input) {
22741
22992
  status: promoted ? "active" : "candidate"
22742
22993
  });
22743
22994
  const pageRecord = await buildManagedGraphPage(
22744
- path25.join(paths.wikiDir, relativePath),
22995
+ path26.join(paths.wikiDir, relativePath),
22745
22996
  {
22746
22997
  status: promoted ? "active" : "candidate",
22747
22998
  managedBy: "system",
@@ -22878,7 +23129,7 @@ async function syncVaultArtifacts(rootDir, input) {
22878
23129
  confidence: 1
22879
23130
  }),
22880
23131
  content: await buildManagedContent(
22881
- path25.join(paths.wikiDir, "projects", "index.md"),
23132
+ path26.join(paths.wikiDir, "projects", "index.md"),
22882
23133
  {
22883
23134
  managedBy: "system",
22884
23135
  compiledFrom: indexCompiledFrom(projectIndexRefs)
@@ -22902,7 +23153,7 @@ async function syncVaultArtifacts(rootDir, input) {
22902
23153
  records.push({
22903
23154
  page: projectIndexRef,
22904
23155
  content: await buildManagedContent(
22905
- path25.join(paths.wikiDir, projectIndexRef.path),
23156
+ path26.join(paths.wikiDir, projectIndexRef.path),
22906
23157
  {
22907
23158
  managedBy: "system",
22908
23159
  compiledFrom: indexCompiledFrom(Object.values(sections).flat())
@@ -22930,7 +23181,7 @@ async function syncVaultArtifacts(rootDir, input) {
22930
23181
  confidence: 1
22931
23182
  }),
22932
23183
  content: await buildManagedContent(
22933
- path25.join(paths.wikiDir, "index.md"),
23184
+ path26.join(paths.wikiDir, "index.md"),
22934
23185
  {
22935
23186
  managedBy: "system",
22936
23187
  compiledFrom: indexCompiledFrom(allPages)
@@ -22966,7 +23217,7 @@ async function syncVaultArtifacts(rootDir, input) {
22966
23217
  confidence: 1
22967
23218
  }),
22968
23219
  content: await buildManagedContent(
22969
- path25.join(paths.wikiDir, relativePath),
23220
+ path26.join(paths.wikiDir, relativePath),
22970
23221
  {
22971
23222
  managedBy: "system",
22972
23223
  compiledFrom: indexCompiledFrom(pages)
@@ -22977,12 +23228,12 @@ async function syncVaultArtifacts(rootDir, input) {
22977
23228
  }
22978
23229
  const nextPagePaths = new Set(records.map((record) => record.page.path));
22979
23230
  const obsoleteGraphPaths = (previousGraph?.pages ?? []).filter((page) => page.kind !== "output" && page.kind !== "insight").map((page) => page.path).filter((relativePath) => !nextPagePaths.has(relativePath));
22980
- const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path25.relative(paths.wikiDir, absolutePath))).filter((relativePath) => !nextPagePaths.has(relativePath));
23231
+ const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path26.relative(paths.wikiDir, absolutePath))).filter((relativePath) => !nextPagePaths.has(relativePath));
22981
23232
  const obsoletePaths = uniqueStrings4([...obsoleteGraphPaths, ...existingProjectIndexPaths]);
22982
23233
  const changedFiles = [];
22983
23234
  for (const record of records) {
22984
- const absolutePath = path25.join(paths.wikiDir, record.page.path);
22985
- const current = await fileExists(absolutePath) ? await fs21.readFile(absolutePath, "utf8") : null;
23235
+ const absolutePath = path26.join(paths.wikiDir, record.page.path);
23236
+ const current = await fileExists(absolutePath) ? await fs22.readFile(absolutePath, "utf8") : null;
22986
23237
  if (current !== record.content) {
22987
23238
  changedPages.push(record.page.path);
22988
23239
  changedFiles.push({ relativePath: record.page.path, content: record.content });
@@ -23007,10 +23258,10 @@ async function syncVaultArtifacts(rootDir, input) {
23007
23258
  await writePage(paths.wikiDir, record.page.path, record.content, writeChanges);
23008
23259
  }
23009
23260
  for (const relativePath of obsoletePaths) {
23010
- await fs21.rm(path25.join(paths.wikiDir, relativePath), { force: true });
23261
+ await fs22.rm(path26.join(paths.wikiDir, relativePath), { force: true });
23011
23262
  }
23012
23263
  await writeJsonFile(paths.graphPath, graph);
23013
- await writeJsonFile(path25.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
23264
+ await writeJsonFile(path26.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
23014
23265
  await writeJsonFile(paths.codeIndexPath, input.codeIndex);
23015
23266
  await writeJsonFile(paths.compileStatePath, {
23016
23267
  generatedAt: graph.generatedAt,
@@ -23108,18 +23359,18 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23108
23359
  })
23109
23360
  );
23110
23361
  await Promise.all([
23111
- ensureDir(path25.join(paths.wikiDir, "sources")),
23112
- ensureDir(path25.join(paths.wikiDir, "code")),
23113
- ensureDir(path25.join(paths.wikiDir, "concepts")),
23114
- ensureDir(path25.join(paths.wikiDir, "entities")),
23115
- ensureDir(path25.join(paths.wikiDir, "outputs")),
23116
- ensureDir(path25.join(paths.wikiDir, "dashboards")),
23117
- ensureDir(path25.join(paths.wikiDir, "graph")),
23118
- ensureDir(path25.join(paths.wikiDir, "graph", "communities")),
23119
- ensureDir(path25.join(paths.wikiDir, "projects")),
23120
- ensureDir(path25.join(paths.wikiDir, "candidates"))
23362
+ ensureDir(path26.join(paths.wikiDir, "sources")),
23363
+ ensureDir(path26.join(paths.wikiDir, "code")),
23364
+ ensureDir(path26.join(paths.wikiDir, "concepts")),
23365
+ ensureDir(path26.join(paths.wikiDir, "entities")),
23366
+ ensureDir(path26.join(paths.wikiDir, "outputs")),
23367
+ ensureDir(path26.join(paths.wikiDir, "dashboards")),
23368
+ ensureDir(path26.join(paths.wikiDir, "graph")),
23369
+ ensureDir(path26.join(paths.wikiDir, "graph", "communities")),
23370
+ ensureDir(path26.join(paths.wikiDir, "projects")),
23371
+ ensureDir(path26.join(paths.wikiDir, "candidates"))
23121
23372
  ]);
23122
- const projectsIndexPath = path25.join(paths.wikiDir, "projects", "index.md");
23373
+ const projectsIndexPath = path26.join(paths.wikiDir, "projects", "index.md");
23123
23374
  await writeFileIfChanged(
23124
23375
  projectsIndexPath,
23125
23376
  await buildManagedContent(
@@ -23140,7 +23391,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23140
23391
  outputs: pages.filter((page) => page.kind === "output" && page.projectIds.includes(project.id)),
23141
23392
  candidates: pages.filter((page) => page.status === "candidate" && page.projectIds.includes(project.id))
23142
23393
  };
23143
- const absolutePath = path25.join(paths.wikiDir, "projects", project.id, "index.md");
23394
+ const absolutePath = path26.join(paths.wikiDir, "projects", project.id, "index.md");
23144
23395
  await writeFileIfChanged(
23145
23396
  absolutePath,
23146
23397
  await buildManagedContent(
@@ -23158,7 +23409,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23158
23409
  )
23159
23410
  );
23160
23411
  }
23161
- const rootIndexPath = path25.join(paths.wikiDir, "index.md");
23412
+ const rootIndexPath = path26.join(paths.wikiDir, "index.md");
23162
23413
  await writeFileIfChanged(
23163
23414
  rootIndexPath,
23164
23415
  await buildManagedContent(
@@ -23184,7 +23435,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23184
23435
  ["candidates/index.md", "candidates", pagesWithGraph.filter((page) => page.status === "candidate")],
23185
23436
  ["graph/index.md", "graph", pagesWithGraph.filter((page) => page.kind === "graph_report" || page.kind === "community_summary")]
23186
23437
  ]) {
23187
- const absolutePath = path25.join(paths.wikiDir, relativePath);
23438
+ const absolutePath = path26.join(paths.wikiDir, relativePath);
23188
23439
  await writeFileIfChanged(
23189
23440
  absolutePath,
23190
23441
  await buildManagedContent(
@@ -23198,31 +23449,31 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23198
23449
  );
23199
23450
  }
23200
23451
  for (const record of graphOrientation.records) {
23201
- await writeFileIfChanged(path25.join(paths.wikiDir, record.page.path), record.content);
23452
+ await writeFileIfChanged(path26.join(paths.wikiDir, record.page.path), record.content);
23202
23453
  }
23203
23454
  for (const record of dashboardRecords) {
23204
- await writeFileIfChanged(path25.join(paths.wikiDir, record.page.path), record.content);
23455
+ await writeFileIfChanged(path26.join(paths.wikiDir, record.page.path), record.content);
23205
23456
  }
23206
23457
  if (graphOrientation.report) {
23207
- await writeJsonFile(path25.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
23458
+ await writeJsonFile(path26.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
23208
23459
  }
23209
- const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path25.relative(paths.wikiDir, absolutePath)));
23460
+ const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path26.relative(paths.wikiDir, absolutePath)));
23210
23461
  const allowedProjectIndexPaths = /* @__PURE__ */ new Set([
23211
23462
  "projects/index.md",
23212
23463
  ...configuredProjects.map((project) => `projects/${project.id}/index.md`)
23213
23464
  ]);
23214
23465
  await Promise.all(
23215
- existingProjectIndexPaths.filter((relativePath) => !allowedProjectIndexPaths.has(relativePath)).map((relativePath) => fs21.rm(path25.join(paths.wikiDir, relativePath), { force: true }))
23466
+ existingProjectIndexPaths.filter((relativePath) => !allowedProjectIndexPaths.has(relativePath)).map((relativePath) => fs22.rm(path26.join(paths.wikiDir, relativePath), { force: true }))
23216
23467
  );
23217
- const existingGraphPages = (await listFilesRecursive(path25.join(paths.wikiDir, "graph").replace(/\/$/, "")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path25.relative(paths.wikiDir, absolutePath)));
23468
+ const existingGraphPages = (await listFilesRecursive(path26.join(paths.wikiDir, "graph").replace(/\/$/, "")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path26.relative(paths.wikiDir, absolutePath)));
23218
23469
  const allowedGraphPages = /* @__PURE__ */ new Set(["graph/index.md", ...graphOrientation.records.map((record) => record.page.path)]);
23219
23470
  await Promise.all(
23220
- existingGraphPages.filter((relativePath) => !allowedGraphPages.has(relativePath)).map((relativePath) => fs21.rm(path25.join(paths.wikiDir, relativePath), { force: true }))
23471
+ existingGraphPages.filter((relativePath) => !allowedGraphPages.has(relativePath)).map((relativePath) => fs22.rm(path26.join(paths.wikiDir, relativePath), { force: true }))
23221
23472
  );
23222
- const existingDashboardPages = (await listFilesRecursive(path25.join(paths.wikiDir, "dashboards")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path25.relative(paths.wikiDir, absolutePath)));
23473
+ const existingDashboardPages = (await listFilesRecursive(path26.join(paths.wikiDir, "dashboards")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path26.relative(paths.wikiDir, absolutePath)));
23223
23474
  const allowedDashboardPages = /* @__PURE__ */ new Set(["dashboards/index.md", ...dashboardRecords.map((record) => record.page.path)]);
23224
23475
  await Promise.all(
23225
- existingDashboardPages.filter((relativePath) => !allowedDashboardPages.has(relativePath)).map((relativePath) => fs21.rm(path25.join(paths.wikiDir, relativePath), { force: true }))
23476
+ existingDashboardPages.filter((relativePath) => !allowedDashboardPages.has(relativePath)).map((relativePath) => fs22.rm(path26.join(paths.wikiDir, relativePath), { force: true }))
23226
23477
  );
23227
23478
  await rebuildSearchIndex(paths.searchDbPath, pagesWithGraph, paths.wikiDir);
23228
23479
  }
@@ -23242,7 +23493,7 @@ async function prepareOutputPageSave(rootDir, input) {
23242
23493
  confidence: 0.74
23243
23494
  }
23244
23495
  });
23245
- const absolutePath = path25.join(paths.wikiDir, output.page.path);
23496
+ const absolutePath = path26.join(paths.wikiDir, output.page.path);
23246
23497
  return {
23247
23498
  page: output.page,
23248
23499
  savedPath: absolutePath,
@@ -23254,15 +23505,15 @@ async function prepareOutputPageSave(rootDir, input) {
23254
23505
  async function persistOutputPage(rootDir, input) {
23255
23506
  const { paths } = await loadVaultConfig(rootDir);
23256
23507
  const prepared = await prepareOutputPageSave(rootDir, input);
23257
- await ensureDir(path25.dirname(prepared.savedPath));
23258
- await fs21.writeFile(prepared.savedPath, prepared.content, "utf8");
23508
+ await ensureDir(path26.dirname(prepared.savedPath));
23509
+ await fs22.writeFile(prepared.savedPath, prepared.content, "utf8");
23259
23510
  for (const assetFile of prepared.assetFiles) {
23260
- const assetPath = path25.join(paths.wikiDir, assetFile.relativePath);
23261
- await ensureDir(path25.dirname(assetPath));
23511
+ const assetPath = path26.join(paths.wikiDir, assetFile.relativePath);
23512
+ await ensureDir(path26.dirname(assetPath));
23262
23513
  if (typeof assetFile.content === "string") {
23263
- await fs21.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
23514
+ await fs22.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
23264
23515
  } else {
23265
- await fs21.writeFile(assetPath, assetFile.content);
23516
+ await fs22.writeFile(assetPath, assetFile.content);
23266
23517
  }
23267
23518
  }
23268
23519
  return { page: prepared.page, savedPath: prepared.savedPath, outputAssets: prepared.outputAssets };
@@ -23283,7 +23534,7 @@ async function prepareExploreHubSave(rootDir, input) {
23283
23534
  confidence: 0.76
23284
23535
  }
23285
23536
  });
23286
- const absolutePath = path25.join(paths.wikiDir, hub.page.path);
23537
+ const absolutePath = path26.join(paths.wikiDir, hub.page.path);
23287
23538
  return {
23288
23539
  page: hub.page,
23289
23540
  savedPath: absolutePath,
@@ -23295,15 +23546,15 @@ async function prepareExploreHubSave(rootDir, input) {
23295
23546
  async function persistExploreHub(rootDir, input) {
23296
23547
  const { paths } = await loadVaultConfig(rootDir);
23297
23548
  const prepared = await prepareExploreHubSave(rootDir, input);
23298
- await ensureDir(path25.dirname(prepared.savedPath));
23299
- await fs21.writeFile(prepared.savedPath, prepared.content, "utf8");
23549
+ await ensureDir(path26.dirname(prepared.savedPath));
23550
+ await fs22.writeFile(prepared.savedPath, prepared.content, "utf8");
23300
23551
  for (const assetFile of prepared.assetFiles) {
23301
- const assetPath = path25.join(paths.wikiDir, assetFile.relativePath);
23302
- await ensureDir(path25.dirname(assetPath));
23552
+ const assetPath = path26.join(paths.wikiDir, assetFile.relativePath);
23553
+ await ensureDir(path26.dirname(assetPath));
23303
23554
  if (typeof assetFile.content === "string") {
23304
- await fs21.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
23555
+ await fs22.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
23305
23556
  } else {
23306
- await fs21.writeFile(assetPath, assetFile.content);
23557
+ await fs22.writeFile(assetPath, assetFile.content);
23307
23558
  }
23308
23559
  }
23309
23560
  return { page: prepared.page, savedPath: prepared.savedPath, outputAssets: prepared.outputAssets };
@@ -23321,17 +23572,17 @@ async function stageOutputApprovalBundle(rootDir, stagedPages, options = {}) {
23321
23572
  ]);
23322
23573
  const labelsByPath = new Map(stagedPages.filter((item) => item.label).map((item) => [item.page.path, item.label]));
23323
23574
  const approvalId = `schedule-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
23324
- const approvalDir = path25.join(paths.approvalsDir, approvalId);
23575
+ const approvalDir = path26.join(paths.approvalsDir, approvalId);
23325
23576
  await ensureDir(approvalDir);
23326
- await ensureDir(path25.join(approvalDir, "wiki"));
23327
- await ensureDir(path25.join(approvalDir, "state"));
23577
+ await ensureDir(path26.join(approvalDir, "wiki"));
23578
+ await ensureDir(path26.join(approvalDir, "state"));
23328
23579
  for (const file of changedFiles) {
23329
- const targetPath = path25.join(approvalDir, "wiki", file.relativePath);
23330
- await ensureDir(path25.dirname(targetPath));
23580
+ const targetPath = path26.join(approvalDir, "wiki", file.relativePath);
23581
+ await ensureDir(path26.dirname(targetPath));
23331
23582
  if ("binary" in file && file.binary) {
23332
- await fs21.writeFile(targetPath, Buffer.from(file.content, "base64"));
23583
+ await fs22.writeFile(targetPath, Buffer.from(file.content, "base64"));
23333
23584
  } else {
23334
- await fs21.writeFile(targetPath, file.content, "utf8");
23585
+ await fs22.writeFile(targetPath, file.content, "utf8");
23335
23586
  }
23336
23587
  }
23337
23588
  const nextPages = sortGraphPages([
@@ -23346,7 +23597,7 @@ async function stageOutputApprovalBundle(rootDir, stagedPages, options = {}) {
23346
23597
  sources: previousGraph?.sources ?? [],
23347
23598
  pages: nextPages
23348
23599
  };
23349
- await fs21.writeFile(path25.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
23600
+ await fs22.writeFile(path26.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
23350
23601
  await writeApprovalManifest(paths, {
23351
23602
  approvalId,
23352
23603
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -23396,10 +23647,10 @@ async function executeQuery(rootDir, question, format, options = {}) {
23396
23647
  const searchResults = searchPages(paths.searchDbPath, question, 5);
23397
23648
  const excerpts = await Promise.all(
23398
23649
  searchResults.map(async (result) => {
23399
- const absolutePath = path25.join(paths.wikiDir, result.path);
23650
+ const absolutePath = path26.join(paths.wikiDir, result.path);
23400
23651
  try {
23401
- const content = await fs21.readFile(absolutePath, "utf8");
23402
- const parsed = matter12(content);
23652
+ const content = await fs22.readFile(absolutePath, "utf8");
23653
+ const parsed = matter13(content);
23403
23654
  return `# ${result.title}
23404
23655
  ${truncate(normalizeWhitespace(parsed.content), 1200)}`;
23405
23656
  } catch {
@@ -23672,12 +23923,12 @@ function computeStructuredDiff(current, staged, isBinaryAsset) {
23672
23923
  let currentBody = current ?? "";
23673
23924
  let stagedBody = staged ?? "";
23674
23925
  if (current) {
23675
- const parsed = matter12(current);
23926
+ const parsed = matter13(current);
23676
23927
  currentData = parsed.data ?? {};
23677
23928
  currentBody = parsed.content;
23678
23929
  }
23679
23930
  if (staged) {
23680
- const parsed = matter12(staged);
23931
+ const parsed = matter13(staged);
23681
23932
  stagedData = parsed.data ?? {};
23682
23933
  stagedBody = parsed.content;
23683
23934
  }
@@ -23705,8 +23956,8 @@ function computeChangeSummary(current, staged, changeType) {
23705
23956
  if (changeType === "delete") return "Removed page";
23706
23957
  if (changeType === "promote") return "Promoted from candidate";
23707
23958
  if (!current || !staged) return "Updated page";
23708
- const currentParsed = matter12(current);
23709
- const stagedParsed = matter12(staged);
23959
+ const currentParsed = matter13(current);
23960
+ const stagedParsed = matter13(staged);
23710
23961
  const changes = [];
23711
23962
  const currentTags = currentParsed.data.tags ?? [];
23712
23963
  const stagedTags = stagedParsed.data.tags ?? [];
@@ -23726,7 +23977,7 @@ function computeChangeSummary(current, staged, changeType) {
23726
23977
  async function listApprovals(rootDir) {
23727
23978
  const { paths } = await loadVaultConfig(rootDir);
23728
23979
  const manifests = await Promise.all(
23729
- (await fs21.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => {
23980
+ (await fs22.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => {
23730
23981
  try {
23731
23982
  return await readApprovalManifest(paths, entry.name);
23732
23983
  } catch {
@@ -23742,8 +23993,8 @@ async function readApproval(rootDir, approvalId, options) {
23742
23993
  const details = await Promise.all(
23743
23994
  manifest.entries.map(async (entry) => {
23744
23995
  const currentPath = entry.previousPath ?? entry.nextPath;
23745
- const currentContent = currentPath ? await fs21.readFile(path25.join(paths.wikiDir, currentPath), "utf8").catch(() => void 0) : void 0;
23746
- const stagedContent = entry.nextPath ? await fs21.readFile(path25.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath), "utf8").catch(() => void 0) : void 0;
23996
+ const currentContent = currentPath ? await fs22.readFile(path26.join(paths.wikiDir, currentPath), "utf8").catch(() => void 0) : void 0;
23997
+ const stagedContent = entry.nextPath ? await fs22.readFile(path26.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath), "utf8").catch(() => void 0) : void 0;
23747
23998
  const detail = {
23748
23999
  ...entry,
23749
24000
  currentContent,
@@ -23785,26 +24036,26 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
23785
24036
  if (!entry.nextPath) {
23786
24037
  throw new Error(`Approval entry ${entry.pageId} is missing a staged path.`);
23787
24038
  }
23788
- const stagedAbsolutePath = path25.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath);
23789
- const stagedContent = await fs21.readFile(stagedAbsolutePath, "utf8");
23790
- const targetAbsolutePath = path25.join(paths.wikiDir, entry.nextPath);
23791
- await ensureDir(path25.dirname(targetAbsolutePath));
23792
- await fs21.writeFile(targetAbsolutePath, stagedContent, "utf8");
24039
+ const stagedAbsolutePath = path26.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath);
24040
+ const stagedContent = await fs22.readFile(stagedAbsolutePath, "utf8");
24041
+ const targetAbsolutePath = path26.join(paths.wikiDir, entry.nextPath);
24042
+ await ensureDir(path26.dirname(targetAbsolutePath));
24043
+ await fs22.writeFile(targetAbsolutePath, stagedContent, "utf8");
23793
24044
  if (entry.changeType === "promote" && entry.previousPath) {
23794
- await fs21.rm(path25.join(paths.wikiDir, entry.previousPath), { force: true });
24045
+ await fs22.rm(path26.join(paths.wikiDir, entry.previousPath), { force: true });
23795
24046
  }
23796
24047
  const nextPage = bundleGraph?.pages.find((page) => page.id === entry.pageId && page.path === entry.nextPath) ?? parseStoredPage(entry.nextPath, stagedContent);
23797
24048
  if (nextPage.kind === "output" && nextPage.outputAssets?.length) {
23798
- const outputAssetDir = path25.join(paths.wikiDir, "outputs", "assets", path25.basename(nextPage.path, ".md"));
23799
- await fs21.rm(outputAssetDir, { recursive: true, force: true });
24049
+ const outputAssetDir = path26.join(paths.wikiDir, "outputs", "assets", path26.basename(nextPage.path, ".md"));
24050
+ await fs22.rm(outputAssetDir, { recursive: true, force: true });
23800
24051
  for (const asset of nextPage.outputAssets) {
23801
- const stagedAssetPath = path25.join(paths.approvalsDir, approvalId, "wiki", asset.path);
24052
+ const stagedAssetPath = path26.join(paths.approvalsDir, approvalId, "wiki", asset.path);
23802
24053
  if (!await fileExists(stagedAssetPath)) {
23803
24054
  continue;
23804
24055
  }
23805
- const targetAssetPath = path25.join(paths.wikiDir, asset.path);
23806
- await ensureDir(path25.dirname(targetAssetPath));
23807
- await fs21.copyFile(stagedAssetPath, targetAssetPath);
24056
+ const targetAssetPath = path26.join(paths.wikiDir, asset.path);
24057
+ await ensureDir(path26.dirname(targetAssetPath));
24058
+ await fs22.copyFile(stagedAssetPath, targetAssetPath);
23808
24059
  }
23809
24060
  }
23810
24061
  nextPages = nextPages.filter(
@@ -23815,10 +24066,10 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
23815
24066
  } else {
23816
24067
  const deletedPage = nextPages.find((page) => page.id === entry.pageId || page.path === entry.previousPath) ?? bundleGraph?.pages.find((page) => page.id === entry.pageId || page.path === entry.previousPath) ?? null;
23817
24068
  if (entry.previousPath) {
23818
- await fs21.rm(path25.join(paths.wikiDir, entry.previousPath), { force: true });
24069
+ await fs22.rm(path26.join(paths.wikiDir, entry.previousPath), { force: true });
23819
24070
  }
23820
24071
  if (deletedPage?.kind === "output") {
23821
- await fs21.rm(path25.join(paths.wikiDir, "outputs", "assets", path25.basename(deletedPage.path, ".md")), {
24072
+ await fs22.rm(path26.join(paths.wikiDir, "outputs", "assets", path26.basename(deletedPage.path, ".md")), {
23822
24073
  recursive: true,
23823
24074
  force: true
23824
24075
  });
@@ -23949,10 +24200,10 @@ async function promoteCandidate(rootDir, target) {
23949
24200
  const { paths } = await loadVaultConfig(rootDir);
23950
24201
  const graph = await readJsonFile(paths.graphPath);
23951
24202
  const candidate = resolveCandidateTarget(graph?.pages ?? [], target);
23952
- const raw = await fs21.readFile(path25.join(paths.wikiDir, candidate.path), "utf8");
23953
- const parsed = matter12(raw);
24203
+ const raw = await fs22.readFile(path26.join(paths.wikiDir, candidate.path), "utf8");
24204
+ const parsed = matter13(raw);
23954
24205
  const nextUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
23955
- const nextContent = matter12.stringify(parsed.content, {
24206
+ const nextContent = matter13.stringify(parsed.content, {
23956
24207
  ...parsed.data,
23957
24208
  status: "active",
23958
24209
  updated_at: nextUpdatedAt,
@@ -23961,10 +24212,10 @@ async function promoteCandidate(rootDir, target) {
23961
24212
  )
23962
24213
  });
23963
24214
  const nextPath = candidateActivePath(candidate);
23964
- const nextAbsolutePath = path25.join(paths.wikiDir, nextPath);
23965
- await ensureDir(path25.dirname(nextAbsolutePath));
23966
- await fs21.writeFile(nextAbsolutePath, nextContent, "utf8");
23967
- await fs21.rm(path25.join(paths.wikiDir, candidate.path), { force: true });
24215
+ const nextAbsolutePath = path26.join(paths.wikiDir, nextPath);
24216
+ await ensureDir(path26.dirname(nextAbsolutePath));
24217
+ await fs22.writeFile(nextAbsolutePath, nextContent, "utf8");
24218
+ await fs22.rm(path26.join(paths.wikiDir, candidate.path), { force: true });
23968
24219
  const nextPage = parseStoredPage(nextPath, nextContent, { createdAt: candidate.createdAt, updatedAt: nextUpdatedAt });
23969
24220
  const nextPages = sortGraphPages(
23970
24221
  (graph?.pages ?? []).filter((page) => page.id !== candidate.id && page.path !== candidate.path).concat(nextPage)
@@ -24105,10 +24356,10 @@ async function createSupersessionEdge(rootDir, oldPageIdOrPath, newPageIdOrPath)
24105
24356
  }
24106
24357
  const now = /* @__PURE__ */ new Date();
24107
24358
  const nextOldPage = markSuperseded(oldPage, newPage.id, now);
24108
- const oldAbsolutePath = path25.join(paths.wikiDir, oldPage.path);
24359
+ const oldAbsolutePath = path26.join(paths.wikiDir, oldPage.path);
24109
24360
  if (await fileExists(oldAbsolutePath)) {
24110
- const current = await fs21.readFile(oldAbsolutePath, "utf8");
24111
- const parsed = matter12(current);
24361
+ const current = await fs22.readFile(oldAbsolutePath, "utf8");
24362
+ const parsed = matter13(current);
24112
24363
  const nextData = {
24113
24364
  ...parsed.data,
24114
24365
  freshness: "stale",
@@ -24116,7 +24367,7 @@ async function createSupersessionEdge(rootDir, oldPageIdOrPath, newPageIdOrPath)
24116
24367
  superseded_by: newPage.id,
24117
24368
  updated_at: nextOldPage.updatedAt
24118
24369
  };
24119
- await fs21.writeFile(oldAbsolutePath, matter12.stringify(parsed.content, nextData), "utf8");
24370
+ await fs22.writeFile(oldAbsolutePath, matter13.stringify(parsed.content, nextData), "utf8");
24120
24371
  }
24121
24372
  const resolveNodeId = (pageId) => {
24122
24373
  const node = graph.nodes.find((item) => item.pageId === pageId);
@@ -24167,7 +24418,7 @@ async function archiveCandidate(rootDir, target) {
24167
24418
  const { paths } = await loadVaultConfig(rootDir);
24168
24419
  const graph = await readJsonFile(paths.graphPath);
24169
24420
  const candidate = resolveCandidateTarget(graph?.pages ?? [], target);
24170
- await fs21.rm(path25.join(paths.wikiDir, candidate.path), { force: true });
24421
+ await fs22.rm(path26.join(paths.wikiDir, candidate.path), { force: true });
24171
24422
  const nextPages = sortGraphPages((graph?.pages ?? []).filter((page) => page.id !== candidate.id && page.path !== candidate.path));
24172
24423
  const nextGraph = {
24173
24424
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -24206,18 +24457,18 @@ async function archiveCandidate(rootDir, target) {
24206
24457
  }
24207
24458
  async function ensureObsidianWorkspace(rootDir) {
24208
24459
  const { config } = await loadVaultConfig(rootDir);
24209
- const obsidianDir = path25.join(rootDir, ".obsidian");
24460
+ const obsidianDir = path26.join(rootDir, ".obsidian");
24210
24461
  const projectIds = projectEntries(config).map((project) => project.id);
24211
24462
  await ensureDir(obsidianDir);
24212
24463
  await Promise.all([
24213
- writeJsonFile(path25.join(obsidianDir, "app.json"), {
24464
+ writeJsonFile(path26.join(obsidianDir, "app.json"), {
24214
24465
  alwaysUpdateLinks: true,
24215
24466
  newFileLocation: "folder",
24216
24467
  newFileFolderPath: "wiki/insights",
24217
24468
  useMarkdownLinks: false,
24218
24469
  attachmentFolderPath: "raw/assets"
24219
24470
  }),
24220
- writeJsonFile(path25.join(obsidianDir, "core-plugins.json"), [
24471
+ writeJsonFile(path26.join(obsidianDir, "core-plugins.json"), [
24221
24472
  "file-explorer",
24222
24473
  "global-search",
24223
24474
  "switcher",
@@ -24227,7 +24478,7 @@ async function ensureObsidianWorkspace(rootDir) {
24227
24478
  "tag-pane",
24228
24479
  "page-preview"
24229
24480
  ]),
24230
- writeJsonFile(path25.join(obsidianDir, "graph.json"), {
24481
+ writeJsonFile(path26.join(obsidianDir, "graph.json"), {
24231
24482
  "collapse-filter": false,
24232
24483
  search: "",
24233
24484
  showTags: true,
@@ -24247,7 +24498,7 @@ async function ensureObsidianWorkspace(rootDir) {
24247
24498
  ],
24248
24499
  localJumps: false
24249
24500
  }),
24250
- writeJsonFile(path25.join(obsidianDir, "types.json"), {
24501
+ writeJsonFile(path26.join(obsidianDir, "types.json"), {
24251
24502
  types: {
24252
24503
  page_id: "text",
24253
24504
  kind: "text",
@@ -24268,7 +24519,7 @@ async function ensureObsidianWorkspace(rootDir) {
24268
24519
  cssclasses: "multitext"
24269
24520
  }
24270
24521
  }),
24271
- writeJsonFile(path25.join(obsidianDir, "workspace.json"), {
24522
+ writeJsonFile(path26.join(obsidianDir, "workspace.json"), {
24272
24523
  active: "root",
24273
24524
  lastOpenFiles: ["wiki/index.md", "wiki/projects/index.md", "wiki/candidates/index.md", "wiki/insights/index.md"],
24274
24525
  left: {
@@ -24281,20 +24532,20 @@ async function ensureObsidianWorkspace(rootDir) {
24281
24532
  ]);
24282
24533
  }
24283
24534
  async function initLiteVault(rootDir, options) {
24284
- const rawDir = path25.join(rootDir, "raw");
24285
- const wikiDir = path25.join(rootDir, "wiki");
24286
- const schemaPath = path25.join(rootDir, PRIMARY_SCHEMA_FILENAME);
24287
- const indexPath = path25.join(wikiDir, "index.md");
24288
- const logPath = path25.join(wikiDir, "log.md");
24535
+ const rawDir = path26.join(rootDir, "raw");
24536
+ const wikiDir = path26.join(rootDir, "wiki");
24537
+ const schemaPath = path26.join(rootDir, PRIMARY_SCHEMA_FILENAME);
24538
+ const indexPath = path26.join(wikiDir, "index.md");
24539
+ const logPath = path26.join(wikiDir, "log.md");
24289
24540
  await Promise.all([ensureDir(rawDir), ensureDir(wikiDir)]);
24290
24541
  if (!await fileExists(schemaPath)) {
24291
- await fs21.writeFile(schemaPath, defaultVaultSchema("default"), "utf8");
24542
+ await fs22.writeFile(schemaPath, defaultVaultSchema("default"), "utf8");
24292
24543
  }
24293
24544
  const now = (/* @__PURE__ */ new Date()).toISOString();
24294
24545
  if (!await fileExists(indexPath)) {
24295
- await fs21.writeFile(
24546
+ await fs22.writeFile(
24296
24547
  indexPath,
24297
- matter12.stringify(
24548
+ matter13.stringify(
24298
24549
  [
24299
24550
  "# Wiki Index",
24300
24551
  "",
@@ -24330,9 +24581,9 @@ async function initLiteVault(rootDir, options) {
24330
24581
  );
24331
24582
  }
24332
24583
  if (!await fileExists(logPath)) {
24333
- await fs21.writeFile(
24584
+ await fs22.writeFile(
24334
24585
  logPath,
24335
- matter12.stringify(
24586
+ matter13.stringify(
24336
24587
  [
24337
24588
  "# Activity Log",
24338
24589
  "",
@@ -24366,7 +24617,7 @@ async function initLiteVault(rootDir, options) {
24366
24617
  );
24367
24618
  }
24368
24619
  if (options.obsidian) {
24369
- const obsidianDir = path25.join(rootDir, ".obsidian");
24620
+ const obsidianDir = path26.join(rootDir, ".obsidian");
24370
24621
  await ensureDir(obsidianDir);
24371
24622
  }
24372
24623
  }
@@ -24380,11 +24631,11 @@ async function initVault(rootDir, options = {}) {
24380
24631
  const profile = config.profile;
24381
24632
  const isResearchProfile = profile.presets.length > 0 || profile.guidedSessionMode === "canonical_review" || profile.dataviewBlocks;
24382
24633
  await installConfiguredAgents(rootDir);
24383
- const insightsIndexPath = path25.join(paths.wikiDir, "insights", "index.md");
24634
+ const insightsIndexPath = path26.join(paths.wikiDir, "insights", "index.md");
24384
24635
  const now = (/* @__PURE__ */ new Date()).toISOString();
24385
24636
  await writeFileIfChanged(
24386
24637
  insightsIndexPath,
24387
- matter12.stringify(
24638
+ matter13.stringify(
24388
24639
  (isResearchProfile ? [
24389
24640
  "# Insights",
24390
24641
  "",
@@ -24430,8 +24681,8 @@ async function initVault(rootDir, options = {}) {
24430
24681
  )
24431
24682
  );
24432
24683
  await writeFileIfChanged(
24433
- path25.join(paths.wikiDir, "projects", "index.md"),
24434
- matter12.stringify(["# Projects", "", "- Run `swarmvault compile` to build project rollups.", ""].join("\n"), {
24684
+ path26.join(paths.wikiDir, "projects", "index.md"),
24685
+ matter13.stringify(["# Projects", "", "- Run `swarmvault compile` to build project rollups.", ""].join("\n"), {
24435
24686
  page_id: "projects:index",
24436
24687
  kind: "index",
24437
24688
  title: "Projects",
@@ -24453,8 +24704,8 @@ async function initVault(rootDir, options = {}) {
24453
24704
  })
24454
24705
  );
24455
24706
  await writeFileIfChanged(
24456
- path25.join(paths.wikiDir, "candidates", "index.md"),
24457
- matter12.stringify(["# Candidates", "", "- Run `swarmvault compile` to stage candidate pages.", ""].join("\n"), {
24707
+ path26.join(paths.wikiDir, "candidates", "index.md"),
24708
+ matter13.stringify(["# Candidates", "", "- Run `swarmvault compile` to stage candidate pages.", ""].join("\n"), {
24458
24709
  page_id: "candidates:index",
24459
24710
  kind: "index",
24460
24711
  title: "Candidates",
@@ -24480,8 +24731,8 @@ async function initVault(rootDir, options = {}) {
24480
24731
  }
24481
24732
  if (isResearchProfile) {
24482
24733
  await writeFileIfChanged(
24483
- path25.join(paths.wikiDir, "insights", "research-playbook.md"),
24484
- matter12.stringify(
24734
+ path26.join(paths.wikiDir, "insights", "research-playbook.md"),
24735
+ matter13.stringify(
24485
24736
  [
24486
24737
  `# ${requestedProfile === "personal-research" ? "Personal Research Playbook" : "Research Playbook"}`,
24487
24738
  "",
@@ -24639,7 +24890,7 @@ async function compileVault(rootDir, options = {}) {
24639
24890
  ),
24640
24891
  Promise.all(
24641
24892
  clean.map(async (manifest) => {
24642
- const cached = await readJsonFile(path25.join(paths.analysesDir, `${manifest.sourceId}.json`));
24893
+ const cached = await readJsonFile(path26.join(paths.analysesDir, `${manifest.sourceId}.json`));
24643
24894
  if (cached) {
24644
24895
  analysisProgress.tick(manifest.title);
24645
24896
  return cached;
@@ -24667,22 +24918,22 @@ async function compileVault(rootDir, options = {}) {
24667
24918
  }
24668
24919
  const enriched = enrichResolvedCodeImports(manifest, analysis, codeIndex);
24669
24920
  if (analysisSignature(enriched) !== analysisSignature(analysis)) {
24670
- await writeJsonFile(path25.join(paths.analysesDir, `${analysis.sourceId}.json`), enriched);
24921
+ await writeJsonFile(path26.join(paths.analysesDir, `${analysis.sourceId}.json`), enriched);
24671
24922
  }
24672
24923
  return enriched;
24673
24924
  })
24674
24925
  );
24675
24926
  await Promise.all([
24676
- ensureDir(path25.join(paths.wikiDir, "sources")),
24677
- ensureDir(path25.join(paths.wikiDir, "code")),
24678
- ensureDir(path25.join(paths.wikiDir, "concepts")),
24679
- ensureDir(path25.join(paths.wikiDir, "entities")),
24680
- ensureDir(path25.join(paths.wikiDir, "outputs")),
24681
- ensureDir(path25.join(paths.wikiDir, "projects")),
24682
- ensureDir(path25.join(paths.wikiDir, "insights")),
24683
- ensureDir(path25.join(paths.wikiDir, "candidates")),
24684
- ensureDir(path25.join(paths.wikiDir, "candidates", "concepts")),
24685
- ensureDir(path25.join(paths.wikiDir, "candidates", "entities"))
24927
+ ensureDir(path26.join(paths.wikiDir, "sources")),
24928
+ ensureDir(path26.join(paths.wikiDir, "code")),
24929
+ ensureDir(path26.join(paths.wikiDir, "concepts")),
24930
+ ensureDir(path26.join(paths.wikiDir, "entities")),
24931
+ ensureDir(path26.join(paths.wikiDir, "outputs")),
24932
+ ensureDir(path26.join(paths.wikiDir, "projects")),
24933
+ ensureDir(path26.join(paths.wikiDir, "insights")),
24934
+ ensureDir(path26.join(paths.wikiDir, "candidates")),
24935
+ ensureDir(path26.join(paths.wikiDir, "candidates", "concepts")),
24936
+ ensureDir(path26.join(paths.wikiDir, "candidates", "entities"))
24686
24937
  ]);
24687
24938
  const sync = await syncVaultArtifacts(rootDir, {
24688
24939
  schemas,
@@ -24802,10 +25053,10 @@ async function compileVault(rootDir, options = {}) {
24802
25053
  }
24803
25054
  const estimates = await Promise.all(
24804
25055
  sync.allPages.map(async (page) => {
24805
- const fullPath = path25.join(paths.wikiDir, page.path);
25056
+ const fullPath = path26.join(paths.wikiDir, page.path);
24806
25057
  let content = "";
24807
25058
  try {
24808
- content = await fs21.readFile(fullPath, "utf8");
25059
+ content = await fs22.readFile(fullPath, "utf8");
24809
25060
  } catch {
24810
25061
  }
24811
25062
  return estimatePageTokens2(page.id, page.path, page.kind, content, nodeDegreeLookup.get(page.id), page.confidence);
@@ -24813,9 +25064,9 @@ async function compileVault(rootDir, options = {}) {
24813
25064
  );
24814
25065
  const budgetResult = trimToTokenBudget2(estimates, options.maxTokens);
24815
25066
  for (const dropped of budgetResult.dropped) {
24816
- const fullPath = path25.join(paths.wikiDir, dropped.path);
25067
+ const fullPath = path26.join(paths.wikiDir, dropped.path);
24817
25068
  try {
24818
- await fs21.unlink(fullPath);
25069
+ await fs22.unlink(fullPath);
24819
25070
  } catch {
24820
25071
  }
24821
25072
  }
@@ -24910,7 +25161,7 @@ async function queryVault(rootDir, options) {
24910
25161
  assetFiles: staged.assetFiles
24911
25162
  }
24912
25163
  ]);
24913
- stagedPath = path25.join(approval.approvalDir, "wiki", staged.page.path);
25164
+ stagedPath = path26.join(approval.approvalDir, "wiki", staged.page.path);
24914
25165
  savedPageId = staged.page.id;
24915
25166
  approvalId = approval.approvalId;
24916
25167
  approvalDir = approval.approvalDir;
@@ -25169,9 +25420,9 @@ ${orchestrationNotes.join("\n")}
25169
25420
  approvalId = approval.approvalId;
25170
25421
  approvalDir = approval.approvalDir;
25171
25422
  stepResults.forEach((result, index) => {
25172
- result.stagedPath = path25.join(approval.approvalDir, "wiki", stagedStepPages[index]?.page.path ?? "");
25423
+ result.stagedPath = path26.join(approval.approvalDir, "wiki", stagedStepPages[index]?.page.path ?? "");
25173
25424
  });
25174
- stagedHubPath = path25.join(approval.approvalDir, "wiki", hubPage.path);
25425
+ stagedHubPath = path26.join(approval.approvalDir, "wiki", hubPage.path);
25175
25426
  } else {
25176
25427
  await refreshVaultAfterOutputSave(rootDir);
25177
25428
  }
@@ -25315,11 +25566,11 @@ async function benchmarkVault(rootDir, options = {}) {
25315
25566
  }
25316
25567
  }
25317
25568
  for (const page of graph.pages) {
25318
- const absolutePath = path25.join(paths.wikiDir, page.path);
25569
+ const absolutePath = path26.join(paths.wikiDir, page.path);
25319
25570
  if (!await fileExists(absolutePath)) {
25320
25571
  continue;
25321
25572
  }
25322
- const parsed = matter12(await fs21.readFile(absolutePath, "utf8"));
25573
+ const parsed = matter13(await fs22.readFile(absolutePath, "utf8"));
25323
25574
  pageContentsById.set(page.id, parsed.content);
25324
25575
  }
25325
25576
  const configuredQuestions = (config.benchmark?.questions ?? []).map((question) => normalizeWhitespace(question)).filter(Boolean);
@@ -25414,7 +25665,7 @@ async function listGraphHyperedges(rootDir, target, limit = 25) {
25414
25665
  }
25415
25666
  async function readGraphReport(rootDir) {
25416
25667
  const { paths } = await loadVaultConfig(rootDir);
25417
- return readJsonFile(path25.join(paths.wikiDir, "graph", "report.json"));
25668
+ return readJsonFile(path26.join(paths.wikiDir, "graph", "report.json"));
25418
25669
  }
25419
25670
  async function listGodNodes(rootDir, limit) {
25420
25671
  const graph = await ensureCompiledGraph(rootDir);
@@ -25440,19 +25691,19 @@ async function readPage(rootDir, relativePath) {
25440
25691
  return null;
25441
25692
  }
25442
25693
  const { paths } = await loadVaultConfig(rootDir);
25443
- const absolutePath = path25.resolve(paths.wikiDir, relativePath);
25694
+ const absolutePath = path26.resolve(paths.wikiDir, relativePath);
25444
25695
  if (!isPathWithin(paths.wikiDir, absolutePath)) {
25445
25696
  return null;
25446
25697
  }
25447
- const stats = await fs21.stat(absolutePath).catch(() => null);
25698
+ const stats = await fs22.stat(absolutePath).catch(() => null);
25448
25699
  if (!stats?.isFile()) {
25449
25700
  return null;
25450
25701
  }
25451
- const raw = await fs21.readFile(absolutePath, "utf8");
25452
- const parsed = matter12(raw);
25702
+ const raw = await fs22.readFile(absolutePath, "utf8");
25703
+ const parsed = matter13(raw);
25453
25704
  return {
25454
25705
  path: relativePath,
25455
- title: typeof parsed.data.title === "string" ? parsed.data.title : path25.basename(relativePath, path25.extname(relativePath)),
25706
+ title: typeof parsed.data.title === "string" ? parsed.data.title : path26.basename(relativePath, path26.extname(relativePath)),
25456
25707
  frontmatter: parsed.data,
25457
25708
  content: parsed.content
25458
25709
  };
@@ -25519,7 +25770,7 @@ function tierLintFindings(paths, graph, consolidationConfig, now = /* @__PURE__
25519
25770
  severity: "info",
25520
25771
  code: "stale_working_tier",
25521
25772
  message: `Working-tier insight ${page.title} has not been consolidated after the session window.`,
25522
- pagePath: path25.join(paths.wikiDir, page.path),
25773
+ pagePath: path26.join(paths.wikiDir, page.path),
25523
25774
  relatedPageIds: [page.id]
25524
25775
  });
25525
25776
  }
@@ -25531,7 +25782,7 @@ function tierLintFindings(paths, graph, consolidationConfig, now = /* @__PURE__
25531
25782
  severity: "warning",
25532
25783
  code: "broken_consolidation_basis",
25533
25784
  message: `Tier page ${page.title} references missing lower-tier page ids: ${missing.join(", ")}.`,
25534
- pagePath: path25.join(paths.wikiDir, page.path),
25785
+ pagePath: path26.join(paths.wikiDir, page.path),
25535
25786
  relatedPageIds: [page.id]
25536
25787
  });
25537
25788
  }
@@ -25541,7 +25792,7 @@ function tierLintFindings(paths, graph, consolidationConfig, now = /* @__PURE__
25541
25792
  severity: "warning",
25542
25793
  code: "semantic_without_episodic_basis",
25543
25794
  message: `Semantic-tier page ${page.title} has no episodic basis recorded.`,
25544
- pagePath: path25.join(paths.wikiDir, page.path),
25795
+ pagePath: path26.join(paths.wikiDir, page.path),
25545
25796
  relatedPageIds: [page.id]
25546
25797
  });
25547
25798
  }
@@ -25562,7 +25813,7 @@ function decayLintFindings(paths, graph, freshnessConfig, now = /* @__PURE__ */
25562
25813
  severity: "info",
25563
25814
  code: "decayed-pages",
25564
25815
  message: `Page ${page.title} has decayed (score=${score.toFixed(2)}, below threshold ${staleThreshold}).`,
25565
- pagePath: path25.join(paths.wikiDir, page.path),
25816
+ pagePath: path26.join(paths.wikiDir, page.path),
25566
25817
  relatedPageIds: [page.id]
25567
25818
  });
25568
25819
  }
@@ -25571,7 +25822,7 @@ function decayLintFindings(paths, graph, freshnessConfig, now = /* @__PURE__ */
25571
25822
  severity: "warning",
25572
25823
  code: "broken_supersession",
25573
25824
  message: `Page ${page.title} is marked supersededBy ${supersededBy}, but that page does not exist.`,
25574
- pagePath: path25.join(paths.wikiDir, page.path),
25825
+ pagePath: path26.join(paths.wikiDir, page.path),
25575
25826
  relatedPageIds: [page.id]
25576
25827
  });
25577
25828
  }
@@ -25580,7 +25831,7 @@ function decayLintFindings(paths, graph, freshnessConfig, now = /* @__PURE__ */
25580
25831
  severity: "info",
25581
25832
  code: "inconsistent_decay",
25582
25833
  message: `Page ${page.title} is marked stale but decay score ${score.toFixed(2)} is above the threshold.`,
25583
- pagePath: path25.join(paths.wikiDir, page.path),
25834
+ pagePath: path26.join(paths.wikiDir, page.path),
25584
25835
  relatedPageIds: [page.id]
25585
25836
  });
25586
25837
  }
@@ -25602,7 +25853,7 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
25602
25853
  severity: "warning",
25603
25854
  code: "stale_page",
25604
25855
  message: `Page ${page.title} is stale because the vault schema changed.`,
25605
- pagePath: path25.join(paths.wikiDir, page.path),
25856
+ pagePath: path26.join(paths.wikiDir, page.path),
25606
25857
  relatedPageIds: [page.id]
25607
25858
  });
25608
25859
  }
@@ -25615,7 +25866,7 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
25615
25866
  severity: "warning",
25616
25867
  code: "stale_page",
25617
25868
  message: `Page ${page.title} is stale because source ${sourceId} changed.`,
25618
- pagePath: path25.join(paths.wikiDir, page.path),
25869
+ pagePath: path26.join(paths.wikiDir, page.path),
25619
25870
  relatedSourceIds: [sourceId],
25620
25871
  relatedPageIds: [page.id]
25621
25872
  });
@@ -25626,13 +25877,13 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
25626
25877
  severity: "info",
25627
25878
  code: "orphan_page",
25628
25879
  message: `Page ${page.title} has no backlinks.`,
25629
- pagePath: path25.join(paths.wikiDir, page.path),
25880
+ pagePath: path26.join(paths.wikiDir, page.path),
25630
25881
  relatedPageIds: [page.id]
25631
25882
  });
25632
25883
  }
25633
- const absolutePath = path25.join(paths.wikiDir, page.path);
25884
+ const absolutePath = path26.join(paths.wikiDir, page.path);
25634
25885
  if (await fileExists(absolutePath)) {
25635
- const content = await fs21.readFile(absolutePath, "utf8");
25886
+ const content = await fs22.readFile(absolutePath, "utf8");
25636
25887
  const claimLines = extractClaimSectionLines(content);
25637
25888
  if (claimLines !== null) {
25638
25889
  const uncited = claimLines.filter(
@@ -25789,8 +26040,8 @@ async function consolidateVault(rootDir, options = {}) {
25789
26040
  }
25790
26041
 
25791
26042
  // src/watch.ts
25792
- import fs22 from "fs/promises";
25793
- import path26 from "path";
26043
+ import fs23 from "fs/promises";
26044
+ import path27 from "path";
25794
26045
  import process3 from "process";
25795
26046
  import chokidar from "chokidar";
25796
26047
  var MAX_BACKOFF_MS = 3e4;
@@ -25844,7 +26095,7 @@ function isCodeOnlyChange(reasons) {
25844
26095
  for (const reason of reasons) {
25845
26096
  const match = reason.match(FILE_CHANGE_RE);
25846
26097
  if (!match) return false;
25847
- const ext = path26.extname(match[1]).toLowerCase();
26098
+ const ext = path27.extname(match[1]).toLowerCase();
25848
26099
  if (!ext || !CODE_EXTENSIONS.has(ext)) return false;
25849
26100
  }
25850
26101
  return reasons.size > 0;
@@ -25853,7 +26104,7 @@ function hasNonCodeChanges(reasons) {
25853
26104
  for (const reason of reasons) {
25854
26105
  const match = reason.match(FILE_CHANGE_RE);
25855
26106
  if (!match) return true;
25856
- const ext = path26.extname(match[1]).toLowerCase();
26107
+ const ext = path27.extname(match[1]).toLowerCase();
25857
26108
  if (!ext || !CODE_EXTENSIONS.has(ext)) return true;
25858
26109
  }
25859
26110
  return false;
@@ -25866,17 +26117,17 @@ function collectNonCodePaths(reasons) {
25866
26117
  result.push(reason);
25867
26118
  continue;
25868
26119
  }
25869
- const ext = path26.extname(match[1]).toLowerCase();
26120
+ const ext = path27.extname(match[1]).toLowerCase();
25870
26121
  if (!ext || !CODE_EXTENSIONS.has(ext)) result.push(match[1]);
25871
26122
  }
25872
26123
  return result;
25873
26124
  }
25874
26125
  function hasIgnoredRepoSegment(baseDir, targetPath) {
25875
- const relativePath = path26.relative(baseDir, targetPath);
26126
+ const relativePath = path27.relative(baseDir, targetPath);
25876
26127
  if (!relativePath || relativePath.startsWith("..")) {
25877
26128
  return false;
25878
26129
  }
25879
- return relativePath.split(path26.sep).some((segment) => REPO_WATCH_IGNORES.has(segment));
26130
+ return relativePath.split(path27.sep).some((segment) => REPO_WATCH_IGNORES.has(segment));
25880
26131
  }
25881
26132
  function workspaceIgnoreRoots(rootDir, paths) {
25882
26133
  return [
@@ -25885,22 +26136,22 @@ function workspaceIgnoreRoots(rootDir, paths) {
25885
26136
  paths.stateDir,
25886
26137
  paths.agentDir,
25887
26138
  paths.inboxDir,
25888
- path26.join(rootDir, ".claude"),
25889
- path26.join(rootDir, ".cursor"),
25890
- path26.join(rootDir, ".obsidian")
25891
- ].map((candidate) => path26.resolve(candidate));
26139
+ path27.join(rootDir, ".claude"),
26140
+ path27.join(rootDir, ".cursor"),
26141
+ path27.join(rootDir, ".obsidian")
26142
+ ].map((candidate) => path27.resolve(candidate));
25892
26143
  }
25893
26144
  async function resolveWatchTargets(rootDir, paths, options) {
25894
- const targets = /* @__PURE__ */ new Set([path26.resolve(paths.inboxDir)]);
26145
+ const targets = /* @__PURE__ */ new Set([path27.resolve(paths.inboxDir)]);
25895
26146
  if (options.repo) {
25896
26147
  for (const repoRoot of await resolveWatchedRepoRoots(rootDir, { overrideRoots: options.overrideRoots })) {
25897
- targets.add(path26.resolve(repoRoot));
26148
+ targets.add(path27.resolve(repoRoot));
25898
26149
  }
25899
26150
  }
25900
26151
  return [...targets].sort((left, right) => left.localeCompare(right));
25901
26152
  }
25902
26153
  function resolveRootRelative(rootDir, candidate) {
25903
- return path26.isAbsolute(candidate) ? path26.resolve(candidate) : path26.resolve(rootDir, candidate);
26154
+ return path27.isAbsolute(candidate) ? path27.resolve(candidate) : path27.resolve(rootDir, candidate);
25904
26155
  }
25905
26156
  async function resolveWatchedRepoRoots(rootDir, options = {}) {
25906
26157
  const override = options.overrideRoots?.filter(Boolean) ?? [];
@@ -25914,17 +26165,17 @@ async function resolveWatchedRepoRoots(rootDir, options = {}) {
25914
26165
  const excluded = new Set(
25915
26166
  (watchConfig.excludeRepoRoots ?? []).filter(Boolean).map((candidate) => resolveRootRelative(rootDir, candidate))
25916
26167
  );
25917
- return dedupeSorted(baseRoots.filter((candidate) => !excluded.has(path26.resolve(candidate))));
26168
+ return dedupeSorted(baseRoots.filter((candidate) => !excluded.has(path27.resolve(candidate))));
25918
26169
  }
25919
26170
  async function listWatchedRoots(rootDir, options = {}) {
25920
26171
  return resolveWatchedRepoRoots(rootDir, options);
25921
26172
  }
25922
26173
  function dedupeSorted(values) {
25923
- return [...new Set(values.map((value) => path26.resolve(value)))].sort((left, right) => left.localeCompare(right));
26174
+ return [...new Set(values.map((value) => path27.resolve(value)))].sort((left, right) => left.localeCompare(right));
25924
26175
  }
25925
26176
  async function readConfigJson(rootDir) {
25926
- const configPath = path26.join(rootDir, "swarmvault.config.json");
25927
- const raw = await fs22.readFile(configPath, "utf8");
26177
+ const configPath = path27.join(rootDir, "swarmvault.config.json");
26178
+ const raw = await fs23.readFile(configPath, "utf8");
25928
26179
  const parsed = JSON.parse(raw);
25929
26180
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
25930
26181
  throw new Error("swarmvault.config.json must contain a JSON object.");
@@ -25932,7 +26183,7 @@ async function readConfigJson(rootDir) {
25932
26183
  return { path: configPath, content: parsed };
25933
26184
  }
25934
26185
  async function writeConfigJson(configPath, content) {
25935
- await fs22.writeFile(configPath, `${JSON.stringify(content, null, 2)}
26186
+ await fs23.writeFile(configPath, `${JSON.stringify(content, null, 2)}
25936
26187
  `, "utf8");
25937
26188
  }
25938
26189
  function getWatchBlock(config) {
@@ -26105,7 +26356,7 @@ async function watchVault(rootDir, options = {}) {
26105
26356
  const { paths } = await initWorkspace(rootDir);
26106
26357
  const baseDebounceMs = options.debounceMs ?? 900;
26107
26358
  const ignoredRoots = workspaceIgnoreRoots(rootDir, paths);
26108
- const inboxWatchRoot = path26.resolve(paths.inboxDir);
26359
+ const inboxWatchRoot = path27.resolve(paths.inboxDir);
26109
26360
  let watchTargets = await resolveWatchTargets(rootDir, paths, options);
26110
26361
  let timer;
26111
26362
  let running = false;
@@ -26120,7 +26371,7 @@ async function watchVault(rootDir, options = {}) {
26120
26371
  usePolling: true,
26121
26372
  interval: 100,
26122
26373
  ignored: (targetPath) => {
26123
- const absolutePath = path26.resolve(targetPath);
26374
+ const absolutePath = path27.resolve(targetPath);
26124
26375
  const primaryTarget = watchTargets.filter((watchTarget) => isPathWithin(watchTarget, absolutePath)).sort((left, right) => right.length - left.length)[0] ?? null;
26125
26376
  if (!primaryTarget) {
26126
26377
  return false;
@@ -26322,8 +26573,8 @@ async function watchVault(rootDir, options = {}) {
26322
26573
  }
26323
26574
  };
26324
26575
  const reasonForPath = (targetPath) => {
26325
- const baseDir = watchTargets.filter((watchTarget) => isPathWithin(watchTarget, path26.resolve(targetPath))).sort((left, right) => right.length - left.length)[0] ?? paths.inboxDir;
26326
- return path26.relative(baseDir, targetPath) || ".";
26576
+ const baseDir = watchTargets.filter((watchTarget) => isPathWithin(watchTarget, path27.resolve(targetPath))).sort((left, right) => right.length - left.length)[0] ?? paths.inboxDir;
26577
+ return path27.relative(baseDir, targetPath) || ".";
26327
26578
  };
26328
26579
  watcher.on("add", (filePath) => schedule(`add:${reasonForPath(filePath)}`)).on("change", (filePath) => schedule(`change:${reasonForPath(filePath)}`)).on("unlink", (filePath) => schedule(`unlink:${reasonForPath(filePath)}`)).on("addDir", (dirPath) => schedule(`addDir:${reasonForPath(dirPath)}`)).on("unlinkDir", (dirPath) => schedule(`unlinkDir:${reasonForPath(dirPath)}`)).on("error", (caught) => schedule(`error:${caught instanceof Error ? caught.message : String(caught)}`));
26329
26580
  await new Promise((resolve, reject) => {
@@ -26362,7 +26613,7 @@ async function getWatchStatus(rootDir) {
26362
26613
  }
26363
26614
 
26364
26615
  // src/mcp.ts
26365
- var SERVER_VERSION = "0.11.0";
26616
+ var SERVER_VERSION = "0.12.0";
26366
26617
  async function createMcpServer(rootDir) {
26367
26618
  const server = new McpServer({
26368
26619
  name: "swarmvault",
@@ -26694,6 +26945,19 @@ async function createMcpServer(rootDir) {
26694
26945
  return asToolText(result);
26695
26946
  })
26696
26947
  );
26948
+ server.registerTool(
26949
+ "migrate",
26950
+ {
26951
+ description: "Detect the vault's version and preview the migration plan to the current SwarmVault version.",
26952
+ inputSchema: {
26953
+ target: z8.string().optional().describe("Optional target version cap (migrations with toVersion above this are skipped)")
26954
+ }
26955
+ },
26956
+ safeHandler(async ({ target }) => {
26957
+ const plan = await runMigration(rootDir, { targetVersion: target, dryRun: true });
26958
+ return asToolText(plan);
26959
+ })
26960
+ );
26697
26961
  server.registerResource(
26698
26962
  "swarmvault-config",
26699
26963
  "swarmvault://config",
@@ -26760,7 +27024,7 @@ async function createMcpServer(rootDir) {
26760
27024
  },
26761
27025
  async () => {
26762
27026
  const { paths } = await loadVaultConfig(rootDir);
26763
- const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path27.relative(paths.sessionsDir, filePath))).sort();
27027
+ const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path28.relative(paths.sessionsDir, filePath))).sort();
26764
27028
  return asTextResource("swarmvault://sessions", JSON.stringify(files, null, 2));
26765
27029
  }
26766
27030
  );
@@ -26793,8 +27057,8 @@ async function createMcpServer(rootDir) {
26793
27057
  return asTextResource(`swarmvault://pages/${encodedPath}`, `Page not found: ${relativePath}`);
26794
27058
  }
26795
27059
  const { paths } = await loadVaultConfig(rootDir);
26796
- const absolutePath = path27.resolve(paths.wikiDir, relativePath);
26797
- return asTextResource(`swarmvault://pages/${encodedPath}`, await fs23.readFile(absolutePath, "utf8"));
27060
+ const absolutePath = path28.resolve(paths.wikiDir, relativePath);
27061
+ return asTextResource(`swarmvault://pages/${encodedPath}`, await fs24.readFile(absolutePath, "utf8"));
26798
27062
  }
26799
27063
  );
26800
27064
  server.registerResource(
@@ -26802,11 +27066,11 @@ async function createMcpServer(rootDir) {
26802
27066
  new ResourceTemplate("swarmvault://sessions/{path}", {
26803
27067
  list: async () => {
26804
27068
  const { paths } = await loadVaultConfig(rootDir);
26805
- const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path27.relative(paths.sessionsDir, filePath))).sort();
27069
+ const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path28.relative(paths.sessionsDir, filePath))).sort();
26806
27070
  return {
26807
27071
  resources: files.map((relativePath) => ({
26808
27072
  uri: `swarmvault://sessions/${encodeURIComponent(relativePath)}`,
26809
- name: path27.basename(relativePath, ".md"),
27073
+ name: path28.basename(relativePath, ".md"),
26810
27074
  title: relativePath,
26811
27075
  description: "SwarmVault session artifact",
26812
27076
  mimeType: "text/markdown"
@@ -26823,11 +27087,11 @@ async function createMcpServer(rootDir) {
26823
27087
  const { paths } = await loadVaultConfig(rootDir);
26824
27088
  const encodedPath = typeof variables.path === "string" ? variables.path : "";
26825
27089
  const relativePath = decodeURIComponent(encodedPath);
26826
- const absolutePath = path27.resolve(paths.sessionsDir, relativePath);
27090
+ const absolutePath = path28.resolve(paths.sessionsDir, relativePath);
26827
27091
  if (!isPathWithin(paths.sessionsDir, absolutePath) || !await fileExists(absolutePath)) {
26828
27092
  return asTextResource(`swarmvault://sessions/${encodedPath}`, `Session not found: ${relativePath}`);
26829
27093
  }
26830
- return asTextResource(`swarmvault://sessions/${encodedPath}`, await fs23.readFile(absolutePath, "utf8"));
27094
+ return asTextResource(`swarmvault://sessions/${encodedPath}`, await fs24.readFile(absolutePath, "utf8"));
26831
27095
  }
26832
27096
  );
26833
27097
  return server;
@@ -26885,14 +27149,76 @@ function asTextResource(uri, text) {
26885
27149
  };
26886
27150
  }
26887
27151
 
27152
+ // src/providers/openai-compatible-capabilities.ts
27153
+ var OPENAI_COMPATIBLE_CAPABILITY_MATRIX = Object.freeze({
27154
+ openai: {
27155
+ presetId: "openai",
27156
+ apiStyle: "responses",
27157
+ capabilities: ["responses", "chat", "structured", "tools", "vision", "embeddings", "streaming", "image_generation", "audio"],
27158
+ notes: "Reference implementation. Supports responses API, strict structured output, tool calling, vision, image generation, and Whisper transcription."
27159
+ },
27160
+ "openai-compatible": {
27161
+ presetId: "openai-compatible",
27162
+ apiStyle: "responses",
27163
+ capabilities: ["chat", "structured", "embeddings", "audio"],
27164
+ notes: "Generic fallback for self-hosted backends. Structured output adherence varies; verify capability flags per deployment."
27165
+ },
27166
+ openrouter: {
27167
+ presetId: "openrouter",
27168
+ apiStyle: "chat",
27169
+ capabilities: ["chat", "structured", "embeddings"],
27170
+ notes: "Router of upstream models. No responses API, no vision at the gateway level, structured output requires model-specific care."
27171
+ },
27172
+ groq: {
27173
+ presetId: "groq",
27174
+ apiStyle: "chat",
27175
+ capabilities: ["chat", "structured", "embeddings", "audio"],
27176
+ notes: "Fast chat completions, Whisper-compatible audio endpoint, no vision, no responses API."
27177
+ },
27178
+ together: {
27179
+ presetId: "together",
27180
+ apiStyle: "chat",
27181
+ capabilities: ["chat", "structured", "embeddings"],
27182
+ notes: "Chat completions with mixed structured-output reliability across hosted models. No vision or audio."
27183
+ },
27184
+ xai: {
27185
+ presetId: "xai",
27186
+ apiStyle: "chat",
27187
+ capabilities: ["chat", "structured", "embeddings"],
27188
+ notes: "Grok API. Chat and structured output; no vision or audio in the open surface."
27189
+ },
27190
+ cerebras: {
27191
+ presetId: "cerebras",
27192
+ apiStyle: "chat",
27193
+ capabilities: ["chat", "structured", "embeddings"],
27194
+ notes: "High-throughput inference. No vision, no audio, no image generation."
27195
+ },
27196
+ ollama: {
27197
+ presetId: "ollama",
27198
+ apiStyle: "chat",
27199
+ capabilities: ["chat", "structured", "tools", "vision", "embeddings", "streaming", "local", "audio"],
27200
+ notes: "Local-first. Capabilities depend on which models are installed; structured output is best-effort."
27201
+ }
27202
+ });
27203
+ function lookupPresetCapabilities(presetId) {
27204
+ return OPENAI_COMPATIBLE_CAPABILITY_MATRIX[presetId] ?? null;
27205
+ }
27206
+ async function withCapabilityFallback(provider, capability, run, fallback) {
27207
+ if (provider.capabilities.has(capability)) {
27208
+ return { supported: true, reason: null, value: await run() };
27209
+ }
27210
+ const fallbackValue = await fallback();
27211
+ return { supported: false, reason: "unsupported", value: fallbackValue };
27212
+ }
27213
+
26888
27214
  // src/schedule.ts
26889
- import fs24 from "fs/promises";
26890
- import path28 from "path";
27215
+ import fs25 from "fs/promises";
27216
+ import path29 from "path";
26891
27217
  function scheduleStatePath(schedulesDir, jobId) {
26892
- return path28.join(schedulesDir, `${encodeURIComponent(jobId)}.json`);
27218
+ return path29.join(schedulesDir, `${encodeURIComponent(jobId)}.json`);
26893
27219
  }
26894
27220
  function scheduleLockPath(schedulesDir, jobId) {
26895
- return path28.join(schedulesDir, `${encodeURIComponent(jobId)}.lock`);
27221
+ return path29.join(schedulesDir, `${encodeURIComponent(jobId)}.lock`);
26896
27222
  }
26897
27223
  function parseEveryDuration(value) {
26898
27224
  const match = value.trim().match(/^(\d+)(m|h|d)$/i);
@@ -26995,13 +27321,13 @@ async function acquireJobLease(rootDir, jobId) {
26995
27321
  const { paths } = await loadVaultConfig(rootDir);
26996
27322
  const leasePath = scheduleLockPath(paths.schedulesDir, jobId);
26997
27323
  await ensureDir(paths.schedulesDir);
26998
- const handle = await fs24.open(leasePath, "wx");
27324
+ const handle = await fs25.open(leasePath, "wx");
26999
27325
  await handle.writeFile(`${process.pid}
27000
27326
  ${(/* @__PURE__ */ new Date()).toISOString()}
27001
27327
  `);
27002
27328
  await handle.close();
27003
27329
  return async () => {
27004
- await fs24.rm(leasePath, { force: true });
27330
+ await fs25.rm(leasePath, { force: true });
27005
27331
  };
27006
27332
  }
27007
27333
  async function listSchedules(rootDir) {
@@ -27160,9 +27486,9 @@ async function serveSchedules(rootDir, pollMs = 3e4) {
27160
27486
 
27161
27487
  // src/sources.ts
27162
27488
  import { spawn as spawn2 } from "child_process";
27163
- import fs25 from "fs/promises";
27164
- import path29 from "path";
27165
- import matter13 from "gray-matter";
27489
+ import fs26 from "fs/promises";
27490
+ import path30 from "path";
27491
+ import matter14 from "gray-matter";
27166
27492
  import { JSDOM as JSDOM3 } from "jsdom";
27167
27493
  var DEFAULT_CRAWL_MAX_PAGES = 12;
27168
27494
  var DEFAULT_CRAWL_MAX_DEPTH = 2;
@@ -27207,24 +27533,24 @@ function emptyManagedSourceSyncCounts() {
27207
27533
  };
27208
27534
  }
27209
27535
  function withinRoot2(rootPath, targetPath) {
27210
- const relative = path29.relative(rootPath, targetPath);
27211
- return relative === "" || !relative.startsWith("..") && !path29.isAbsolute(relative);
27536
+ const relative = path30.relative(rootPath, targetPath);
27537
+ return relative === "" || !relative.startsWith("..") && !path30.isAbsolute(relative);
27212
27538
  }
27213
27539
  async function findNearestGitRoot3(startPath) {
27214
- let current = path29.resolve(startPath);
27540
+ let current = path30.resolve(startPath);
27215
27541
  try {
27216
- const stat = await fs25.stat(current);
27542
+ const stat = await fs26.stat(current);
27217
27543
  if (!stat.isDirectory()) {
27218
- current = path29.dirname(current);
27544
+ current = path30.dirname(current);
27219
27545
  }
27220
27546
  } catch {
27221
- current = path29.dirname(current);
27547
+ current = path30.dirname(current);
27222
27548
  }
27223
27549
  while (true) {
27224
- if (await fileExists(path29.join(current, ".git"))) {
27550
+ if (await fileExists(path30.join(current, ".git"))) {
27225
27551
  return current;
27226
27552
  }
27227
- const parent = path29.dirname(current);
27553
+ const parent = path30.dirname(current);
27228
27554
  if (parent === current) {
27229
27555
  return null;
27230
27556
  }
@@ -27298,7 +27624,7 @@ function isAllowedDocsCandidate(candidate, startUrl) {
27298
27624
  if (candidate.origin !== startUrl.origin) {
27299
27625
  return false;
27300
27626
  }
27301
- const extension = path29.extname(candidate.pathname).toLowerCase();
27627
+ const extension = path30.extname(candidate.pathname).toLowerCase();
27302
27628
  if (extension && extension !== ".html" && extension !== ".htm" && extension !== ".md") {
27303
27629
  return false;
27304
27630
  }
@@ -27387,14 +27713,14 @@ function matchesManagedSourceSpec(existing, input) {
27387
27713
  return false;
27388
27714
  }
27389
27715
  if (input.kind === "directory" || input.kind === "file") {
27390
- return path29.resolve(existing.path ?? "") === path29.resolve(input.path);
27716
+ return path30.resolve(existing.path ?? "") === path30.resolve(input.path);
27391
27717
  }
27392
27718
  return (existing.url ?? "") === input.url;
27393
27719
  }
27394
27720
  async function resolveManagedSourceInput(rootDir, input) {
27395
- const absoluteInput = path29.resolve(rootDir, input);
27721
+ const absoluteInput = path30.resolve(rootDir, input);
27396
27722
  if (!(input.startsWith("http://") || input.startsWith("https://"))) {
27397
- const stat = await fs25.stat(absoluteInput).catch(() => null);
27723
+ const stat = await fs26.stat(absoluteInput).catch(() => null);
27398
27724
  if (!stat) {
27399
27725
  throw new Error(`Source not found: ${input}`);
27400
27726
  }
@@ -27402,7 +27728,7 @@ async function resolveManagedSourceInput(rootDir, input) {
27402
27728
  return {
27403
27729
  kind: "file",
27404
27730
  path: absoluteInput,
27405
- title: path29.basename(absoluteInput, path29.extname(absoluteInput)) || absoluteInput
27731
+ title: path30.basename(absoluteInput, path30.extname(absoluteInput)) || absoluteInput
27406
27732
  };
27407
27733
  }
27408
27734
  if (!stat.isDirectory()) {
@@ -27414,7 +27740,7 @@ async function resolveManagedSourceInput(rootDir, input) {
27414
27740
  kind: "directory",
27415
27741
  path: absoluteInput,
27416
27742
  repoRoot,
27417
- title: path29.basename(absoluteInput) || absoluteInput
27743
+ title: path30.basename(absoluteInput) || absoluteInput
27418
27744
  };
27419
27745
  }
27420
27746
  const github = normalizeGitHubRepoRootUrl(input);
@@ -27437,16 +27763,16 @@ async function resolveManagedSourceInput(rootDir, input) {
27437
27763
  };
27438
27764
  }
27439
27765
  function directorySourceIdsFor(manifests, inputPath) {
27440
- return manifests.filter((manifest) => manifest.originalPath && withinRoot2(path29.resolve(inputPath), path29.resolve(manifest.originalPath))).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
27766
+ return manifests.filter((manifest) => manifest.originalPath && withinRoot2(path30.resolve(inputPath), path30.resolve(manifest.originalPath))).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
27441
27767
  }
27442
27768
  function fileSourceIdsFor(manifests, inputPath) {
27443
- const absoluteInput = path29.resolve(inputPath);
27444
- return manifests.filter((manifest) => manifest.originalPath && path29.resolve(manifest.originalPath) === absoluteInput).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
27769
+ const absoluteInput = path30.resolve(inputPath);
27770
+ return manifests.filter((manifest) => manifest.originalPath && path30.resolve(manifest.originalPath) === absoluteInput).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
27445
27771
  }
27446
27772
  async function syncDirectorySource(rootDir, inputPath, repoRoot) {
27447
27773
  const manifestsBefore = await listManifests(rootDir);
27448
27774
  const previousInScope = manifestsBefore.filter(
27449
- (manifest) => manifest.originalPath && withinRoot2(path29.resolve(inputPath), path29.resolve(manifest.originalPath))
27775
+ (manifest) => manifest.originalPath && withinRoot2(path30.resolve(inputPath), path30.resolve(manifest.originalPath))
27450
27776
  );
27451
27777
  const result = await ingestDirectory(rootDir, inputPath, { repoRoot });
27452
27778
  const removed = [];
@@ -27454,7 +27780,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
27454
27780
  if (!manifest.originalPath) {
27455
27781
  continue;
27456
27782
  }
27457
- if (await fileExists(path29.resolve(manifest.originalPath))) {
27783
+ if (await fileExists(path30.resolve(manifest.originalPath))) {
27458
27784
  continue;
27459
27785
  }
27460
27786
  const removedManifest = await removeManifestBySourceId(rootDir, manifest.sourceId);
@@ -27464,7 +27790,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
27464
27790
  }
27465
27791
  const manifestsAfter = await listManifests(rootDir);
27466
27792
  return {
27467
- title: path29.basename(inputPath) || inputPath,
27793
+ title: path30.basename(inputPath) || inputPath,
27468
27794
  sourceIds: directorySourceIdsFor(manifestsAfter, inputPath),
27469
27795
  counts: {
27470
27796
  scannedCount: result.scannedCount,
@@ -27480,7 +27806,7 @@ async function syncFileSource(rootDir, inputPath) {
27480
27806
  const result = await ingestInputDetailed(rootDir, inputPath);
27481
27807
  const manifestsAfter = await listManifests(rootDir);
27482
27808
  return {
27483
- title: path29.basename(inputPath, path29.extname(inputPath)) || inputPath,
27809
+ title: path30.basename(inputPath, path30.extname(inputPath)) || inputPath,
27484
27810
  sourceIds: fileSourceIdsFor(manifestsAfter, inputPath),
27485
27811
  counts: {
27486
27812
  scannedCount: result.scannedCount,
@@ -27514,8 +27840,8 @@ async function runGitCommand(cwd, args) {
27514
27840
  }
27515
27841
  async function syncGitHubRepoSource(rootDir, entry) {
27516
27842
  const workingDir = await managedSourceWorkingDir(rootDir, entry.id);
27517
- const checkoutDir = path29.join(workingDir, "checkout");
27518
- await fs25.rm(checkoutDir, { recursive: true, force: true });
27843
+ const checkoutDir = path30.join(workingDir, "checkout");
27844
+ await fs26.rm(checkoutDir, { recursive: true, force: true });
27519
27845
  await ensureDir(workingDir);
27520
27846
  if (!entry.url) {
27521
27847
  throw new Error(`Managed source ${entry.id} is missing its repository URL.`);
@@ -27645,7 +27971,7 @@ function scopedNodeIds(graph, sourceIds) {
27645
27971
  async function loadSourceAnalyses(rootDir, sourceIds) {
27646
27972
  const { paths } = await loadVaultConfig(rootDir);
27647
27973
  const analyses = await Promise.all(
27648
- sourceIds.map(async (sourceId) => await readJsonFile(path29.join(paths.analysesDir, `${sourceId}.json`)))
27974
+ sourceIds.map(async (sourceId) => await readJsonFile(path30.join(paths.analysesDir, `${sourceId}.json`)))
27649
27975
  );
27650
27976
  return analyses.filter((analysis) => Boolean(analysis?.sourceId));
27651
27977
  }
@@ -27806,9 +28132,9 @@ async function writeSourceBriefForScope(rootDir, source) {
27806
28132
  confidence: 0.82
27807
28133
  }
27808
28134
  });
27809
- const absolutePath = path29.join(paths.wikiDir, output.page.path);
27810
- await ensureDir(path29.dirname(absolutePath));
27811
- await fs25.writeFile(absolutePath, output.content, "utf8");
28135
+ const absolutePath = path30.join(paths.wikiDir, output.page.path);
28136
+ await ensureDir(path30.dirname(absolutePath));
28137
+ await fs26.writeFile(absolutePath, output.content, "utf8");
27812
28138
  return absolutePath;
27813
28139
  }
27814
28140
  async function writeSourceBrief(rootDir, source) {
@@ -28096,7 +28422,7 @@ function selectGuidedTargetPages(scope, sourcePages, questions) {
28096
28422
  return (matchedTargets.length ? matchedTargets : canonicalPages).slice(0, 6);
28097
28423
  }
28098
28424
  function insightRelativePathForTarget(page, scope) {
28099
- const basename = path29.basename(page.path);
28425
+ const basename = path30.basename(page.path);
28100
28426
  if (page.kind === "concept") {
28101
28427
  return `insights/concepts/${basename}`;
28102
28428
  }
@@ -28323,7 +28649,7 @@ async function stageSourceReviewForScope(rootDir, scope) {
28323
28649
  return {
28324
28650
  sourceId: scope.id,
28325
28651
  pageId: output.page.id,
28326
- reviewPath: path29.join(approval.approvalDir, "wiki", output.page.path),
28652
+ reviewPath: path30.join(approval.approvalDir, "wiki", output.page.path),
28327
28653
  staged: true,
28328
28654
  approvalId: approval.approvalId,
28329
28655
  approvalDir: approval.approvalDir
@@ -28390,7 +28716,7 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
28390
28716
  const evidenceState = contradictions.length > 0 ? "conflicting" : session.targetedPagePaths.some(
28391
28717
  (targetPath) => sourcePages.some((page) => page.path === targetPath && page.sourceIds.some((sourceId) => !scope.sourceIds.includes(sourceId)))
28392
28718
  ) ? "reinforcing" : session.targetedPagePaths.length ? "new" : "needs_judgment";
28393
- const relativeBriefPath = session.briefPath && path29.isAbsolute(session.briefPath) ? path29.relative(paths.wikiDir, session.briefPath) : session.briefPath;
28719
+ const relativeBriefPath = session.briefPath && path30.isAbsolute(session.briefPath) ? path30.relative(paths.wikiDir, session.briefPath) : session.briefPath;
28394
28720
  const sessionMarkdown = [
28395
28721
  `# Guided Session: ${scope.title}`,
28396
28722
  "",
@@ -28473,9 +28799,9 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
28473
28799
  async function persistSourceSessionPage(rootDir, scope, session) {
28474
28800
  const { paths } = await loadVaultConfig(rootDir);
28475
28801
  const output = await buildSourceSessionSavedPage(rootDir, scope, session);
28476
- const absolutePath = path29.join(paths.wikiDir, output.page.path);
28477
- await ensureDir(path29.dirname(absolutePath));
28478
- await fs25.writeFile(absolutePath, output.content, "utf8");
28802
+ const absolutePath = path30.join(paths.wikiDir, output.page.path);
28803
+ await ensureDir(path30.dirname(absolutePath));
28804
+ await fs26.writeFile(absolutePath, output.content, "utf8");
28479
28805
  return { pageId: output.page.id, sessionPath: absolutePath };
28480
28806
  }
28481
28807
  async function buildGuidedUpdatePages(rootDir, scope, session) {
@@ -28503,9 +28829,9 @@ async function buildGuidedUpdatePages(rootDir, scope, session) {
28503
28829
  targetPages.map(async (targetPage) => {
28504
28830
  const evidenceState = classifyGuidedEvidenceState(scope, targetPage, contradictions);
28505
28831
  const relativePath = useCanonicalTargets && targetPage ? targetPage.path : targetPage ? insightRelativePathForTarget(targetPage, scope) : `insights/topics/${slugify(scope.title)}.md`;
28506
- const absolutePath = path29.join(paths.wikiDir, relativePath);
28507
- const existingContent = await fileExists(absolutePath) ? await fs25.readFile(absolutePath, "utf8") : "";
28508
- const parsed = existingContent ? matter13(existingContent) : { data: {}, content: "" };
28832
+ const absolutePath = path30.join(paths.wikiDir, relativePath);
28833
+ const existingContent = await fileExists(absolutePath) ? await fs26.readFile(absolutePath, "utf8") : "";
28834
+ const parsed = existingContent ? matter14(existingContent) : { data: {}, content: "" };
28509
28835
  const existingData = parsed.data;
28510
28836
  const existingSourceIds = Array.isArray(existingData.source_ids) ? existingData.source_ids.filter((value) => typeof value === "string") : [];
28511
28837
  const existingProjectIds = Array.isArray(existingData.project_ids) ? existingData.project_ids.filter((value) => typeof value === "string") : [];
@@ -28566,7 +28892,7 @@ async function buildGuidedUpdatePages(rootDir, scope, session) {
28566
28892
  ""
28567
28893
  ].join("\n");
28568
28894
  const nextBody = replaceMarkedSection(baseBody, scope.id, updateBlock);
28569
- const content = matter13.stringify(
28895
+ const content = matter14.stringify(
28570
28896
  `${nextBody.trimEnd()}
28571
28897
  `,
28572
28898
  JSON.parse(
@@ -28675,8 +29001,8 @@ async function stageSourceGuideForScope(rootDir, scope, options = {}) {
28675
29001
  }
28676
29002
  );
28677
29003
  session.status = "staged";
28678
- session.reviewPath = path29.join(approval.approvalDir, "wiki", reviewOutput.page.path);
28679
- session.guidePath = path29.join(approval.approvalDir, "wiki", guideOutput.page.path);
29004
+ session.reviewPath = path30.join(approval.approvalDir, "wiki", reviewOutput.page.path);
29005
+ session.guidePath = path30.join(approval.approvalDir, "wiki", guideOutput.page.path);
28680
29006
  session.approvalId = approval.approvalId;
28681
29007
  session.approvalDir = approval.approvalDir;
28682
29008
  const persisted = await persistSourceSessionPage(rootDir, scope, session);
@@ -28814,7 +29140,7 @@ async function addManagedSource(rootDir, input, options = {}) {
28814
29140
  const existing = sources.find((candidate) => matchesManagedSourceSpec(candidate, resolved));
28815
29141
  const now = (/* @__PURE__ */ new Date()).toISOString();
28816
29142
  const source = existing ?? {
28817
- id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind, path29.resolve(resolved.path), resolved.title) : stableManagedSourceId(resolved.kind, resolved.url, resolved.title),
29143
+ id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind, path30.resolve(resolved.path), resolved.title) : stableManagedSourceId(resolved.kind, resolved.url, resolved.title),
28818
29144
  kind: resolved.kind,
28819
29145
  title: resolved.title,
28820
29146
  path: resolved.kind === "directory" || resolved.kind === "file" ? resolved.path : void 0,
@@ -28942,7 +29268,7 @@ async function deleteManagedSource(rootDir, id) {
28942
29268
  sources.filter((source) => source.id !== id)
28943
29269
  );
28944
29270
  const workingDir = await managedSourceWorkingDir(rootDir, id);
28945
- await fs25.rm(workingDir, { recursive: true, force: true });
29271
+ await fs26.rm(workingDir, { recursive: true, force: true });
28946
29272
  return { removed: target };
28947
29273
  }
28948
29274
 
@@ -28950,11 +29276,11 @@ async function deleteManagedSource(rootDir, id) {
28950
29276
  import { execFile as execFile2 } from "child_process";
28951
29277
  import { randomUUID } from "crypto";
28952
29278
  import { EventEmitter } from "events";
28953
- import fs26 from "fs/promises";
29279
+ import fs27 from "fs/promises";
28954
29280
  import http from "http";
28955
- import path30 from "path";
29281
+ import path31 from "path";
28956
29282
  import { promisify as promisify2 } from "util";
28957
- import matter14 from "gray-matter";
29283
+ import matter15 from "gray-matter";
28958
29284
  import mime2 from "mime-types";
28959
29285
 
28960
29286
  // src/graph-presentation.ts
@@ -29106,7 +29432,7 @@ function toViewerLintFindings(findings) {
29106
29432
  var execFileAsync2 = promisify2(execFile2);
29107
29433
  async function isReadableFile(absolutePath) {
29108
29434
  try {
29109
- const stats = await fs26.stat(absolutePath);
29435
+ const stats = await fs27.stat(absolutePath);
29110
29436
  return stats.isFile();
29111
29437
  } catch {
29112
29438
  return false;
@@ -29117,15 +29443,15 @@ async function readViewerPage(rootDir, relativePath) {
29117
29443
  return null;
29118
29444
  }
29119
29445
  const { paths } = await loadVaultConfig(rootDir);
29120
- const absolutePath = path30.resolve(paths.wikiDir, relativePath);
29446
+ const absolutePath = path31.resolve(paths.wikiDir, relativePath);
29121
29447
  if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
29122
29448
  return null;
29123
29449
  }
29124
- const raw = await fs26.readFile(absolutePath, "utf8");
29125
- const parsed = matter14(raw);
29450
+ const raw = await fs27.readFile(absolutePath, "utf8");
29451
+ const parsed = matter15(raw);
29126
29452
  return {
29127
29453
  path: relativePath,
29128
- title: typeof parsed.data.title === "string" ? parsed.data.title : path30.basename(relativePath, path30.extname(relativePath)),
29454
+ title: typeof parsed.data.title === "string" ? parsed.data.title : path31.basename(relativePath, path31.extname(relativePath)),
29129
29455
  frontmatter: parsed.data,
29130
29456
  content: parsed.content,
29131
29457
  assets: normalizeOutputAssets(parsed.data.output_assets)
@@ -29136,12 +29462,12 @@ async function readViewerAsset(rootDir, relativePath) {
29136
29462
  return null;
29137
29463
  }
29138
29464
  const { paths } = await loadVaultConfig(rootDir);
29139
- const absolutePath = path30.resolve(paths.wikiDir, relativePath);
29465
+ const absolutePath = path31.resolve(paths.wikiDir, relativePath);
29140
29466
  if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
29141
29467
  return null;
29142
29468
  }
29143
29469
  return {
29144
- buffer: await fs26.readFile(absolutePath),
29470
+ buffer: await fs27.readFile(absolutePath),
29145
29471
  mimeType: mime2.lookup(absolutePath) || "application/octet-stream"
29146
29472
  };
29147
29473
  }
@@ -29164,12 +29490,12 @@ async function readJsonBody(request) {
29164
29490
  return JSON.parse(raw);
29165
29491
  }
29166
29492
  async function ensureViewerDist(viewerDistDir) {
29167
- const indexPath = path30.join(viewerDistDir, "index.html");
29493
+ const indexPath = path31.join(viewerDistDir, "index.html");
29168
29494
  if (await fileExists(indexPath)) {
29169
29495
  return;
29170
29496
  }
29171
- const viewerProjectDir = path30.dirname(viewerDistDir);
29172
- if (await fileExists(path30.join(viewerProjectDir, "package.json"))) {
29497
+ const viewerProjectDir = path31.dirname(viewerDistDir);
29498
+ if (await fileExists(path31.join(viewerProjectDir, "package.json"))) {
29173
29499
  await execFileAsync2("pnpm", ["build"], { cwd: viewerProjectDir });
29174
29500
  }
29175
29501
  }
@@ -29192,7 +29518,7 @@ async function startGraphServer(rootDir, port, options = {}) {
29192
29518
  response.end(JSON.stringify({ error: "Graph artifact not found. Run `swarmvault compile` first." }));
29193
29519
  return;
29194
29520
  }
29195
- const reportPath = path30.join(paths.wikiDir, "graph", "report.json");
29521
+ const reportPath = path31.join(paths.wikiDir, "graph", "report.json");
29196
29522
  const report = await readJsonFile(reportPath) ?? null;
29197
29523
  response.writeHead(200, { "content-type": "application/json" });
29198
29524
  response.end(JSON.stringify(buildViewerGraphArtifact(graph, { report, full: options.full ?? false })));
@@ -29256,13 +29582,13 @@ async function startGraphServer(rootDir, port, options = {}) {
29256
29582
  return;
29257
29583
  }
29258
29584
  if (url.pathname === "/api/graph-report") {
29259
- const reportPath = path30.join(paths.wikiDir, "graph", "report.json");
29585
+ const reportPath = path31.join(paths.wikiDir, "graph", "report.json");
29260
29586
  if (!await fileExists(reportPath)) {
29261
29587
  response.writeHead(404, { "content-type": "application/json" });
29262
29588
  response.end(JSON.stringify({ error: "Graph report artifact not found. Run `swarmvault compile` first." }));
29263
29589
  return;
29264
29590
  }
29265
- const body = await fs26.readFile(reportPath, "utf8");
29591
+ const body = await fs27.readFile(reportPath, "utf8");
29266
29592
  response.writeHead(200, { "content-type": "application/json" });
29267
29593
  response.end(body);
29268
29594
  return;
@@ -29363,7 +29689,7 @@ async function startGraphServer(rootDir, port, options = {}) {
29363
29689
  return;
29364
29690
  }
29365
29691
  if (url.pathname === "/api/workspace") {
29366
- const reportPath = path30.join(paths.wikiDir, "graph", "report.json");
29692
+ const reportPath = path31.join(paths.wikiDir, "graph", "report.json");
29367
29693
  const [graphRaw, reportRaw, approvalsRaw, candidatesRaw, watchStatusRaw, lintRaw] = await Promise.all([
29368
29694
  readJsonFile(paths.graphPath).catch(() => null),
29369
29695
  readJsonFile(reportPath).catch(() => null),
@@ -29459,15 +29785,15 @@ async function startGraphServer(rootDir, port, options = {}) {
29459
29785
  return;
29460
29786
  }
29461
29787
  const relativePath = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
29462
- const target = path30.join(paths.viewerDistDir, relativePath);
29463
- const fallback = path30.join(paths.viewerDistDir, "index.html");
29788
+ const target = path31.join(paths.viewerDistDir, relativePath);
29789
+ const fallback = path31.join(paths.viewerDistDir, "index.html");
29464
29790
  const filePath = await fileExists(target) ? target : fallback;
29465
29791
  if (!await fileExists(filePath)) {
29466
29792
  response.writeHead(503, { "content-type": "text/plain" });
29467
29793
  response.end("Viewer build not found. Run `pnpm build` first.");
29468
29794
  return;
29469
29795
  }
29470
- const staticBody = await fs26.readFile(filePath);
29796
+ const staticBody = await fs27.readFile(filePath);
29471
29797
  response.writeHead(200, { "content-type": mime2.lookup(filePath) || "text/plain" });
29472
29798
  response.end(staticBody);
29473
29799
  } catch (error) {
@@ -29507,7 +29833,7 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
29507
29833
  throw new Error("Graph artifact not found. Run `swarmvault compile` first.");
29508
29834
  }
29509
29835
  await ensureViewerDist(paths.viewerDistDir);
29510
- const indexPath = path30.join(paths.viewerDistDir, "index.html");
29836
+ const indexPath = path31.join(paths.viewerDistDir, "index.html");
29511
29837
  if (!await fileExists(indexPath)) {
29512
29838
  throw new Error("Viewer build not found. Run `pnpm build` first.");
29513
29839
  }
@@ -29533,17 +29859,17 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
29533
29859
  } : null;
29534
29860
  })
29535
29861
  );
29536
- const rawHtml = await fs26.readFile(indexPath, "utf8");
29862
+ const rawHtml = await fs27.readFile(indexPath, "utf8");
29537
29863
  const scriptMatch = rawHtml.match(/<script type="module" crossorigin src="([^"]+)"><\/script>/);
29538
29864
  const styleMatch = rawHtml.match(/<link rel="stylesheet" crossorigin href="([^"]+)">/);
29539
- const scriptPath = scriptMatch?.[1] ? path30.join(paths.viewerDistDir, scriptMatch[1].replace(/^\//, "")) : null;
29540
- const stylePath = styleMatch?.[1] ? path30.join(paths.viewerDistDir, styleMatch[1].replace(/^\//, "")) : null;
29865
+ const scriptPath = scriptMatch?.[1] ? path31.join(paths.viewerDistDir, scriptMatch[1].replace(/^\//, "")) : null;
29866
+ const stylePath = styleMatch?.[1] ? path31.join(paths.viewerDistDir, styleMatch[1].replace(/^\//, "")) : null;
29541
29867
  if (!scriptPath || !await fileExists(scriptPath)) {
29542
29868
  throw new Error("Viewer script bundle not found. Run `pnpm build` first.");
29543
29869
  }
29544
- const script = await fs26.readFile(scriptPath, "utf8");
29545
- const style = stylePath && await fileExists(stylePath) ? await fs26.readFile(stylePath, "utf8") : "";
29546
- const report = await readJsonFile(path30.join(paths.wikiDir, "graph", "report.json"));
29870
+ const script = await fs27.readFile(scriptPath, "utf8");
29871
+ const style = stylePath && await fileExists(stylePath) ? await fs27.readFile(stylePath, "utf8") : "";
29872
+ const report = await readJsonFile(path31.join(paths.wikiDir, "graph", "report.json"));
29547
29873
  const embeddedData = JSON.stringify(
29548
29874
  { graph: buildViewerGraphArtifact(graph, { report, full: options.full ?? false }), pages: pages.filter(Boolean), report },
29549
29875
  null,
@@ -29566,11 +29892,12 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
29566
29892
  "</html>",
29567
29893
  ""
29568
29894
  ].filter(Boolean).join("\n");
29569
- await fs26.mkdir(path30.dirname(outputPath), { recursive: true });
29570
- await fs26.writeFile(outputPath, html, "utf8");
29571
- return path30.resolve(outputPath);
29895
+ await fs27.mkdir(path31.dirname(outputPath), { recursive: true });
29896
+ await fs27.writeFile(outputPath, html, "utf8");
29897
+ return path31.resolve(outputPath);
29572
29898
  }
29573
29899
  export {
29900
+ ALL_MIGRATIONS,
29574
29901
  DEFAULT_CONSOLIDATION_CONFIG,
29575
29902
  DEFAULT_HALF_LIFE_DAYS,
29576
29903
  DEFAULT_HALF_LIFE_DAYS_BY_SOURCE_CLASS,
@@ -29578,6 +29905,7 @@ export {
29578
29905
  DEFAULT_REDACTION_PATTERNS,
29579
29906
  DEFAULT_STALE_THRESHOLD,
29580
29907
  LARGE_REPO_NODE_THRESHOLD,
29908
+ OPENAI_COMPATIBLE_CAPABILITY_MATRIX,
29581
29909
  acceptApproval,
29582
29910
  addInput,
29583
29911
  addManagedSource,
@@ -29602,6 +29930,7 @@ export {
29602
29930
  defaultVaultConfig,
29603
29931
  defaultVaultSchema,
29604
29932
  deleteManagedSource,
29933
+ detectVaultVersion,
29605
29934
  estimatePageTokens,
29606
29935
  estimateTokens,
29607
29936
  evaluateCandidateForPromotion,
@@ -29643,9 +29972,11 @@ export {
29643
29972
  loadVaultConfig,
29644
29973
  loadVaultSchema,
29645
29974
  loadVaultSchemas,
29975
+ lookupPresetCapabilities,
29646
29976
  markSuperseded,
29647
29977
  pathGraphVault,
29648
29978
  persistDecayFrontmatter,
29979
+ planMigration,
29649
29980
  previewCandidatePromotions,
29650
29981
  promoteCandidate,
29651
29982
  pushGraphNeo4j,
@@ -29671,6 +30002,7 @@ export {
29671
30002
  runAutoPromotion,
29672
30003
  runConsolidation,
29673
30004
  runDecayPass,
30005
+ runMigration,
29674
30006
  runSchedule,
29675
30007
  runWatchCycle,
29676
30008
  searchVault,
@@ -29683,5 +30015,6 @@ export {
29683
30015
  synthesizeHyperedgeHubs,
29684
30016
  trimToTokenBudget,
29685
30017
  uninstallGitHooks,
29686
- watchVault
30018
+ watchVault,
30019
+ withCapabilityFallback
29687
30020
  };