@swarmvaultai/engine 0.5.0 → 0.6.1
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/chunk-FD3LJQ4T.js +1216 -0
- package/dist/chunk-OK5752AP.js +1325 -0
- package/dist/index.d.ts +68 -12
- package/dist/index.js +1274 -461
- package/dist/registry-TYROWPR5.js +12 -0
- package/dist/registry-XOPLQNZY.js +12 -0
- package/package.json +7 -7
- package/LICENSE +0 -21
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
uniqueBy,
|
|
22
22
|
writeFileIfChanged,
|
|
23
23
|
writeJsonFile
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-OK5752AP.js";
|
|
25
25
|
|
|
26
26
|
// src/agents.ts
|
|
27
27
|
import crypto from "crypto";
|
|
@@ -8502,8 +8502,8 @@ async function readExtractionArtifact(rootDir, manifest) {
|
|
|
8502
8502
|
}
|
|
8503
8503
|
|
|
8504
8504
|
// src/mcp.ts
|
|
8505
|
-
import
|
|
8506
|
-
import
|
|
8505
|
+
import fs20 from "fs/promises";
|
|
8506
|
+
import path24 from "path";
|
|
8507
8507
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8508
8508
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8509
8509
|
import { z as z8 } from "zod";
|
|
@@ -8616,8 +8616,8 @@ function buildSchemaPrompt(schema, instruction) {
|
|
|
8616
8616
|
}
|
|
8617
8617
|
|
|
8618
8618
|
// src/vault.ts
|
|
8619
|
-
import
|
|
8620
|
-
import
|
|
8619
|
+
import fs19 from "fs/promises";
|
|
8620
|
+
import path23 from "path";
|
|
8621
8621
|
import matter9 from "gray-matter";
|
|
8622
8622
|
import { z as z7 } from "zod";
|
|
8623
8623
|
|
|
@@ -10579,6 +10579,43 @@ import matter5 from "gray-matter";
|
|
|
10579
10579
|
function uniqueStrings2(values) {
|
|
10580
10580
|
return uniqueBy(values.filter(Boolean), (value) => value);
|
|
10581
10581
|
}
|
|
10582
|
+
var GUIDED_SOURCE_MARKER_PREFIX = "<!-- swarmvault-guided-source:";
|
|
10583
|
+
var GUIDED_SOURCE_START_SUFFIX = ":start -->";
|
|
10584
|
+
var GUIDED_SOURCE_END_SUFFIX = ":end -->";
|
|
10585
|
+
function extractGuidedSourceBlocks(content) {
|
|
10586
|
+
if (!content) {
|
|
10587
|
+
return [];
|
|
10588
|
+
}
|
|
10589
|
+
const blocks = [];
|
|
10590
|
+
let cursor = 0;
|
|
10591
|
+
while (cursor < content.length) {
|
|
10592
|
+
const startIndex = content.indexOf(GUIDED_SOURCE_MARKER_PREFIX, cursor);
|
|
10593
|
+
if (startIndex === -1) {
|
|
10594
|
+
break;
|
|
10595
|
+
}
|
|
10596
|
+
const scopeEndIndex = content.indexOf(GUIDED_SOURCE_START_SUFFIX, startIndex);
|
|
10597
|
+
if (scopeEndIndex === -1) {
|
|
10598
|
+
break;
|
|
10599
|
+
}
|
|
10600
|
+
const scopeId = content.slice(startIndex + GUIDED_SOURCE_MARKER_PREFIX.length, scopeEndIndex);
|
|
10601
|
+
const endMarker = `${GUIDED_SOURCE_MARKER_PREFIX}${scopeId}${GUIDED_SOURCE_END_SUFFIX}`;
|
|
10602
|
+
const endIndex = content.indexOf(endMarker, scopeEndIndex);
|
|
10603
|
+
if (endIndex === -1) {
|
|
10604
|
+
break;
|
|
10605
|
+
}
|
|
10606
|
+
const blockEnd = endIndex + endMarker.length;
|
|
10607
|
+
blocks.push(content.slice(startIndex, blockEnd).trim());
|
|
10608
|
+
cursor = blockEnd;
|
|
10609
|
+
}
|
|
10610
|
+
return uniqueStrings2(blocks);
|
|
10611
|
+
}
|
|
10612
|
+
function appendGuidedSourceBlocks(body, existingContent) {
|
|
10613
|
+
const blocks = extractGuidedSourceBlocks(existingContent);
|
|
10614
|
+
if (!blocks.length) {
|
|
10615
|
+
return body;
|
|
10616
|
+
}
|
|
10617
|
+
return [body.trimEnd(), "", "## Guided Session Notes", "", ...blocks, ""].join("\n");
|
|
10618
|
+
}
|
|
10582
10619
|
function safeFrontmatter(value) {
|
|
10583
10620
|
return JSON.parse(JSON.stringify(value));
|
|
10584
10621
|
}
|
|
@@ -10667,7 +10704,7 @@ function detailList(manifest, key) {
|
|
|
10667
10704
|
const items = value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
10668
10705
|
return items.length ? items : void 0;
|
|
10669
10706
|
}
|
|
10670
|
-
function buildSourcePage(manifest, analysis, schemaHash, metadata, relatedOutputs = [], modulePage, decorations) {
|
|
10707
|
+
function buildSourcePage(manifest, analysis, schemaHash, metadata, relatedOutputs = [], modulePage, decorations, existingContent) {
|
|
10671
10708
|
const relativePath = pagePathFor("source", manifest.sourceId);
|
|
10672
10709
|
const pageId = `source:${manifest.sourceId}`;
|
|
10673
10710
|
const { sourceHashes, sourceSemanticHashes } = sourceHashesForManifest(manifest);
|
|
@@ -10709,61 +10746,64 @@ function buildSourcePage(manifest, analysis, schemaHash, metadata, relatedOutput
|
|
|
10709
10746
|
schema_hash: schemaHash,
|
|
10710
10747
|
...sourceHashFrontmatter(sourceHashes, sourceSemanticHashes)
|
|
10711
10748
|
};
|
|
10712
|
-
const body =
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10749
|
+
const body = appendGuidedSourceBlocks(
|
|
10750
|
+
[
|
|
10751
|
+
`# ${analysis.title}`,
|
|
10752
|
+
"",
|
|
10753
|
+
`Source ID: \`${manifest.sourceId}\``,
|
|
10754
|
+
`Source Kind: \`${manifest.sourceKind}\``,
|
|
10755
|
+
manifest.url ? `Source URL: ${manifest.url}` : `Source Path: \`${manifest.originalPath ?? manifest.storedPath}\``,
|
|
10756
|
+
...manifest.sourceType ? [`Source Type: \`${manifest.sourceType}\``, ""] : [""],
|
|
10757
|
+
...manifest.sourceClass ? [`Source Class: \`${manifest.sourceClass}\``, ""] : [],
|
|
10758
|
+
...manifest.sourceGroupTitle ? [`Source Group: ${manifest.sourceGroupTitle}`] : [],
|
|
10759
|
+
...manifest.partTitle ? [`Part: ${manifest.partIndex ?? "?"}/${manifest.partCount ?? "?"} - ${manifest.partTitle}`] : [],
|
|
10760
|
+
...manifest.details && Object.keys(manifest.details).length ? [
|
|
10761
|
+
"",
|
|
10762
|
+
"## Source Details",
|
|
10763
|
+
"",
|
|
10764
|
+
...Object.entries(manifest.details).map(([key, value]) => `- ${key.replace(/_/g, " ")}: ${value}`),
|
|
10765
|
+
""
|
|
10766
|
+
] : [],
|
|
10723
10767
|
"",
|
|
10724
|
-
"##
|
|
10768
|
+
"## Summary",
|
|
10725
10769
|
"",
|
|
10726
|
-
|
|
10727
|
-
""
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10770
|
+
analysis.summary,
|
|
10771
|
+
"",
|
|
10772
|
+
...analysis.code ? [
|
|
10773
|
+
"## Code Module",
|
|
10774
|
+
"",
|
|
10775
|
+
`- Language: \`${analysis.code.language}\``,
|
|
10776
|
+
modulePage ? `- Module Page: [[${modulePage.path.replace(/\.md$/, "")}|${modulePage.title}]]` : "- Module Page: Not generated.",
|
|
10777
|
+
`- Exports: ${analysis.code.exports.length ? analysis.code.exports.join(", ") : "None detected."}`,
|
|
10778
|
+
`- Symbols: ${analysis.code.symbols.length ? analysis.code.symbols.map((symbol) => symbol.name).join(", ") : "None detected."}`,
|
|
10779
|
+
analysis.code.diagnostics.length ? `- Diagnostics: ${analysis.code.diagnostics.length}` : "- Diagnostics: None.",
|
|
10780
|
+
""
|
|
10781
|
+
] : [],
|
|
10782
|
+
"## Concepts",
|
|
10736
10783
|
"",
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10784
|
+
...analysis.concepts.length ? analysis.concepts.map(
|
|
10785
|
+
(item) => `- [[${pagePathFor("concept", slugify(item.name)).replace(/\.md$/, "")}|${item.name}]]: ${item.description}`
|
|
10786
|
+
) : ["- None detected."],
|
|
10787
|
+
"",
|
|
10788
|
+
"## Entities",
|
|
10789
|
+
"",
|
|
10790
|
+
...analysis.entities.length ? analysis.entities.map(
|
|
10791
|
+
(item) => `- [[${pagePathFor("entity", slugify(item.name)).replace(/\.md$/, "")}|${item.name}]]: ${item.description}`
|
|
10792
|
+
) : ["- None detected."],
|
|
10793
|
+
"",
|
|
10794
|
+
"## Claims",
|
|
10795
|
+
"",
|
|
10796
|
+
...analysis.claims.length ? analysis.claims.map((claim) => `- ${claim.text} [source:${claim.citation}]`) : ["- No claims extracted."],
|
|
10797
|
+
"",
|
|
10798
|
+
"## Questions",
|
|
10799
|
+
"",
|
|
10800
|
+
...analysis.questions.length ? analysis.questions.map((question) => `- ${question}`) : ["- No follow-up questions yet."],
|
|
10801
|
+
"",
|
|
10802
|
+
...relatedOutputsSection(relatedOutputs),
|
|
10742
10803
|
""
|
|
10743
|
-
]
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
...analysis.concepts.length ? analysis.concepts.map(
|
|
10747
|
-
(item) => `- [[${pagePathFor("concept", slugify(item.name)).replace(/\.md$/, "")}|${item.name}]]: ${item.description}`
|
|
10748
|
-
) : ["- None detected."],
|
|
10749
|
-
"",
|
|
10750
|
-
"## Entities",
|
|
10751
|
-
"",
|
|
10752
|
-
...analysis.entities.length ? analysis.entities.map(
|
|
10753
|
-
(item) => `- [[${pagePathFor("entity", slugify(item.name)).replace(/\.md$/, "")}|${item.name}]]: ${item.description}`
|
|
10754
|
-
) : ["- None detected."],
|
|
10755
|
-
"",
|
|
10756
|
-
"## Claims",
|
|
10757
|
-
"",
|
|
10758
|
-
...analysis.claims.length ? analysis.claims.map((claim) => `- ${claim.text} [source:${claim.citation}]`) : ["- No claims extracted."],
|
|
10759
|
-
"",
|
|
10760
|
-
"## Questions",
|
|
10761
|
-
"",
|
|
10762
|
-
...analysis.questions.length ? analysis.questions.map((question) => `- ${question}`) : ["- No follow-up questions yet."],
|
|
10763
|
-
"",
|
|
10764
|
-
...relatedOutputsSection(relatedOutputs),
|
|
10765
|
-
""
|
|
10766
|
-
].join("\n");
|
|
10804
|
+
].join("\n"),
|
|
10805
|
+
existingContent
|
|
10806
|
+
);
|
|
10767
10807
|
return {
|
|
10768
10808
|
page: {
|
|
10769
10809
|
id: pageId,
|
|
@@ -10943,7 +10983,7 @@ function buildModulePage(input) {
|
|
|
10943
10983
|
content: matter5.stringify(body, frontmatter)
|
|
10944
10984
|
};
|
|
10945
10985
|
}
|
|
10946
|
-
function buildAggregatePage(kind, name, descriptions, sourceAnalyses, sourceHashes, sourceSemanticHashes, schemaHash, metadata, relativePath, relatedOutputs = [], decorations) {
|
|
10986
|
+
function buildAggregatePage(kind, name, descriptions, sourceAnalyses, sourceHashes, sourceSemanticHashes, schemaHash, metadata, relativePath, relatedOutputs = [], decorations, existingContent) {
|
|
10947
10987
|
const slug = slugify(name);
|
|
10948
10988
|
const pageId = `${kind}:${slug}`;
|
|
10949
10989
|
const sourceIds = sourceAnalyses.map((item) => item.sourceId);
|
|
@@ -10969,26 +11009,29 @@ function buildAggregatePage(kind, name, descriptions, sourceAnalyses, sourceHash
|
|
|
10969
11009
|
schema_hash: schemaHash,
|
|
10970
11010
|
...sourceHashFrontmatter(sourceHashes, sourceSemanticHashes)
|
|
10971
11011
|
};
|
|
10972
|
-
const body =
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
11012
|
+
const body = appendGuidedSourceBlocks(
|
|
11013
|
+
[
|
|
11014
|
+
`# ${name}`,
|
|
11015
|
+
"",
|
|
11016
|
+
"## Summary",
|
|
11017
|
+
"",
|
|
11018
|
+
summary,
|
|
11019
|
+
"",
|
|
11020
|
+
"## Seen In",
|
|
11021
|
+
"",
|
|
11022
|
+
...sourceAnalyses.map((item) => `- [[${pagePathFor("source", item.sourceId).replace(/\.md$/, "")}|${item.title}]]`),
|
|
11023
|
+
"",
|
|
11024
|
+
"## Source Claims",
|
|
11025
|
+
"",
|
|
11026
|
+
...sourceAnalyses.flatMap(
|
|
11027
|
+
(item) => item.claims.filter((claim) => claim.text.toLowerCase().includes(name.toLowerCase())).map((claim) => `- ${claim.text} [source:${claim.citation}]`)
|
|
11028
|
+
),
|
|
11029
|
+
"",
|
|
11030
|
+
...relatedOutputsSection(relatedOutputs),
|
|
11031
|
+
""
|
|
11032
|
+
].join("\n"),
|
|
11033
|
+
existingContent
|
|
11034
|
+
);
|
|
10992
11035
|
return {
|
|
10993
11036
|
page: {
|
|
10994
11037
|
id: pageId,
|
|
@@ -11137,15 +11180,15 @@ function sourceTypeForNode(node, pagesById) {
|
|
|
11137
11180
|
return pagesById.get(node.pageId)?.sourceType;
|
|
11138
11181
|
}
|
|
11139
11182
|
function supportingPathDetails(graph, edge) {
|
|
11140
|
-
const
|
|
11183
|
+
const path29 = shortestGraphPath(graph, edge.source, edge.target);
|
|
11141
11184
|
const edgesById = new Map(graph.edges.map((item) => [item.id, item]));
|
|
11142
|
-
const pathEdges =
|
|
11185
|
+
const pathEdges = path29.edgeIds.map((edgeId) => edgesById.get(edgeId)).filter((item) => Boolean(item));
|
|
11143
11186
|
return {
|
|
11144
|
-
pathNodeIds:
|
|
11145
|
-
pathEdgeIds:
|
|
11187
|
+
pathNodeIds: path29.nodeIds,
|
|
11188
|
+
pathEdgeIds: path29.edgeIds,
|
|
11146
11189
|
pathRelations: pathEdges.map((item) => item.relation),
|
|
11147
11190
|
pathEvidenceClasses: pathEdges.map((item) => item.evidenceClass),
|
|
11148
|
-
pathSummary:
|
|
11191
|
+
pathSummary: path29.summary
|
|
11149
11192
|
};
|
|
11150
11193
|
}
|
|
11151
11194
|
function surpriseScore(edge, graph, pagesById, hyperedgesByNodeId) {
|
|
@@ -11214,7 +11257,7 @@ function topSurprisingConnections(graph, pagesById) {
|
|
|
11214
11257
|
}).map((edge) => {
|
|
11215
11258
|
const source = nodesById.get(edge.source);
|
|
11216
11259
|
const target = nodesById.get(edge.target);
|
|
11217
|
-
const
|
|
11260
|
+
const path29 = supportingPathDetails(graph, edge);
|
|
11218
11261
|
const scored = surpriseScore(edge, graph, pagesById, hyperedgesByNodeId);
|
|
11219
11262
|
return {
|
|
11220
11263
|
id: edge.id,
|
|
@@ -11225,11 +11268,11 @@ function topSurprisingConnections(graph, pagesById) {
|
|
|
11225
11268
|
relation: edge.relation,
|
|
11226
11269
|
evidenceClass: edge.evidenceClass,
|
|
11227
11270
|
confidence: edge.confidence,
|
|
11228
|
-
pathNodeIds:
|
|
11229
|
-
pathEdgeIds:
|
|
11230
|
-
pathRelations:
|
|
11231
|
-
pathEvidenceClasses:
|
|
11232
|
-
pathSummary:
|
|
11271
|
+
pathNodeIds: path29.pathNodeIds,
|
|
11272
|
+
pathEdgeIds: path29.pathEdgeIds,
|
|
11273
|
+
pathRelations: path29.pathRelations,
|
|
11274
|
+
pathEvidenceClasses: path29.pathEvidenceClasses,
|
|
11275
|
+
pathSummary: path29.pathSummary,
|
|
11233
11276
|
why: scored.why,
|
|
11234
11277
|
explanation: scored.explanation,
|
|
11235
11278
|
surpriseScore: scored.score
|
|
@@ -11744,7 +11787,8 @@ function buildOutputPage(input) {
|
|
|
11744
11787
|
question: input.question,
|
|
11745
11788
|
output_format: input.outputFormat,
|
|
11746
11789
|
output_assets: outputAssets,
|
|
11747
|
-
...input.outputFormat === "slides" ? { marp: true } : {}
|
|
11790
|
+
...input.outputFormat === "slides" ? { marp: true } : {},
|
|
11791
|
+
...input.frontmatter ?? {}
|
|
11748
11792
|
};
|
|
11749
11793
|
return {
|
|
11750
11794
|
page: {
|
|
@@ -11832,7 +11876,7 @@ function buildOutputPage(input) {
|
|
|
11832
11876
|
...input.citations.map((citation) => `- [source:${citation}]`),
|
|
11833
11877
|
""
|
|
11834
11878
|
]).join("\n"),
|
|
11835
|
-
frontmatter
|
|
11879
|
+
safeFrontmatter(frontmatter)
|
|
11836
11880
|
)
|
|
11837
11881
|
};
|
|
11838
11882
|
}
|
|
@@ -12691,6 +12735,58 @@ function searchPages(dbPath, query, limitOrOptions = 5) {
|
|
|
12691
12735
|
}));
|
|
12692
12736
|
}
|
|
12693
12737
|
|
|
12738
|
+
// src/source-sessions.ts
|
|
12739
|
+
import fs18 from "fs/promises";
|
|
12740
|
+
import path22 from "path";
|
|
12741
|
+
function sessionStatePathFor(paths, sessionId) {
|
|
12742
|
+
return path22.join(paths.sourceSessionsDir, `${sessionId}.json`);
|
|
12743
|
+
}
|
|
12744
|
+
async function listGuidedSourceSessions(rootDir) {
|
|
12745
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12746
|
+
const entries = await fs18.readdir(paths.sourceSessionsDir, { withFileTypes: true }).catch(() => []);
|
|
12747
|
+
const sessions = await Promise.all(
|
|
12748
|
+
entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => await readJsonFile(path22.join(paths.sourceSessionsDir, entry.name)))
|
|
12749
|
+
);
|
|
12750
|
+
return sessions.filter((session) => Boolean(session)).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
12751
|
+
}
|
|
12752
|
+
async function readGuidedSourceSession(rootDir, sessionId) {
|
|
12753
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12754
|
+
return await readJsonFile(sessionStatePathFor(paths, sessionId));
|
|
12755
|
+
}
|
|
12756
|
+
async function findLatestGuidedSourceSessionByScope(rootDir, scopeId) {
|
|
12757
|
+
const sessions = await listGuidedSourceSessions(rootDir);
|
|
12758
|
+
return sessions.find((session) => session.scopeId === scopeId) ?? null;
|
|
12759
|
+
}
|
|
12760
|
+
async function writeGuidedSourceSession(rootDir, session) {
|
|
12761
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12762
|
+
await ensureDir(paths.sourceSessionsDir);
|
|
12763
|
+
const next = {
|
|
12764
|
+
...session,
|
|
12765
|
+
updatedAt: session.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
12766
|
+
};
|
|
12767
|
+
const filePath = sessionStatePathFor(paths, session.sessionId);
|
|
12768
|
+
await fs18.writeFile(filePath, `${JSON.stringify(next, null, 2)}
|
|
12769
|
+
`, "utf8");
|
|
12770
|
+
return filePath;
|
|
12771
|
+
}
|
|
12772
|
+
async function updateGuidedSourceSessionStatus(rootDir, sessionId, status) {
|
|
12773
|
+
const existing = await readGuidedSourceSession(rootDir, sessionId);
|
|
12774
|
+
if (!existing) {
|
|
12775
|
+
return null;
|
|
12776
|
+
}
|
|
12777
|
+
const next = {
|
|
12778
|
+
...existing,
|
|
12779
|
+
status,
|
|
12780
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12781
|
+
};
|
|
12782
|
+
await writeGuidedSourceSession(rootDir, next);
|
|
12783
|
+
return next;
|
|
12784
|
+
}
|
|
12785
|
+
async function guidedSourceSessionStatePath(rootDir, sessionId) {
|
|
12786
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12787
|
+
return sessionStatePathFor(paths, sessionId);
|
|
12788
|
+
}
|
|
12789
|
+
|
|
12694
12790
|
// src/vault.ts
|
|
12695
12791
|
var COMPILE_PROGRESS_THRESHOLD = 120;
|
|
12696
12792
|
var COMPILE_PROGRESS_UPDATE_INTERVAL = 50;
|
|
@@ -12745,7 +12841,7 @@ function outputFormatInstruction(format) {
|
|
|
12745
12841
|
}
|
|
12746
12842
|
}
|
|
12747
12843
|
function outputAssetPath(slug, fileName) {
|
|
12748
|
-
return toPosix(
|
|
12844
|
+
return toPosix(path23.join("outputs", "assets", slug, fileName));
|
|
12749
12845
|
}
|
|
12750
12846
|
function outputAssetId(slug, role) {
|
|
12751
12847
|
return `output:${slug}:asset:${role}`;
|
|
@@ -12885,7 +12981,7 @@ async function resolveImageGenerationProvider(rootDir) {
|
|
|
12885
12981
|
if (!providerConfig) {
|
|
12886
12982
|
throw new Error(`No provider configured with id "${preferredProviderId}" for task "imageProvider".`);
|
|
12887
12983
|
}
|
|
12888
|
-
const { createProvider: createProvider2 } = await import("./registry-
|
|
12984
|
+
const { createProvider: createProvider2 } = await import("./registry-TYROWPR5.js");
|
|
12889
12985
|
return createProvider2(preferredProviderId, providerConfig, rootDir);
|
|
12890
12986
|
}
|
|
12891
12987
|
async function generateOutputArtifacts(rootDir, input) {
|
|
@@ -13083,7 +13179,7 @@ async function generateOutputArtifacts(rootDir, input) {
|
|
|
13083
13179
|
};
|
|
13084
13180
|
}
|
|
13085
13181
|
function normalizeProjectRoot(root) {
|
|
13086
|
-
const normalized = toPosix(
|
|
13182
|
+
const normalized = toPosix(path23.posix.normalize(root.replace(/\\/g, "/"))).replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
13087
13183
|
return normalized;
|
|
13088
13184
|
}
|
|
13089
13185
|
function projectEntries(config) {
|
|
@@ -13109,10 +13205,10 @@ function manifestPathForProject(rootDir, manifest) {
|
|
|
13109
13205
|
if (!rawPath) {
|
|
13110
13206
|
return toPosix(manifest.storedPath);
|
|
13111
13207
|
}
|
|
13112
|
-
if (!
|
|
13208
|
+
if (!path23.isAbsolute(rawPath)) {
|
|
13113
13209
|
return normalizeProjectRoot(rawPath);
|
|
13114
13210
|
}
|
|
13115
|
-
const relative = toPosix(
|
|
13211
|
+
const relative = toPosix(path23.relative(rootDir, rawPath));
|
|
13116
13212
|
return relative.startsWith("..") ? toPosix(rawPath) : normalizeProjectRoot(relative);
|
|
13117
13213
|
}
|
|
13118
13214
|
function prefixMatches(value, prefix) {
|
|
@@ -13265,6 +13361,7 @@ function approvalSummary(manifest) {
|
|
|
13265
13361
|
createdAt: manifest.createdAt,
|
|
13266
13362
|
bundleType: manifest.bundleType,
|
|
13267
13363
|
title: manifest.title,
|
|
13364
|
+
sourceSessionId: manifest.sourceSessionId,
|
|
13268
13365
|
entryCount: manifest.entries.length,
|
|
13269
13366
|
pendingCount: manifest.entries.filter((entry) => entry.status === "pending").length,
|
|
13270
13367
|
acceptedCount: manifest.entries.filter((entry) => entry.status === "accepted").length,
|
|
@@ -13288,7 +13385,8 @@ function pageHashes(pages) {
|
|
|
13288
13385
|
return Object.fromEntries(pages.map((page) => [page.page.id, page.contentHash]));
|
|
13289
13386
|
}
|
|
13290
13387
|
async function buildManagedGraphPage(absolutePath, defaults, build) {
|
|
13291
|
-
const existingContent = await fileExists(absolutePath) ? await
|
|
13388
|
+
const existingContent = await fileExists(absolutePath) ? await fs19.readFile(absolutePath, "utf8") : null;
|
|
13389
|
+
let carriedContent = existingContent;
|
|
13292
13390
|
let existing = await loadExistingManagedPageState(absolutePath, {
|
|
13293
13391
|
status: defaults.status ?? "active",
|
|
13294
13392
|
managedBy: defaults.managedBy
|
|
@@ -13303,6 +13401,7 @@ async function buildManagedGraphPage(absolutePath, defaults, build) {
|
|
|
13303
13401
|
status: defaults.status ?? "active",
|
|
13304
13402
|
managedBy: defaults.managedBy
|
|
13305
13403
|
});
|
|
13404
|
+
carriedContent = await fs19.readFile(candidatePath, "utf8");
|
|
13306
13405
|
usedFallbackState = true;
|
|
13307
13406
|
break;
|
|
13308
13407
|
}
|
|
@@ -13315,18 +13414,18 @@ async function buildManagedGraphPage(absolutePath, defaults, build) {
|
|
|
13315
13414
|
managedBy: defaults.managedBy,
|
|
13316
13415
|
confidence: defaults.confidence
|
|
13317
13416
|
};
|
|
13318
|
-
let built = build(metadata);
|
|
13319
|
-
if (
|
|
13417
|
+
let built = build(metadata, carriedContent);
|
|
13418
|
+
if (carriedContent && carriedContent !== built.content) {
|
|
13320
13419
|
metadata = {
|
|
13321
13420
|
...metadata,
|
|
13322
13421
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13323
13422
|
};
|
|
13324
|
-
built = build(metadata);
|
|
13423
|
+
built = build(metadata, carriedContent);
|
|
13325
13424
|
}
|
|
13326
13425
|
return built;
|
|
13327
13426
|
}
|
|
13328
13427
|
async function buildManagedContent(absolutePath, defaults, build) {
|
|
13329
|
-
const existingContent = await fileExists(absolutePath) ? await
|
|
13428
|
+
const existingContent = await fileExists(absolutePath) ? await fs19.readFile(absolutePath, "utf8") : null;
|
|
13330
13429
|
let existing = await loadExistingManagedPageState(absolutePath, {
|
|
13331
13430
|
status: defaults.status ?? "active",
|
|
13332
13431
|
managedBy: defaults.managedBy
|
|
@@ -13368,15 +13467,19 @@ function manifestDetailValue(manifest, key) {
|
|
|
13368
13467
|
}
|
|
13369
13468
|
async function loadAnalysesBySourceIds(paths, sourceIds) {
|
|
13370
13469
|
const analyses = await Promise.all(
|
|
13371
|
-
sourceIds.map(async (sourceId) => await readJsonFile(
|
|
13470
|
+
sourceIds.map(async (sourceId) => await readJsonFile(path23.join(paths.analysesDir, `${sourceId}.json`)))
|
|
13372
13471
|
);
|
|
13373
13472
|
return analyses.filter((analysis) => Boolean(analysis?.sourceId));
|
|
13374
13473
|
}
|
|
13375
|
-
async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
13474
|
+
async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
|
|
13475
|
+
const dataviewEnabled = config.profile.dataviewBlocks;
|
|
13476
|
+
const profilePresets = config.profile.presets;
|
|
13477
|
+
const dashboardPack = config.profile.dashboardPack;
|
|
13376
13478
|
const sourcePages = graph.pages.filter((page) => page.kind === "source");
|
|
13377
13479
|
const reviewPages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-reviews/"));
|
|
13378
13480
|
const briefPages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-briefs/"));
|
|
13379
13481
|
const guidePages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-guides/"));
|
|
13482
|
+
const sessionPages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-sessions/"));
|
|
13380
13483
|
const conceptPages = graph.pages.filter((page) => page.kind === "concept" && page.status !== "candidate").slice(0, 16);
|
|
13381
13484
|
const entityPages = graph.pages.filter((page) => page.kind === "entity" && page.status !== "candidate").slice(0, 16);
|
|
13382
13485
|
const manifests = graph.sources;
|
|
@@ -13387,9 +13490,12 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13387
13490
|
const openQuestions = uniqueStrings3(
|
|
13388
13491
|
analyses.flatMap((analysis) => analysis.questions.map((question) => `${analysis.title}: ${question}`))
|
|
13389
13492
|
).slice(0, 20);
|
|
13493
|
+
const sourceSessions = await listGuidedSourceSessions(paths.rootDir);
|
|
13390
13494
|
const stagedGuideBundles = (await Promise.all(
|
|
13391
|
-
(await
|
|
13392
|
-
)).filter((manifest) => Boolean(manifest)).filter((manifest) => manifest.bundleType === "guided_source").sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, 12);
|
|
13495
|
+
(await fs19.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => await readJsonFile(approvalManifestPath(paths, entry.name)))
|
|
13496
|
+
)).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);
|
|
13497
|
+
const readerFocusPages = uniqueBy([...guidePages, ...briefPages, ...conceptPages, ...entityPages], (page) => page.id).slice(0, 8);
|
|
13498
|
+
const diligenceSessions = sourceSessions.filter((session) => session.status === "staged" || session.status === "awaiting_input").slice(0, 8);
|
|
13393
13499
|
const dashboards = [
|
|
13394
13500
|
{
|
|
13395
13501
|
relativePath: "dashboards/index.md",
|
|
@@ -13401,17 +13507,23 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13401
13507
|
"- [[dashboards/recent-sources|Recent Sources]]",
|
|
13402
13508
|
"- [[dashboards/reading-log|Reading Log]]",
|
|
13403
13509
|
"- [[dashboards/timeline|Timeline]]",
|
|
13510
|
+
"- [[dashboards/source-sessions|Source Sessions]]",
|
|
13404
13511
|
"- [[dashboards/source-guides|Source Guides]]",
|
|
13405
13512
|
"- [[dashboards/research-map|Research Map]]",
|
|
13406
13513
|
"- [[dashboards/contradictions|Contradictions]]",
|
|
13407
13514
|
"- [[dashboards/open-questions|Open Questions]]",
|
|
13408
13515
|
"",
|
|
13409
|
-
"
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
|
|
13516
|
+
`Profile Presets: ${profilePresets.length ? profilePresets.map((preset) => `\`${preset}\``).join(", ") : "_default_"}`,
|
|
13517
|
+
`Dashboard Pack: \`${dashboardPack}\``,
|
|
13518
|
+
...dataviewEnabled ? [
|
|
13519
|
+
"",
|
|
13520
|
+
"```dataview",
|
|
13521
|
+
"TABLE file.mtime AS updated",
|
|
13522
|
+
'FROM "dashboards"',
|
|
13523
|
+
'WHERE file.name != "index"',
|
|
13524
|
+
"SORT file.mtime desc",
|
|
13525
|
+
"```"
|
|
13526
|
+
] : [],
|
|
13415
13527
|
""
|
|
13416
13528
|
].join("\n"),
|
|
13417
13529
|
{
|
|
@@ -13432,7 +13544,8 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13432
13544
|
backlinks: [],
|
|
13433
13545
|
schema_hash: schemaHash,
|
|
13434
13546
|
source_hashes: {},
|
|
13435
|
-
source_semantic_hashes: {}
|
|
13547
|
+
source_semantic_hashes: {},
|
|
13548
|
+
profile_presets: profilePresets
|
|
13436
13549
|
}
|
|
13437
13550
|
)
|
|
13438
13551
|
},
|
|
@@ -13444,13 +13557,16 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13444
13557
|
"# Recent Sources",
|
|
13445
13558
|
"",
|
|
13446
13559
|
...recentSourcePages.length ? recentSourcePages.map((page) => `- ${page.updatedAt}: [[${page.path.replace(/\.md$/, "")}|${page.title}]]`) : ["- No source pages yet."],
|
|
13447
|
-
"",
|
|
13448
|
-
|
|
13449
|
-
|
|
13450
|
-
|
|
13451
|
-
|
|
13452
|
-
|
|
13453
|
-
|
|
13560
|
+
...dashboardPack === "reader" && readerFocusPages.length ? ["", "## Reader Focus", "", ...readerFocusPages.map((page) => `- [[${page.path.replace(/\.md$/, "")}|${page.title}]]`)] : [],
|
|
13561
|
+
...dataviewEnabled ? [
|
|
13562
|
+
"",
|
|
13563
|
+
"```dataview",
|
|
13564
|
+
"TABLE source_type, occurred_at, participants",
|
|
13565
|
+
'FROM "sources"',
|
|
13566
|
+
"SORT updated_at desc",
|
|
13567
|
+
"LIMIT 25",
|
|
13568
|
+
"```"
|
|
13569
|
+
] : [],
|
|
13454
13570
|
""
|
|
13455
13571
|
].join("\n"),
|
|
13456
13572
|
{
|
|
@@ -13471,7 +13587,8 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13471
13587
|
backlinks: [],
|
|
13472
13588
|
schema_hash: schemaHash,
|
|
13473
13589
|
source_hashes: {},
|
|
13474
|
-
source_semantic_hashes: {}
|
|
13590
|
+
source_semantic_hashes: {},
|
|
13591
|
+
profile_presets: profilePresets
|
|
13475
13592
|
}
|
|
13476
13593
|
)
|
|
13477
13594
|
},
|
|
@@ -13487,13 +13604,29 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13487
13604
|
const participants = manifestDetailValue(manifest, "participants");
|
|
13488
13605
|
return `- ${occurredAt}: ${manifest.title}${participants ? ` (${participants})` : ""}`;
|
|
13489
13606
|
}) : recentSourcePages.map((page) => `- ${page.updatedAt}: [[${page.path.replace(/\.md$/, "")}|${page.title}]]`),
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13607
|
+
...sourceSessions.length ? [
|
|
13608
|
+
"",
|
|
13609
|
+
"## Active Guided Sessions",
|
|
13610
|
+
"",
|
|
13611
|
+
...sourceSessions.slice(0, 8).map(
|
|
13612
|
+
(session) => `- ${session.updatedAt}: \`${session.status}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`
|
|
13613
|
+
)
|
|
13614
|
+
] : [],
|
|
13615
|
+
...dashboardPack === "reader" && conceptPages.length ? [
|
|
13616
|
+
"",
|
|
13617
|
+
"## Thesis And Hub Pages",
|
|
13618
|
+
"",
|
|
13619
|
+
...conceptPages.slice(0, 6).map((page) => `- [[${page.path.replace(/\.md$/, "")}|${page.title}]]`)
|
|
13620
|
+
] : [],
|
|
13621
|
+
...dataviewEnabled ? [
|
|
13622
|
+
"",
|
|
13623
|
+
"```dataview",
|
|
13624
|
+
"TABLE occurred_at, source_type, participants, container_title",
|
|
13625
|
+
'FROM "sources"',
|
|
13626
|
+
"SORT occurred_at desc",
|
|
13627
|
+
"LIMIT 25",
|
|
13628
|
+
"```"
|
|
13629
|
+
] : [],
|
|
13497
13630
|
""
|
|
13498
13631
|
].join("\n"),
|
|
13499
13632
|
{
|
|
@@ -13514,7 +13647,8 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13514
13647
|
backlinks: [],
|
|
13515
13648
|
schema_hash: schemaHash,
|
|
13516
13649
|
source_hashes: {},
|
|
13517
|
-
source_semantic_hashes: {}
|
|
13650
|
+
source_semantic_hashes: {},
|
|
13651
|
+
profile_presets: profilePresets
|
|
13518
13652
|
}
|
|
13519
13653
|
)
|
|
13520
13654
|
},
|
|
@@ -13530,13 +13664,15 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13530
13664
|
const sourcePage = sourcePages.find((page) => page.sourceIds.includes(manifest.sourceId));
|
|
13531
13665
|
return `- ${occurredAt}: ${sourcePage ? `[[${sourcePage.path.replace(/\.md$/, "")}|${sourcePage.title}]]` : manifest.title}`;
|
|
13532
13666
|
}) : ["- No timeline-aware sources yet."],
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13667
|
+
...dataviewEnabled ? [
|
|
13668
|
+
"",
|
|
13669
|
+
"```dataview",
|
|
13670
|
+
"TABLE occurred_at, participants, container_title",
|
|
13671
|
+
'FROM "sources"',
|
|
13672
|
+
"WHERE occurred_at",
|
|
13673
|
+
"SORT occurred_at desc",
|
|
13674
|
+
"```"
|
|
13675
|
+
] : [],
|
|
13540
13676
|
""
|
|
13541
13677
|
].join("\n"),
|
|
13542
13678
|
{
|
|
@@ -13557,7 +13693,65 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13557
13693
|
backlinks: [],
|
|
13558
13694
|
schema_hash: schemaHash,
|
|
13559
13695
|
source_hashes: {},
|
|
13560
|
-
source_semantic_hashes: {}
|
|
13696
|
+
source_semantic_hashes: {},
|
|
13697
|
+
profile_presets: profilePresets
|
|
13698
|
+
}
|
|
13699
|
+
)
|
|
13700
|
+
},
|
|
13701
|
+
{
|
|
13702
|
+
relativePath: "dashboards/source-sessions.md",
|
|
13703
|
+
title: "Source Sessions",
|
|
13704
|
+
content: (metadata) => matter9.stringify(
|
|
13705
|
+
[
|
|
13706
|
+
"# Source Sessions",
|
|
13707
|
+
"",
|
|
13708
|
+
"## Active Sessions",
|
|
13709
|
+
"",
|
|
13710
|
+
...sourceSessions.length ? sourceSessions.slice(0, 16).map(
|
|
13711
|
+
(session) => `- ${session.updatedAt}: \`${session.status}\` \`${session.sessionId}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`
|
|
13712
|
+
) : ["- No guided source sessions yet."],
|
|
13713
|
+
"",
|
|
13714
|
+
"## Pending Guided Bundles",
|
|
13715
|
+
"",
|
|
13716
|
+
...stagedGuideBundles.length ? stagedGuideBundles.map(
|
|
13717
|
+
(bundle) => `- ${bundle.createdAt}: \`${bundle.approvalId}\`${bundle.title ? ` ${bundle.title}` : ""} (${bundle.entries.length} staged entr${bundle.entries.length === 1 ? "y" : "ies"})`
|
|
13718
|
+
) : ["- No staged guided bundles right now."],
|
|
13719
|
+
...dataviewEnabled ? [
|
|
13720
|
+
"",
|
|
13721
|
+
"```dataview",
|
|
13722
|
+
"TABLE session_status, evidence_state, canonical_targets",
|
|
13723
|
+
'FROM "outputs/source-sessions"',
|
|
13724
|
+
"SORT file.mtime desc",
|
|
13725
|
+
"```"
|
|
13726
|
+
] : [],
|
|
13727
|
+
""
|
|
13728
|
+
].join("\n"),
|
|
13729
|
+
{
|
|
13730
|
+
page_id: "dashboards:source-sessions",
|
|
13731
|
+
kind: "index",
|
|
13732
|
+
title: "Source Sessions",
|
|
13733
|
+
tags: ["index", "dashboard", "source-sessions"],
|
|
13734
|
+
source_ids: uniqueStrings3([
|
|
13735
|
+
...sessionPages.flatMap((page) => page.sourceIds),
|
|
13736
|
+
...sourceSessions.flatMap((session) => session.sourceIds)
|
|
13737
|
+
]),
|
|
13738
|
+
project_ids: [],
|
|
13739
|
+
node_ids: [],
|
|
13740
|
+
freshness: "fresh",
|
|
13741
|
+
status: metadata.status,
|
|
13742
|
+
confidence: 1,
|
|
13743
|
+
created_at: metadata.createdAt,
|
|
13744
|
+
updated_at: metadata.updatedAt,
|
|
13745
|
+
compiled_from: uniqueStrings3([
|
|
13746
|
+
...sessionPages.flatMap((page) => page.sourceIds),
|
|
13747
|
+
...sourceSessions.flatMap((session) => session.sourceIds)
|
|
13748
|
+
]),
|
|
13749
|
+
managed_by: metadata.managedBy,
|
|
13750
|
+
backlinks: [],
|
|
13751
|
+
schema_hash: schemaHash,
|
|
13752
|
+
source_hashes: {},
|
|
13753
|
+
source_semantic_hashes: {},
|
|
13754
|
+
profile_presets: profilePresets
|
|
13561
13755
|
}
|
|
13562
13756
|
)
|
|
13563
13757
|
},
|
|
@@ -13575,11 +13769,14 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13575
13769
|
...stagedGuideBundles.length ? stagedGuideBundles.map(
|
|
13576
13770
|
(bundle) => `- ${bundle.createdAt}: \`${bundle.approvalId}\`${bundle.title ? ` ${bundle.title}` : ""} (${bundle.entries.length} staged entr${bundle.entries.length === 1 ? "y" : "ies"})`
|
|
13577
13771
|
) : ["- No staged guided bundles right now."],
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13772
|
+
...dataviewEnabled ? [
|
|
13773
|
+
"",
|
|
13774
|
+
"```dataview",
|
|
13775
|
+
"TABLE evidence_state, canonical_targets, file.mtime AS updated",
|
|
13776
|
+
'FROM "outputs/source-guides"',
|
|
13777
|
+
"SORT file.mtime desc",
|
|
13778
|
+
"```"
|
|
13779
|
+
] : [],
|
|
13583
13780
|
""
|
|
13584
13781
|
].join("\n"),
|
|
13585
13782
|
{
|
|
@@ -13606,7 +13803,8 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13606
13803
|
backlinks: [],
|
|
13607
13804
|
schema_hash: schemaHash,
|
|
13608
13805
|
source_hashes: {},
|
|
13609
|
-
source_semantic_hashes: {}
|
|
13806
|
+
source_semantic_hashes: {},
|
|
13807
|
+
profile_presets: profilePresets
|
|
13610
13808
|
}
|
|
13611
13809
|
)
|
|
13612
13810
|
},
|
|
@@ -13628,13 +13826,19 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13628
13826
|
"## Recently Guided Sources",
|
|
13629
13827
|
"",
|
|
13630
13828
|
...guidePages.length ? guidePages.slice(0, 8).map((page) => `- [[${page.path.replace(/\.md$/, "")}|${page.title}]]`) : ["- No accepted source guides yet."],
|
|
13631
|
-
...report?.suggestedQuestions?.length ? ["", "## Suggested Questions", "", ...report.suggestedQuestions.slice(0, 8).map((question) => `- ${question}`)] : [],
|
|
13632
13829
|
"",
|
|
13633
|
-
"
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
"
|
|
13637
|
-
|
|
13830
|
+
"## Active Source Sessions",
|
|
13831
|
+
"",
|
|
13832
|
+
...sourceSessions.length ? sourceSessions.slice(0, 8).map((session) => `- \`${session.status}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`) : ["- No active source sessions yet."],
|
|
13833
|
+
...report?.suggestedQuestions?.length ? ["", "## Suggested Questions", "", ...report.suggestedQuestions.slice(0, 8).map((question) => `- ${question}`)] : [],
|
|
13834
|
+
...dataviewEnabled ? [
|
|
13835
|
+
"",
|
|
13836
|
+
"```dataview",
|
|
13837
|
+
'TABLE file.folder, file.mtime FROM "concepts" OR "entities"',
|
|
13838
|
+
"SORT file.mtime desc",
|
|
13839
|
+
"LIMIT 30",
|
|
13840
|
+
"```"
|
|
13841
|
+
] : [],
|
|
13638
13842
|
""
|
|
13639
13843
|
].join("\n"),
|
|
13640
13844
|
{
|
|
@@ -13663,7 +13867,8 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13663
13867
|
backlinks: [],
|
|
13664
13868
|
schema_hash: schemaHash,
|
|
13665
13869
|
source_hashes: {},
|
|
13666
|
-
source_semantic_hashes: {}
|
|
13870
|
+
source_semantic_hashes: {},
|
|
13871
|
+
profile_presets: profilePresets
|
|
13667
13872
|
}
|
|
13668
13873
|
)
|
|
13669
13874
|
},
|
|
@@ -13686,10 +13891,21 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13686
13891
|
...[...guidePages, ...reviewPages, ...briefPages].slice(0, 12).map((page) => `- [[${page.path.replace(/\.md$/, "")}|${page.title}]]`),
|
|
13687
13892
|
""
|
|
13688
13893
|
] : [],
|
|
13689
|
-
"
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13894
|
+
...dashboardPack === "diligence" && diligenceSessions.length ? [
|
|
13895
|
+
"## Active Evidence Review Sessions",
|
|
13896
|
+
"",
|
|
13897
|
+
...diligenceSessions.map(
|
|
13898
|
+
(session) => `- \`${session.status}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`
|
|
13899
|
+
),
|
|
13900
|
+
""
|
|
13901
|
+
] : [],
|
|
13902
|
+
...dataviewEnabled ? [
|
|
13903
|
+
"```dataview",
|
|
13904
|
+
'TABLE evidence_state, session_status, canonical_targets FROM "outputs/source-reviews" OR "outputs/source-guides" OR "outputs/source-sessions"',
|
|
13905
|
+
'WHERE evidence_state = "conflicting"',
|
|
13906
|
+
"SORT file.mtime desc",
|
|
13907
|
+
"```"
|
|
13908
|
+
] : [],
|
|
13693
13909
|
""
|
|
13694
13910
|
].join("\n"),
|
|
13695
13911
|
{
|
|
@@ -13710,7 +13926,8 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13710
13926
|
backlinks: [],
|
|
13711
13927
|
schema_hash: schemaHash,
|
|
13712
13928
|
source_hashes: {},
|
|
13713
|
-
source_semantic_hashes: {}
|
|
13929
|
+
source_semantic_hashes: {},
|
|
13930
|
+
profile_presets: profilePresets
|
|
13714
13931
|
}
|
|
13715
13932
|
)
|
|
13716
13933
|
},
|
|
@@ -13722,11 +13939,19 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13722
13939
|
"# Open Questions",
|
|
13723
13940
|
"",
|
|
13724
13941
|
...openQuestions.length ? openQuestions.map((question) => `- ${question}`) : ["- No open questions are currently extracted."],
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13942
|
+
...sourceSessions.length ? [
|
|
13943
|
+
"",
|
|
13944
|
+
"## Active Guided Sessions",
|
|
13945
|
+
"",
|
|
13946
|
+
...sourceSessions.filter((session) => session.status === "awaiting_input" || session.status === "staged").slice(0, 8).map((session) => `- \`${session.status}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`)
|
|
13947
|
+
] : [],
|
|
13948
|
+
...dataviewEnabled ? [
|
|
13949
|
+
"",
|
|
13950
|
+
"```dataview",
|
|
13951
|
+
'TABLE question_state, session_status, evidence_state FROM "outputs/source-briefs" OR "outputs/source-reviews" OR "outputs/source-guides" OR "outputs/source-sessions"',
|
|
13952
|
+
"SORT file.mtime desc",
|
|
13953
|
+
"```"
|
|
13954
|
+
] : [],
|
|
13730
13955
|
""
|
|
13731
13956
|
].join("\n"),
|
|
13732
13957
|
{
|
|
@@ -13747,14 +13972,15 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13747
13972
|
backlinks: [],
|
|
13748
13973
|
schema_hash: schemaHash,
|
|
13749
13974
|
source_hashes: {},
|
|
13750
|
-
source_semantic_hashes: {}
|
|
13975
|
+
source_semantic_hashes: {},
|
|
13976
|
+
profile_presets: profilePresets
|
|
13751
13977
|
}
|
|
13752
13978
|
)
|
|
13753
13979
|
}
|
|
13754
13980
|
];
|
|
13755
13981
|
const records = [];
|
|
13756
13982
|
for (const dashboard of dashboards) {
|
|
13757
|
-
const absolutePath =
|
|
13983
|
+
const absolutePath = path23.join(paths.wikiDir, dashboard.relativePath);
|
|
13758
13984
|
const compiledFrom = dashboard.relativePath === "dashboards/recent-sources.md" ? recentSourcePages.flatMap((page) => page.sourceIds) : [];
|
|
13759
13985
|
const content = await buildManagedContent(
|
|
13760
13986
|
absolutePath,
|
|
@@ -13868,7 +14094,7 @@ function resetGraphNodeMetrics(nodes) {
|
|
|
13868
14094
|
return nodes.map(({ communityId: _communityId, degree: _degree, bridgeScore: _bridgeScore, isGodNode: _isGodNode, ...node }) => node);
|
|
13869
14095
|
}
|
|
13870
14096
|
function manifestRepoPath(manifest) {
|
|
13871
|
-
return toPosix(manifest.repoRelativePath ??
|
|
14097
|
+
return toPosix(manifest.repoRelativePath ?? path23.basename(manifest.originalPath ?? manifest.storedPath));
|
|
13872
14098
|
}
|
|
13873
14099
|
function goPackageScopeKey(manifest, analysis) {
|
|
13874
14100
|
if (analysis.code?.language !== "go") {
|
|
@@ -13878,7 +14104,7 @@ function goPackageScopeKey(manifest, analysis) {
|
|
|
13878
14104
|
if (!packageName) {
|
|
13879
14105
|
return null;
|
|
13880
14106
|
}
|
|
13881
|
-
return `${packageName}:${
|
|
14107
|
+
return `${packageName}:${path23.posix.dirname(manifestRepoPath(manifest))}`;
|
|
13882
14108
|
}
|
|
13883
14109
|
function buildGoPackageSymbolLookups(analyses, manifestsById) {
|
|
13884
14110
|
const lookups = /* @__PURE__ */ new Map();
|
|
@@ -14347,7 +14573,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
14347
14573
|
const benchmark = await readJsonFile(paths.benchmarkPath);
|
|
14348
14574
|
const communityRecords = [];
|
|
14349
14575
|
for (const community of graph.communities ?? []) {
|
|
14350
|
-
const absolutePath =
|
|
14576
|
+
const absolutePath = path23.join(paths.wikiDir, "graph", "communities", `${community.id.replace(/^community:/, "")}.md`);
|
|
14351
14577
|
communityRecords.push(
|
|
14352
14578
|
await buildManagedGraphPage(
|
|
14353
14579
|
absolutePath,
|
|
@@ -14376,7 +14602,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
14376
14602
|
graphHash: graphHash(graph),
|
|
14377
14603
|
contradictions
|
|
14378
14604
|
});
|
|
14379
|
-
const reportAbsolutePath =
|
|
14605
|
+
const reportAbsolutePath = path23.join(paths.wikiDir, "graph", "report.md");
|
|
14380
14606
|
const reportRecord = await buildManagedGraphPage(
|
|
14381
14607
|
reportAbsolutePath,
|
|
14382
14608
|
{
|
|
@@ -14397,7 +14623,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
14397
14623
|
};
|
|
14398
14624
|
}
|
|
14399
14625
|
async function writePage(wikiDir, relativePath, content, changedPages) {
|
|
14400
|
-
const absolutePath =
|
|
14626
|
+
const absolutePath = path23.resolve(wikiDir, relativePath);
|
|
14401
14627
|
const changed = await writeFileIfChanged(absolutePath, content);
|
|
14402
14628
|
if (changed) {
|
|
14403
14629
|
changedPages.push(relativePath);
|
|
@@ -14463,29 +14689,29 @@ async function requiredCompileArtifactsExist(paths) {
|
|
|
14463
14689
|
paths.graphPath,
|
|
14464
14690
|
paths.codeIndexPath,
|
|
14465
14691
|
paths.searchDbPath,
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14472
|
-
|
|
14473
|
-
|
|
14692
|
+
path23.join(paths.wikiDir, "index.md"),
|
|
14693
|
+
path23.join(paths.wikiDir, "sources", "index.md"),
|
|
14694
|
+
path23.join(paths.wikiDir, "code", "index.md"),
|
|
14695
|
+
path23.join(paths.wikiDir, "concepts", "index.md"),
|
|
14696
|
+
path23.join(paths.wikiDir, "entities", "index.md"),
|
|
14697
|
+
path23.join(paths.wikiDir, "outputs", "index.md"),
|
|
14698
|
+
path23.join(paths.wikiDir, "projects", "index.md"),
|
|
14699
|
+
path23.join(paths.wikiDir, "candidates", "index.md")
|
|
14474
14700
|
];
|
|
14475
14701
|
const checks = await Promise.all(requiredPaths.map((filePath) => fileExists(filePath)));
|
|
14476
14702
|
return checks.every(Boolean);
|
|
14477
14703
|
}
|
|
14478
14704
|
async function loadAvailableCachedAnalyses(paths, manifests) {
|
|
14479
14705
|
const analyses = await Promise.all(
|
|
14480
|
-
manifests.map(async (manifest) => readJsonFile(
|
|
14706
|
+
manifests.map(async (manifest) => readJsonFile(path23.join(paths.analysesDir, `${manifest.sourceId}.json`)))
|
|
14481
14707
|
);
|
|
14482
14708
|
return analyses.filter((analysis) => Boolean(analysis));
|
|
14483
14709
|
}
|
|
14484
14710
|
function approvalManifestPath(paths, approvalId) {
|
|
14485
|
-
return
|
|
14711
|
+
return path23.join(paths.approvalsDir, approvalId, "manifest.json");
|
|
14486
14712
|
}
|
|
14487
14713
|
function approvalGraphPath(paths, approvalId) {
|
|
14488
|
-
return
|
|
14714
|
+
return path23.join(paths.approvalsDir, approvalId, "state", "graph.json");
|
|
14489
14715
|
}
|
|
14490
14716
|
async function readApprovalManifest(paths, approvalId) {
|
|
14491
14717
|
const manifest = await readJsonFile(approvalManifestPath(paths, approvalId));
|
|
@@ -14495,7 +14721,7 @@ async function readApprovalManifest(paths, approvalId) {
|
|
|
14495
14721
|
return manifest;
|
|
14496
14722
|
}
|
|
14497
14723
|
async function writeApprovalManifest(paths, manifest) {
|
|
14498
|
-
await
|
|
14724
|
+
await fs19.writeFile(approvalManifestPath(paths, manifest.approvalId), `${JSON.stringify(manifest, null, 2)}
|
|
14499
14725
|
`, "utf8");
|
|
14500
14726
|
}
|
|
14501
14727
|
async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousGraph, graph, labelsByPath = /* @__PURE__ */ new Map()) {
|
|
@@ -14510,7 +14736,7 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
|
|
|
14510
14736
|
continue;
|
|
14511
14737
|
}
|
|
14512
14738
|
const previousPage = previousPagesById.get(nextPage.id);
|
|
14513
|
-
const currentExists = await fileExists(
|
|
14739
|
+
const currentExists = await fileExists(path23.join(paths.wikiDir, file.relativePath));
|
|
14514
14740
|
if (previousPage && previousPage.path !== nextPage.path) {
|
|
14515
14741
|
entries.push({
|
|
14516
14742
|
pageId: nextPage.id,
|
|
@@ -14545,7 +14771,7 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
|
|
|
14545
14771
|
const previousPage = previousPagesByPath.get(deletedPath);
|
|
14546
14772
|
entries.push({
|
|
14547
14773
|
pageId: previousPage?.id ?? `page:${slugify(deletedPath)}`,
|
|
14548
|
-
title: previousPage?.title ??
|
|
14774
|
+
title: previousPage?.title ?? path23.basename(deletedPath, ".md"),
|
|
14549
14775
|
kind: previousPage?.kind ?? "index",
|
|
14550
14776
|
changeType: "delete",
|
|
14551
14777
|
status: "pending",
|
|
@@ -14558,16 +14784,16 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
|
|
|
14558
14784
|
}
|
|
14559
14785
|
async function stageApprovalBundle(paths, changedFiles, deletedPaths, previousGraph, graph) {
|
|
14560
14786
|
const approvalId = `compile-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
14561
|
-
const approvalDir =
|
|
14787
|
+
const approvalDir = path23.join(paths.approvalsDir, approvalId);
|
|
14562
14788
|
await ensureDir(approvalDir);
|
|
14563
|
-
await ensureDir(
|
|
14564
|
-
await ensureDir(
|
|
14789
|
+
await ensureDir(path23.join(approvalDir, "wiki"));
|
|
14790
|
+
await ensureDir(path23.join(approvalDir, "state"));
|
|
14565
14791
|
for (const file of changedFiles) {
|
|
14566
|
-
const targetPath =
|
|
14567
|
-
await ensureDir(
|
|
14568
|
-
await
|
|
14792
|
+
const targetPath = path23.join(approvalDir, "wiki", file.relativePath);
|
|
14793
|
+
await ensureDir(path23.dirname(targetPath));
|
|
14794
|
+
await fs19.writeFile(targetPath, file.content, "utf8");
|
|
14569
14795
|
}
|
|
14570
|
-
await
|
|
14796
|
+
await fs19.writeFile(path23.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
|
|
14571
14797
|
await writeApprovalManifest(paths, {
|
|
14572
14798
|
approvalId,
|
|
14573
14799
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -14633,13 +14859,13 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14633
14859
|
confidence: 1
|
|
14634
14860
|
});
|
|
14635
14861
|
const sourceRecord = await buildManagedGraphPage(
|
|
14636
|
-
|
|
14862
|
+
path23.join(paths.wikiDir, preview.path),
|
|
14637
14863
|
{
|
|
14638
14864
|
managedBy: "system",
|
|
14639
14865
|
confidence: 1,
|
|
14640
14866
|
compiledFrom: [manifest.sourceId]
|
|
14641
14867
|
},
|
|
14642
|
-
(metadata) => buildSourcePage(
|
|
14868
|
+
(metadata, existingContent) => buildSourcePage(
|
|
14643
14869
|
manifest,
|
|
14644
14870
|
analysis,
|
|
14645
14871
|
sourceSchemaHash,
|
|
@@ -14650,7 +14876,8 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14650
14876
|
projectIds: sourceProjectIds,
|
|
14651
14877
|
extraTags: [...sourceCategoryTags, ...analysis.tags ?? []],
|
|
14652
14878
|
sourceClass: manifest.sourceClass
|
|
14653
|
-
}
|
|
14879
|
+
},
|
|
14880
|
+
existingContent
|
|
14654
14881
|
)
|
|
14655
14882
|
);
|
|
14656
14883
|
records.push(sourceRecord);
|
|
@@ -14679,7 +14906,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14679
14906
|
);
|
|
14680
14907
|
records.push(
|
|
14681
14908
|
await buildManagedGraphPage(
|
|
14682
|
-
|
|
14909
|
+
path23.join(paths.wikiDir, modulePreview.path),
|
|
14683
14910
|
{
|
|
14684
14911
|
managedBy: "system",
|
|
14685
14912
|
confidence: 1,
|
|
@@ -14713,8 +14940,8 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14713
14940
|
const relativePath = promoted ? activeAggregatePath(itemKind, slug) : candidatePagePathFor(itemKind, slug);
|
|
14714
14941
|
const aggregateSourceClass2 = aggregateManifestSourceClass(input.manifests, sourceIds);
|
|
14715
14942
|
const fallbackPaths = [
|
|
14716
|
-
|
|
14717
|
-
|
|
14943
|
+
path23.join(paths.wikiDir, activeAggregatePath(itemKind, slug)),
|
|
14944
|
+
path23.join(paths.wikiDir, candidatePagePathFor(itemKind, slug))
|
|
14718
14945
|
];
|
|
14719
14946
|
const confidence = nodeConfidence(aggregate.sourceAnalyses.length);
|
|
14720
14947
|
const preview = emptyGraphPage({
|
|
@@ -14732,7 +14959,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14732
14959
|
status: promoted ? "active" : "candidate"
|
|
14733
14960
|
});
|
|
14734
14961
|
const pageRecord = await buildManagedGraphPage(
|
|
14735
|
-
|
|
14962
|
+
path23.join(paths.wikiDir, relativePath),
|
|
14736
14963
|
{
|
|
14737
14964
|
status: promoted ? "active" : "candidate",
|
|
14738
14965
|
managedBy: "system",
|
|
@@ -14740,7 +14967,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14740
14967
|
compiledFrom: sourceIds,
|
|
14741
14968
|
statePathCandidates: fallbackPaths
|
|
14742
14969
|
},
|
|
14743
|
-
(metadata) => buildAggregatePage(
|
|
14970
|
+
(metadata, existingContent) => buildAggregatePage(
|
|
14744
14971
|
itemKind,
|
|
14745
14972
|
aggregate.name,
|
|
14746
14973
|
aggregate.descriptions,
|
|
@@ -14759,7 +14986,8 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14759
14986
|
...aggregate.sourceAnalyses.map((item) => item.summary)
|
|
14760
14987
|
]),
|
|
14761
14988
|
sourceClass: aggregateSourceClass2
|
|
14762
|
-
}
|
|
14989
|
+
},
|
|
14990
|
+
existingContent
|
|
14763
14991
|
)
|
|
14764
14992
|
);
|
|
14765
14993
|
if (promoted && previousEntry?.status === "candidate") {
|
|
@@ -14813,6 +15041,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14813
15041
|
);
|
|
14814
15042
|
const preliminaryPages = [...basePages, ...graphOrientation.records.map((record) => record.page)];
|
|
14815
15043
|
const dashboardRecords = await buildDashboardRecords(
|
|
15044
|
+
config,
|
|
14816
15045
|
paths,
|
|
14817
15046
|
{
|
|
14818
15047
|
...baseGraph,
|
|
@@ -14861,7 +15090,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14861
15090
|
confidence: 1
|
|
14862
15091
|
}),
|
|
14863
15092
|
content: await buildManagedContent(
|
|
14864
|
-
|
|
15093
|
+
path23.join(paths.wikiDir, "projects", "index.md"),
|
|
14865
15094
|
{
|
|
14866
15095
|
managedBy: "system",
|
|
14867
15096
|
compiledFrom: indexCompiledFrom(projectIndexRefs)
|
|
@@ -14885,7 +15114,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14885
15114
|
records.push({
|
|
14886
15115
|
page: projectIndexRef,
|
|
14887
15116
|
content: await buildManagedContent(
|
|
14888
|
-
|
|
15117
|
+
path23.join(paths.wikiDir, projectIndexRef.path),
|
|
14889
15118
|
{
|
|
14890
15119
|
managedBy: "system",
|
|
14891
15120
|
compiledFrom: indexCompiledFrom(Object.values(sections).flat())
|
|
@@ -14913,7 +15142,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14913
15142
|
confidence: 1
|
|
14914
15143
|
}),
|
|
14915
15144
|
content: await buildManagedContent(
|
|
14916
|
-
|
|
15145
|
+
path23.join(paths.wikiDir, "index.md"),
|
|
14917
15146
|
{
|
|
14918
15147
|
managedBy: "system",
|
|
14919
15148
|
compiledFrom: indexCompiledFrom(allPages)
|
|
@@ -14949,7 +15178,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14949
15178
|
confidence: 1
|
|
14950
15179
|
}),
|
|
14951
15180
|
content: await buildManagedContent(
|
|
14952
|
-
|
|
15181
|
+
path23.join(paths.wikiDir, relativePath),
|
|
14953
15182
|
{
|
|
14954
15183
|
managedBy: "system",
|
|
14955
15184
|
compiledFrom: indexCompiledFrom(pages)
|
|
@@ -14960,12 +15189,12 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14960
15189
|
}
|
|
14961
15190
|
const nextPagePaths = new Set(records.map((record) => record.page.path));
|
|
14962
15191
|
const obsoleteGraphPaths = (previousGraph?.pages ?? []).filter((page) => page.kind !== "output" && page.kind !== "insight").map((page) => page.path).filter((relativePath) => !nextPagePaths.has(relativePath));
|
|
14963
|
-
const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(
|
|
15192
|
+
const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path23.relative(paths.wikiDir, absolutePath))).filter((relativePath) => !nextPagePaths.has(relativePath));
|
|
14964
15193
|
const obsoletePaths = uniqueStrings3([...obsoleteGraphPaths, ...existingProjectIndexPaths]);
|
|
14965
15194
|
const changedFiles = [];
|
|
14966
15195
|
for (const record of records) {
|
|
14967
|
-
const absolutePath =
|
|
14968
|
-
const current = await fileExists(absolutePath) ? await
|
|
15196
|
+
const absolutePath = path23.join(paths.wikiDir, record.page.path);
|
|
15197
|
+
const current = await fileExists(absolutePath) ? await fs19.readFile(absolutePath, "utf8") : null;
|
|
14969
15198
|
if (current !== record.content) {
|
|
14970
15199
|
changedPages.push(record.page.path);
|
|
14971
15200
|
changedFiles.push({ relativePath: record.page.path, content: record.content });
|
|
@@ -14990,10 +15219,10 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14990
15219
|
await writePage(paths.wikiDir, record.page.path, record.content, writeChanges);
|
|
14991
15220
|
}
|
|
14992
15221
|
for (const relativePath of obsoletePaths) {
|
|
14993
|
-
await
|
|
15222
|
+
await fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true });
|
|
14994
15223
|
}
|
|
14995
15224
|
await writeJsonFile(paths.graphPath, graph);
|
|
14996
|
-
await writeJsonFile(
|
|
15225
|
+
await writeJsonFile(path23.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
|
|
14997
15226
|
await writeJsonFile(paths.codeIndexPath, input.codeIndex);
|
|
14998
15227
|
await writeJsonFile(paths.compileStatePath, {
|
|
14999
15228
|
generatedAt: graph.generatedAt,
|
|
@@ -15052,6 +15281,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15052
15281
|
compileState?.generatedAt
|
|
15053
15282
|
) : { records: [], report: null };
|
|
15054
15283
|
const dashboardRecords = currentGraph ? await buildDashboardRecords(
|
|
15284
|
+
config,
|
|
15055
15285
|
paths,
|
|
15056
15286
|
{
|
|
15057
15287
|
...currentGraph,
|
|
@@ -15088,18 +15318,18 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15088
15318
|
})
|
|
15089
15319
|
);
|
|
15090
15320
|
await Promise.all([
|
|
15091
|
-
ensureDir(
|
|
15092
|
-
ensureDir(
|
|
15093
|
-
ensureDir(
|
|
15094
|
-
ensureDir(
|
|
15095
|
-
ensureDir(
|
|
15096
|
-
ensureDir(
|
|
15097
|
-
ensureDir(
|
|
15098
|
-
ensureDir(
|
|
15099
|
-
ensureDir(
|
|
15100
|
-
ensureDir(
|
|
15321
|
+
ensureDir(path23.join(paths.wikiDir, "sources")),
|
|
15322
|
+
ensureDir(path23.join(paths.wikiDir, "code")),
|
|
15323
|
+
ensureDir(path23.join(paths.wikiDir, "concepts")),
|
|
15324
|
+
ensureDir(path23.join(paths.wikiDir, "entities")),
|
|
15325
|
+
ensureDir(path23.join(paths.wikiDir, "outputs")),
|
|
15326
|
+
ensureDir(path23.join(paths.wikiDir, "dashboards")),
|
|
15327
|
+
ensureDir(path23.join(paths.wikiDir, "graph")),
|
|
15328
|
+
ensureDir(path23.join(paths.wikiDir, "graph", "communities")),
|
|
15329
|
+
ensureDir(path23.join(paths.wikiDir, "projects")),
|
|
15330
|
+
ensureDir(path23.join(paths.wikiDir, "candidates"))
|
|
15101
15331
|
]);
|
|
15102
|
-
const projectsIndexPath =
|
|
15332
|
+
const projectsIndexPath = path23.join(paths.wikiDir, "projects", "index.md");
|
|
15103
15333
|
await writeFileIfChanged(
|
|
15104
15334
|
projectsIndexPath,
|
|
15105
15335
|
await buildManagedContent(
|
|
@@ -15120,7 +15350,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15120
15350
|
outputs: pages.filter((page) => page.kind === "output" && page.projectIds.includes(project.id)),
|
|
15121
15351
|
candidates: pages.filter((page) => page.status === "candidate" && page.projectIds.includes(project.id))
|
|
15122
15352
|
};
|
|
15123
|
-
const absolutePath =
|
|
15353
|
+
const absolutePath = path23.join(paths.wikiDir, "projects", project.id, "index.md");
|
|
15124
15354
|
await writeFileIfChanged(
|
|
15125
15355
|
absolutePath,
|
|
15126
15356
|
await buildManagedContent(
|
|
@@ -15138,7 +15368,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15138
15368
|
)
|
|
15139
15369
|
);
|
|
15140
15370
|
}
|
|
15141
|
-
const rootIndexPath =
|
|
15371
|
+
const rootIndexPath = path23.join(paths.wikiDir, "index.md");
|
|
15142
15372
|
await writeFileIfChanged(
|
|
15143
15373
|
rootIndexPath,
|
|
15144
15374
|
await buildManagedContent(
|
|
@@ -15164,7 +15394,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15164
15394
|
["candidates/index.md", "candidates", pagesWithGraph.filter((page) => page.status === "candidate")],
|
|
15165
15395
|
["graph/index.md", "graph", pagesWithGraph.filter((page) => page.kind === "graph_report" || page.kind === "community_summary")]
|
|
15166
15396
|
]) {
|
|
15167
|
-
const absolutePath =
|
|
15397
|
+
const absolutePath = path23.join(paths.wikiDir, relativePath);
|
|
15168
15398
|
await writeFileIfChanged(
|
|
15169
15399
|
absolutePath,
|
|
15170
15400
|
await buildManagedContent(
|
|
@@ -15178,31 +15408,31 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15178
15408
|
);
|
|
15179
15409
|
}
|
|
15180
15410
|
for (const record of graphOrientation.records) {
|
|
15181
|
-
await writeFileIfChanged(
|
|
15411
|
+
await writeFileIfChanged(path23.join(paths.wikiDir, record.page.path), record.content);
|
|
15182
15412
|
}
|
|
15183
15413
|
for (const record of dashboardRecords) {
|
|
15184
|
-
await writeFileIfChanged(
|
|
15414
|
+
await writeFileIfChanged(path23.join(paths.wikiDir, record.page.path), record.content);
|
|
15185
15415
|
}
|
|
15186
15416
|
if (graphOrientation.report) {
|
|
15187
|
-
await writeJsonFile(
|
|
15417
|
+
await writeJsonFile(path23.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
|
|
15188
15418
|
}
|
|
15189
|
-
const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(
|
|
15419
|
+
const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path23.relative(paths.wikiDir, absolutePath)));
|
|
15190
15420
|
const allowedProjectIndexPaths = /* @__PURE__ */ new Set([
|
|
15191
15421
|
"projects/index.md",
|
|
15192
15422
|
...configuredProjects.map((project) => `projects/${project.id}/index.md`)
|
|
15193
15423
|
]);
|
|
15194
15424
|
await Promise.all(
|
|
15195
|
-
existingProjectIndexPaths.filter((relativePath) => !allowedProjectIndexPaths.has(relativePath)).map((relativePath) =>
|
|
15425
|
+
existingProjectIndexPaths.filter((relativePath) => !allowedProjectIndexPaths.has(relativePath)).map((relativePath) => fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true }))
|
|
15196
15426
|
);
|
|
15197
|
-
const existingGraphPages = (await listFilesRecursive(
|
|
15427
|
+
const existingGraphPages = (await listFilesRecursive(path23.join(paths.wikiDir, "graph").replace(/\/$/, "")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path23.relative(paths.wikiDir, absolutePath)));
|
|
15198
15428
|
const allowedGraphPages = /* @__PURE__ */ new Set(["graph/index.md", ...graphOrientation.records.map((record) => record.page.path)]);
|
|
15199
15429
|
await Promise.all(
|
|
15200
|
-
existingGraphPages.filter((relativePath) => !allowedGraphPages.has(relativePath)).map((relativePath) =>
|
|
15430
|
+
existingGraphPages.filter((relativePath) => !allowedGraphPages.has(relativePath)).map((relativePath) => fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true }))
|
|
15201
15431
|
);
|
|
15202
|
-
const existingDashboardPages = (await listFilesRecursive(
|
|
15432
|
+
const existingDashboardPages = (await listFilesRecursive(path23.join(paths.wikiDir, "dashboards")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path23.relative(paths.wikiDir, absolutePath)));
|
|
15203
15433
|
const allowedDashboardPages = /* @__PURE__ */ new Set(["dashboards/index.md", ...dashboardRecords.map((record) => record.page.path)]);
|
|
15204
15434
|
await Promise.all(
|
|
15205
|
-
existingDashboardPages.filter((relativePath) => !allowedDashboardPages.has(relativePath)).map((relativePath) =>
|
|
15435
|
+
existingDashboardPages.filter((relativePath) => !allowedDashboardPages.has(relativePath)).map((relativePath) => fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true }))
|
|
15206
15436
|
);
|
|
15207
15437
|
await rebuildSearchIndex(paths.searchDbPath, pagesWithGraph, paths.wikiDir);
|
|
15208
15438
|
}
|
|
@@ -15222,7 +15452,7 @@ async function prepareOutputPageSave(rootDir, input) {
|
|
|
15222
15452
|
confidence: 0.74
|
|
15223
15453
|
}
|
|
15224
15454
|
});
|
|
15225
|
-
const absolutePath =
|
|
15455
|
+
const absolutePath = path23.join(paths.wikiDir, output.page.path);
|
|
15226
15456
|
return {
|
|
15227
15457
|
page: output.page,
|
|
15228
15458
|
savedPath: absolutePath,
|
|
@@ -15234,15 +15464,15 @@ async function prepareOutputPageSave(rootDir, input) {
|
|
|
15234
15464
|
async function persistOutputPage(rootDir, input) {
|
|
15235
15465
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15236
15466
|
const prepared = await prepareOutputPageSave(rootDir, input);
|
|
15237
|
-
await ensureDir(
|
|
15238
|
-
await
|
|
15467
|
+
await ensureDir(path23.dirname(prepared.savedPath));
|
|
15468
|
+
await fs19.writeFile(prepared.savedPath, prepared.content, "utf8");
|
|
15239
15469
|
for (const assetFile of prepared.assetFiles) {
|
|
15240
|
-
const assetPath =
|
|
15241
|
-
await ensureDir(
|
|
15470
|
+
const assetPath = path23.join(paths.wikiDir, assetFile.relativePath);
|
|
15471
|
+
await ensureDir(path23.dirname(assetPath));
|
|
15242
15472
|
if (typeof assetFile.content === "string") {
|
|
15243
|
-
await
|
|
15473
|
+
await fs19.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
|
|
15244
15474
|
} else {
|
|
15245
|
-
await
|
|
15475
|
+
await fs19.writeFile(assetPath, assetFile.content);
|
|
15246
15476
|
}
|
|
15247
15477
|
}
|
|
15248
15478
|
return { page: prepared.page, savedPath: prepared.savedPath, outputAssets: prepared.outputAssets };
|
|
@@ -15263,7 +15493,7 @@ async function prepareExploreHubSave(rootDir, input) {
|
|
|
15263
15493
|
confidence: 0.76
|
|
15264
15494
|
}
|
|
15265
15495
|
});
|
|
15266
|
-
const absolutePath =
|
|
15496
|
+
const absolutePath = path23.join(paths.wikiDir, hub.page.path);
|
|
15267
15497
|
return {
|
|
15268
15498
|
page: hub.page,
|
|
15269
15499
|
savedPath: absolutePath,
|
|
@@ -15275,15 +15505,15 @@ async function prepareExploreHubSave(rootDir, input) {
|
|
|
15275
15505
|
async function persistExploreHub(rootDir, input) {
|
|
15276
15506
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15277
15507
|
const prepared = await prepareExploreHubSave(rootDir, input);
|
|
15278
|
-
await ensureDir(
|
|
15279
|
-
await
|
|
15508
|
+
await ensureDir(path23.dirname(prepared.savedPath));
|
|
15509
|
+
await fs19.writeFile(prepared.savedPath, prepared.content, "utf8");
|
|
15280
15510
|
for (const assetFile of prepared.assetFiles) {
|
|
15281
|
-
const assetPath =
|
|
15282
|
-
await ensureDir(
|
|
15511
|
+
const assetPath = path23.join(paths.wikiDir, assetFile.relativePath);
|
|
15512
|
+
await ensureDir(path23.dirname(assetPath));
|
|
15283
15513
|
if (typeof assetFile.content === "string") {
|
|
15284
|
-
await
|
|
15514
|
+
await fs19.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
|
|
15285
15515
|
} else {
|
|
15286
|
-
await
|
|
15516
|
+
await fs19.writeFile(assetPath, assetFile.content);
|
|
15287
15517
|
}
|
|
15288
15518
|
}
|
|
15289
15519
|
return { page: prepared.page, savedPath: prepared.savedPath, outputAssets: prepared.outputAssets };
|
|
@@ -15301,17 +15531,17 @@ async function stageOutputApprovalBundle(rootDir, stagedPages, options = {}) {
|
|
|
15301
15531
|
]);
|
|
15302
15532
|
const labelsByPath = new Map(stagedPages.filter((item) => item.label).map((item) => [item.page.path, item.label]));
|
|
15303
15533
|
const approvalId = `schedule-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
15304
|
-
const approvalDir =
|
|
15534
|
+
const approvalDir = path23.join(paths.approvalsDir, approvalId);
|
|
15305
15535
|
await ensureDir(approvalDir);
|
|
15306
|
-
await ensureDir(
|
|
15307
|
-
await ensureDir(
|
|
15536
|
+
await ensureDir(path23.join(approvalDir, "wiki"));
|
|
15537
|
+
await ensureDir(path23.join(approvalDir, "state"));
|
|
15308
15538
|
for (const file of changedFiles) {
|
|
15309
|
-
const targetPath =
|
|
15310
|
-
await ensureDir(
|
|
15539
|
+
const targetPath = path23.join(approvalDir, "wiki", file.relativePath);
|
|
15540
|
+
await ensureDir(path23.dirname(targetPath));
|
|
15311
15541
|
if ("binary" in file && file.binary) {
|
|
15312
|
-
await
|
|
15542
|
+
await fs19.writeFile(targetPath, Buffer.from(file.content, "base64"));
|
|
15313
15543
|
} else {
|
|
15314
|
-
await
|
|
15544
|
+
await fs19.writeFile(targetPath, file.content, "utf8");
|
|
15315
15545
|
}
|
|
15316
15546
|
}
|
|
15317
15547
|
const nextPages = sortGraphPages([
|
|
@@ -15326,12 +15556,13 @@ async function stageOutputApprovalBundle(rootDir, stagedPages, options = {}) {
|
|
|
15326
15556
|
sources: previousGraph?.sources ?? [],
|
|
15327
15557
|
pages: nextPages
|
|
15328
15558
|
};
|
|
15329
|
-
await
|
|
15559
|
+
await fs19.writeFile(path23.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
|
|
15330
15560
|
await writeApprovalManifest(paths, {
|
|
15331
15561
|
approvalId,
|
|
15332
15562
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15333
15563
|
bundleType: options.bundleType ?? "generated_output",
|
|
15334
15564
|
title: options.title,
|
|
15565
|
+
sourceSessionId: options.sourceSessionId,
|
|
15335
15566
|
entries: await buildApprovalEntries(
|
|
15336
15567
|
paths,
|
|
15337
15568
|
stagedPages.map((item) => ({ relativePath: item.page.path, content: item.content })),
|
|
@@ -15361,9 +15592,9 @@ async function executeQuery(rootDir, question, format) {
|
|
|
15361
15592
|
const searchResults = searchPages(paths.searchDbPath, question, 5);
|
|
15362
15593
|
const excerpts = await Promise.all(
|
|
15363
15594
|
searchResults.map(async (result) => {
|
|
15364
|
-
const absolutePath =
|
|
15595
|
+
const absolutePath = path23.join(paths.wikiDir, result.path);
|
|
15365
15596
|
try {
|
|
15366
|
-
const content = await
|
|
15597
|
+
const content = await fs19.readFile(absolutePath, "utf8");
|
|
15367
15598
|
const parsed = matter9(content);
|
|
15368
15599
|
return `# ${result.title}
|
|
15369
15600
|
${truncate(normalizeWhitespace(parsed.content), 1200)}`;
|
|
@@ -15598,7 +15829,7 @@ function computeChangeSummary(current, staged, changeType) {
|
|
|
15598
15829
|
async function listApprovals(rootDir) {
|
|
15599
15830
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15600
15831
|
const manifests = await Promise.all(
|
|
15601
|
-
(await
|
|
15832
|
+
(await fs19.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => {
|
|
15602
15833
|
try {
|
|
15603
15834
|
return await readApprovalManifest(paths, entry.name);
|
|
15604
15835
|
} catch {
|
|
@@ -15614,8 +15845,8 @@ async function readApproval(rootDir, approvalId, options) {
|
|
|
15614
15845
|
const details = await Promise.all(
|
|
15615
15846
|
manifest.entries.map(async (entry) => {
|
|
15616
15847
|
const currentPath = entry.previousPath ?? entry.nextPath;
|
|
15617
|
-
const currentContent = currentPath ? await
|
|
15618
|
-
const stagedContent = entry.nextPath ? await
|
|
15848
|
+
const currentContent = currentPath ? await fs19.readFile(path23.join(paths.wikiDir, currentPath), "utf8").catch(() => void 0) : void 0;
|
|
15849
|
+
const stagedContent = entry.nextPath ? await fs19.readFile(path23.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath), "utf8").catch(() => void 0) : void 0;
|
|
15619
15850
|
const detail = {
|
|
15620
15851
|
...entry,
|
|
15621
15852
|
currentContent,
|
|
@@ -15648,26 +15879,26 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
|
|
|
15648
15879
|
if (!entry.nextPath) {
|
|
15649
15880
|
throw new Error(`Approval entry ${entry.pageId} is missing a staged path.`);
|
|
15650
15881
|
}
|
|
15651
|
-
const stagedAbsolutePath =
|
|
15652
|
-
const stagedContent = await
|
|
15653
|
-
const targetAbsolutePath =
|
|
15654
|
-
await ensureDir(
|
|
15655
|
-
await
|
|
15882
|
+
const stagedAbsolutePath = path23.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath);
|
|
15883
|
+
const stagedContent = await fs19.readFile(stagedAbsolutePath, "utf8");
|
|
15884
|
+
const targetAbsolutePath = path23.join(paths.wikiDir, entry.nextPath);
|
|
15885
|
+
await ensureDir(path23.dirname(targetAbsolutePath));
|
|
15886
|
+
await fs19.writeFile(targetAbsolutePath, stagedContent, "utf8");
|
|
15656
15887
|
if (entry.changeType === "promote" && entry.previousPath) {
|
|
15657
|
-
await
|
|
15888
|
+
await fs19.rm(path23.join(paths.wikiDir, entry.previousPath), { force: true });
|
|
15658
15889
|
}
|
|
15659
15890
|
const nextPage = bundleGraph?.pages.find((page) => page.id === entry.pageId && page.path === entry.nextPath) ?? parseStoredPage(entry.nextPath, stagedContent);
|
|
15660
15891
|
if (nextPage.kind === "output" && nextPage.outputAssets?.length) {
|
|
15661
|
-
const outputAssetDir =
|
|
15662
|
-
await
|
|
15892
|
+
const outputAssetDir = path23.join(paths.wikiDir, "outputs", "assets", path23.basename(nextPage.path, ".md"));
|
|
15893
|
+
await fs19.rm(outputAssetDir, { recursive: true, force: true });
|
|
15663
15894
|
for (const asset of nextPage.outputAssets) {
|
|
15664
|
-
const stagedAssetPath =
|
|
15895
|
+
const stagedAssetPath = path23.join(paths.approvalsDir, approvalId, "wiki", asset.path);
|
|
15665
15896
|
if (!await fileExists(stagedAssetPath)) {
|
|
15666
15897
|
continue;
|
|
15667
15898
|
}
|
|
15668
|
-
const targetAssetPath =
|
|
15669
|
-
await ensureDir(
|
|
15670
|
-
await
|
|
15899
|
+
const targetAssetPath = path23.join(paths.wikiDir, asset.path);
|
|
15900
|
+
await ensureDir(path23.dirname(targetAssetPath));
|
|
15901
|
+
await fs19.copyFile(stagedAssetPath, targetAssetPath);
|
|
15671
15902
|
}
|
|
15672
15903
|
}
|
|
15673
15904
|
nextPages = nextPages.filter(
|
|
@@ -15678,10 +15909,10 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
|
|
|
15678
15909
|
} else {
|
|
15679
15910
|
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;
|
|
15680
15911
|
if (entry.previousPath) {
|
|
15681
|
-
await
|
|
15912
|
+
await fs19.rm(path23.join(paths.wikiDir, entry.previousPath), { force: true });
|
|
15682
15913
|
}
|
|
15683
15914
|
if (deletedPage?.kind === "output") {
|
|
15684
|
-
await
|
|
15915
|
+
await fs19.rm(path23.join(paths.wikiDir, "outputs", "assets", path23.basename(deletedPage.path, ".md")), {
|
|
15685
15916
|
recursive: true,
|
|
15686
15917
|
force: true
|
|
15687
15918
|
});
|
|
@@ -15704,6 +15935,9 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
|
|
|
15704
15935
|
await writeJsonFile(paths.compileStatePath, compileState);
|
|
15705
15936
|
await refreshIndexesAndSearch(rootDir, nextGraph.pages);
|
|
15706
15937
|
await writeApprovalManifest(paths, manifest);
|
|
15938
|
+
if (manifest.sourceSessionId) {
|
|
15939
|
+
await updateGuidedSourceSessionStatus(rootDir, manifest.sourceSessionId, "accepted");
|
|
15940
|
+
}
|
|
15707
15941
|
await recordSession(rootDir, {
|
|
15708
15942
|
operation: "review",
|
|
15709
15943
|
title: `Accepted review entries from ${approvalId}`,
|
|
@@ -15730,6 +15964,9 @@ async function rejectApproval(rootDir, approvalId, targets = []) {
|
|
|
15730
15964
|
entry.status = "rejected";
|
|
15731
15965
|
}
|
|
15732
15966
|
await writeApprovalManifest(paths, manifest);
|
|
15967
|
+
if (manifest.sourceSessionId) {
|
|
15968
|
+
await updateGuidedSourceSessionStatus(rootDir, manifest.sourceSessionId, "rejected");
|
|
15969
|
+
}
|
|
15733
15970
|
await recordSession(rootDir, {
|
|
15734
15971
|
operation: "review",
|
|
15735
15972
|
title: `Rejected review entries from ${approvalId}`,
|
|
@@ -15772,7 +16009,7 @@ async function promoteCandidate(rootDir, target) {
|
|
|
15772
16009
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15773
16010
|
const graph = await readJsonFile(paths.graphPath);
|
|
15774
16011
|
const candidate = resolveCandidateTarget(graph?.pages ?? [], target);
|
|
15775
|
-
const raw = await
|
|
16012
|
+
const raw = await fs19.readFile(path23.join(paths.wikiDir, candidate.path), "utf8");
|
|
15776
16013
|
const parsed = matter9(raw);
|
|
15777
16014
|
const nextUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15778
16015
|
const nextContent = matter9.stringify(parsed.content, {
|
|
@@ -15784,10 +16021,10 @@ async function promoteCandidate(rootDir, target) {
|
|
|
15784
16021
|
)
|
|
15785
16022
|
});
|
|
15786
16023
|
const nextPath = candidateActivePath(candidate);
|
|
15787
|
-
const nextAbsolutePath =
|
|
15788
|
-
await ensureDir(
|
|
15789
|
-
await
|
|
15790
|
-
await
|
|
16024
|
+
const nextAbsolutePath = path23.join(paths.wikiDir, nextPath);
|
|
16025
|
+
await ensureDir(path23.dirname(nextAbsolutePath));
|
|
16026
|
+
await fs19.writeFile(nextAbsolutePath, nextContent, "utf8");
|
|
16027
|
+
await fs19.rm(path23.join(paths.wikiDir, candidate.path), { force: true });
|
|
15791
16028
|
const nextPage = parseStoredPage(nextPath, nextContent, { createdAt: candidate.createdAt, updatedAt: nextUpdatedAt });
|
|
15792
16029
|
const nextPages = sortGraphPages(
|
|
15793
16030
|
(graph?.pages ?? []).filter((page) => page.id !== candidate.id && page.path !== candidate.path).concat(nextPage)
|
|
@@ -15832,7 +16069,7 @@ async function archiveCandidate(rootDir, target) {
|
|
|
15832
16069
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15833
16070
|
const graph = await readJsonFile(paths.graphPath);
|
|
15834
16071
|
const candidate = resolveCandidateTarget(graph?.pages ?? [], target);
|
|
15835
|
-
await
|
|
16072
|
+
await fs19.rm(path23.join(paths.wikiDir, candidate.path), { force: true });
|
|
15836
16073
|
const nextPages = sortGraphPages((graph?.pages ?? []).filter((page) => page.id !== candidate.id && page.path !== candidate.path));
|
|
15837
16074
|
const nextGraph = {
|
|
15838
16075
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15871,18 +16108,18 @@ async function archiveCandidate(rootDir, target) {
|
|
|
15871
16108
|
}
|
|
15872
16109
|
async function ensureObsidianWorkspace(rootDir) {
|
|
15873
16110
|
const { config } = await loadVaultConfig(rootDir);
|
|
15874
|
-
const obsidianDir =
|
|
16111
|
+
const obsidianDir = path23.join(rootDir, ".obsidian");
|
|
15875
16112
|
const projectIds = projectEntries(config).map((project) => project.id);
|
|
15876
16113
|
await ensureDir(obsidianDir);
|
|
15877
16114
|
await Promise.all([
|
|
15878
|
-
writeJsonFile(
|
|
16115
|
+
writeJsonFile(path23.join(obsidianDir, "app.json"), {
|
|
15879
16116
|
alwaysUpdateLinks: true,
|
|
15880
16117
|
newFileLocation: "folder",
|
|
15881
16118
|
newFileFolderPath: "wiki/insights",
|
|
15882
16119
|
useMarkdownLinks: false,
|
|
15883
16120
|
attachmentFolderPath: "raw/assets"
|
|
15884
16121
|
}),
|
|
15885
|
-
writeJsonFile(
|
|
16122
|
+
writeJsonFile(path23.join(obsidianDir, "core-plugins.json"), [
|
|
15886
16123
|
"file-explorer",
|
|
15887
16124
|
"global-search",
|
|
15888
16125
|
"switcher",
|
|
@@ -15892,7 +16129,7 @@ async function ensureObsidianWorkspace(rootDir) {
|
|
|
15892
16129
|
"tag-pane",
|
|
15893
16130
|
"page-preview"
|
|
15894
16131
|
]),
|
|
15895
|
-
writeJsonFile(
|
|
16132
|
+
writeJsonFile(path23.join(obsidianDir, "graph.json"), {
|
|
15896
16133
|
"collapse-filter": false,
|
|
15897
16134
|
search: "",
|
|
15898
16135
|
showTags: true,
|
|
@@ -15904,7 +16141,7 @@ async function ensureObsidianWorkspace(rootDir) {
|
|
|
15904
16141
|
})),
|
|
15905
16142
|
localJumps: false
|
|
15906
16143
|
}),
|
|
15907
|
-
writeJsonFile(
|
|
16144
|
+
writeJsonFile(path23.join(obsidianDir, "workspace.json"), {
|
|
15908
16145
|
active: "root",
|
|
15909
16146
|
lastOpenFiles: ["wiki/index.md", "wiki/projects/index.md", "wiki/candidates/index.md", "wiki/insights/index.md"],
|
|
15910
16147
|
left: {
|
|
@@ -15917,21 +16154,27 @@ async function ensureObsidianWorkspace(rootDir) {
|
|
|
15917
16154
|
]);
|
|
15918
16155
|
}
|
|
15919
16156
|
async function initVault(rootDir, options = {}) {
|
|
15920
|
-
const
|
|
15921
|
-
const { paths } = await initWorkspace(rootDir, { profile });
|
|
16157
|
+
const requestedProfile = options.profile ?? "default";
|
|
16158
|
+
const { config, paths } = await initWorkspace(rootDir, { profile: requestedProfile });
|
|
16159
|
+
const profile = config.profile;
|
|
16160
|
+
const isResearchProfile = profile.presets.length > 0 || profile.guidedSessionMode === "canonical_review" || profile.dataviewBlocks;
|
|
15922
16161
|
await installConfiguredAgents(rootDir);
|
|
15923
|
-
const insightsIndexPath =
|
|
16162
|
+
const insightsIndexPath = path23.join(paths.wikiDir, "insights", "index.md");
|
|
15924
16163
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15925
16164
|
await writeFileIfChanged(
|
|
15926
16165
|
insightsIndexPath,
|
|
15927
16166
|
matter9.stringify(
|
|
15928
|
-
(
|
|
16167
|
+
(isResearchProfile ? [
|
|
15929
16168
|
"# Insights",
|
|
15930
16169
|
"",
|
|
15931
16170
|
"Human-authored research notes live here.",
|
|
15932
16171
|
"",
|
|
15933
16172
|
"- Use this folder for thesis notes, reading reflections, synthesis drafts, and decisions you want to keep explicitly human-authored.",
|
|
15934
|
-
|
|
16173
|
+
...profile.guidedSessionMode === "canonical_review" ? [
|
|
16174
|
+
"- Guided sessions can stage approval-queued updates for canonical pages and fall back to `wiki/insights/` when a claim still needs judgment."
|
|
16175
|
+
] : [
|
|
16176
|
+
"- Guided sessions fall back to `wiki/insights/` for exploratory synthesis until you decide what should become canonical."
|
|
16177
|
+
],
|
|
15935
16178
|
"- Treat these pages as the human judgment layer for your vault.",
|
|
15936
16179
|
""
|
|
15937
16180
|
] : [
|
|
@@ -15940,7 +16183,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15940
16183
|
"Human-authored notes live here.",
|
|
15941
16184
|
"",
|
|
15942
16185
|
"- SwarmVault can read these pages during compile and query.",
|
|
15943
|
-
"- SwarmVault
|
|
16186
|
+
"- SwarmVault can stage insight-page updates through guided sessions, but it never applies them without review.",
|
|
15944
16187
|
""
|
|
15945
16188
|
]).join("\n"),
|
|
15946
16189
|
{
|
|
@@ -15966,7 +16209,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15966
16209
|
)
|
|
15967
16210
|
);
|
|
15968
16211
|
await writeFileIfChanged(
|
|
15969
|
-
|
|
16212
|
+
path23.join(paths.wikiDir, "projects", "index.md"),
|
|
15970
16213
|
matter9.stringify(["# Projects", "", "- Run `swarmvault compile` to build project rollups.", ""].join("\n"), {
|
|
15971
16214
|
page_id: "projects:index",
|
|
15972
16215
|
kind: "index",
|
|
@@ -15989,7 +16232,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15989
16232
|
})
|
|
15990
16233
|
);
|
|
15991
16234
|
await writeFileIfChanged(
|
|
15992
|
-
|
|
16235
|
+
path23.join(paths.wikiDir, "candidates", "index.md"),
|
|
15993
16236
|
matter9.stringify(["# Candidates", "", "- Run `swarmvault compile` to stage candidate pages.", ""].join("\n"), {
|
|
15994
16237
|
page_id: "candidates:index",
|
|
15995
16238
|
kind: "index",
|
|
@@ -16014,15 +16257,21 @@ async function initVault(rootDir, options = {}) {
|
|
|
16014
16257
|
if (options.obsidian) {
|
|
16015
16258
|
await ensureObsidianWorkspace(rootDir);
|
|
16016
16259
|
}
|
|
16017
|
-
if (
|
|
16260
|
+
if (isResearchProfile) {
|
|
16018
16261
|
await writeFileIfChanged(
|
|
16019
|
-
|
|
16262
|
+
path23.join(paths.wikiDir, "insights", "research-playbook.md"),
|
|
16020
16263
|
matter9.stringify(
|
|
16021
16264
|
[
|
|
16022
|
-
"
|
|
16265
|
+
`# ${requestedProfile === "personal-research" ? "Personal Research Playbook" : "Research Playbook"}`,
|
|
16023
16266
|
"",
|
|
16024
16267
|
"- Add one source at a time with `swarmvault ingest <input> --guide` or `swarmvault source add <input> --guide`.",
|
|
16025
|
-
"-
|
|
16268
|
+
"- Resume a guided session with `swarmvault source session <source-id-or-session-id>` whenever you want to answer the session prompts directly.",
|
|
16269
|
+
"- Review `wiki/outputs/source-briefs/`, `wiki/outputs/source-reviews/`, `wiki/outputs/source-guides/`, and `wiki/outputs/source-sessions/` before accepting staged updates.",
|
|
16270
|
+
...profile.guidedSessionMode === "canonical_review" ? ["- Use `swarmvault review show --diff` to inspect staged canonical page edits before accepting them."] : ["- Keep exploratory synthesis in `wiki/insights/` until you are ready to promote it into canonical pages."],
|
|
16271
|
+
...profile.dataviewBlocks ? [
|
|
16272
|
+
"- Dataview-friendly fields are enabled in the dashboards, but every generated page should still read cleanly as plain markdown."
|
|
16273
|
+
] : [],
|
|
16274
|
+
...profile.presets.length ? [`- Active profile presets: ${profile.presets.map((preset) => `\`${preset}\``).join(", ")}.`] : [],
|
|
16026
16275
|
"- Keep unresolved questions visible in `wiki/dashboards/open-questions.md`.",
|
|
16027
16276
|
"- Use `swarmvault review list` and `swarmvault review show --diff` to decide what becomes canonical.",
|
|
16028
16277
|
""
|
|
@@ -16030,7 +16279,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
16030
16279
|
{
|
|
16031
16280
|
page_id: "insights:research-playbook",
|
|
16032
16281
|
kind: "insight",
|
|
16033
|
-
title: "Personal Research Playbook",
|
|
16282
|
+
title: requestedProfile === "personal-research" ? "Personal Research Playbook" : "Research Playbook",
|
|
16034
16283
|
tags: ["insight", "research", "playbook"],
|
|
16035
16284
|
source_ids: [],
|
|
16036
16285
|
project_ids: [],
|
|
@@ -16165,7 +16414,7 @@ async function compileVault(rootDir, options = {}) {
|
|
|
16165
16414
|
),
|
|
16166
16415
|
Promise.all(
|
|
16167
16416
|
clean.map(async (manifest) => {
|
|
16168
|
-
const cached = await readJsonFile(
|
|
16417
|
+
const cached = await readJsonFile(path23.join(paths.analysesDir, `${manifest.sourceId}.json`));
|
|
16169
16418
|
if (cached) {
|
|
16170
16419
|
analysisProgress.tick(manifest.title);
|
|
16171
16420
|
return cached;
|
|
@@ -16193,22 +16442,22 @@ async function compileVault(rootDir, options = {}) {
|
|
|
16193
16442
|
}
|
|
16194
16443
|
const enriched = enrichResolvedCodeImports(manifest, analysis, codeIndex);
|
|
16195
16444
|
if (analysisSignature(enriched) !== analysisSignature(analysis)) {
|
|
16196
|
-
await writeJsonFile(
|
|
16445
|
+
await writeJsonFile(path23.join(paths.analysesDir, `${analysis.sourceId}.json`), enriched);
|
|
16197
16446
|
}
|
|
16198
16447
|
return enriched;
|
|
16199
16448
|
})
|
|
16200
16449
|
);
|
|
16201
16450
|
await Promise.all([
|
|
16202
|
-
ensureDir(
|
|
16203
|
-
ensureDir(
|
|
16204
|
-
ensureDir(
|
|
16205
|
-
ensureDir(
|
|
16206
|
-
ensureDir(
|
|
16207
|
-
ensureDir(
|
|
16208
|
-
ensureDir(
|
|
16209
|
-
ensureDir(
|
|
16210
|
-
ensureDir(
|
|
16211
|
-
ensureDir(
|
|
16451
|
+
ensureDir(path23.join(paths.wikiDir, "sources")),
|
|
16452
|
+
ensureDir(path23.join(paths.wikiDir, "code")),
|
|
16453
|
+
ensureDir(path23.join(paths.wikiDir, "concepts")),
|
|
16454
|
+
ensureDir(path23.join(paths.wikiDir, "entities")),
|
|
16455
|
+
ensureDir(path23.join(paths.wikiDir, "outputs")),
|
|
16456
|
+
ensureDir(path23.join(paths.wikiDir, "projects")),
|
|
16457
|
+
ensureDir(path23.join(paths.wikiDir, "insights")),
|
|
16458
|
+
ensureDir(path23.join(paths.wikiDir, "candidates")),
|
|
16459
|
+
ensureDir(path23.join(paths.wikiDir, "candidates", "concepts")),
|
|
16460
|
+
ensureDir(path23.join(paths.wikiDir, "candidates", "entities"))
|
|
16212
16461
|
]);
|
|
16213
16462
|
const sync = await syncVaultArtifacts(rootDir, {
|
|
16214
16463
|
schemas,
|
|
@@ -16355,7 +16604,7 @@ async function queryVault(rootDir, options) {
|
|
|
16355
16604
|
assetFiles: staged.assetFiles
|
|
16356
16605
|
}
|
|
16357
16606
|
]);
|
|
16358
|
-
stagedPath =
|
|
16607
|
+
stagedPath = path23.join(approval.approvalDir, "wiki", staged.page.path);
|
|
16359
16608
|
savedPageId = staged.page.id;
|
|
16360
16609
|
approvalId = approval.approvalId;
|
|
16361
16610
|
approvalDir = approval.approvalDir;
|
|
@@ -16611,9 +16860,9 @@ ${orchestrationNotes.join("\n")}
|
|
|
16611
16860
|
approvalId = approval.approvalId;
|
|
16612
16861
|
approvalDir = approval.approvalDir;
|
|
16613
16862
|
stepResults.forEach((result, index) => {
|
|
16614
|
-
result.stagedPath =
|
|
16863
|
+
result.stagedPath = path23.join(approval.approvalDir, "wiki", stagedStepPages[index]?.page.path ?? "");
|
|
16615
16864
|
});
|
|
16616
|
-
stagedHubPath =
|
|
16865
|
+
stagedHubPath = path23.join(approval.approvalDir, "wiki", hubPage.path);
|
|
16617
16866
|
} else {
|
|
16618
16867
|
await refreshVaultAfterOutputSave(rootDir);
|
|
16619
16868
|
}
|
|
@@ -16700,11 +16949,11 @@ async function benchmarkVault(rootDir, options = {}) {
|
|
|
16700
16949
|
}
|
|
16701
16950
|
}
|
|
16702
16951
|
for (const page of graph.pages) {
|
|
16703
|
-
const absolutePath =
|
|
16952
|
+
const absolutePath = path23.join(paths.wikiDir, page.path);
|
|
16704
16953
|
if (!await fileExists(absolutePath)) {
|
|
16705
16954
|
continue;
|
|
16706
16955
|
}
|
|
16707
|
-
const parsed = matter9(await
|
|
16956
|
+
const parsed = matter9(await fs19.readFile(absolutePath, "utf8"));
|
|
16708
16957
|
pageContentsById.set(page.id, parsed.content);
|
|
16709
16958
|
}
|
|
16710
16959
|
const configuredQuestions = (config.benchmark?.questions ?? []).map((question) => normalizeWhitespace(question)).filter(Boolean);
|
|
@@ -16759,7 +17008,7 @@ async function listGraphHyperedges(rootDir, target, limit = 25) {
|
|
|
16759
17008
|
}
|
|
16760
17009
|
async function readGraphReport(rootDir) {
|
|
16761
17010
|
const { paths } = await loadVaultConfig(rootDir);
|
|
16762
|
-
return readJsonFile(
|
|
17011
|
+
return readJsonFile(path23.join(paths.wikiDir, "graph", "report.json"));
|
|
16763
17012
|
}
|
|
16764
17013
|
async function listGodNodes(rootDir, limit = 10) {
|
|
16765
17014
|
const graph = await ensureCompiledGraph(rootDir);
|
|
@@ -16772,15 +17021,15 @@ async function listPages(rootDir) {
|
|
|
16772
17021
|
}
|
|
16773
17022
|
async function readPage(rootDir, relativePath) {
|
|
16774
17023
|
const { paths } = await loadVaultConfig(rootDir);
|
|
16775
|
-
const absolutePath =
|
|
17024
|
+
const absolutePath = path23.resolve(paths.wikiDir, relativePath);
|
|
16776
17025
|
if (!absolutePath.startsWith(paths.wikiDir) || !await fileExists(absolutePath)) {
|
|
16777
17026
|
return null;
|
|
16778
17027
|
}
|
|
16779
|
-
const raw = await
|
|
17028
|
+
const raw = await fs19.readFile(absolutePath, "utf8");
|
|
16780
17029
|
const parsed = matter9(raw);
|
|
16781
17030
|
return {
|
|
16782
17031
|
path: relativePath,
|
|
16783
|
-
title: typeof parsed.data.title === "string" ? parsed.data.title :
|
|
17032
|
+
title: typeof parsed.data.title === "string" ? parsed.data.title : path23.basename(relativePath, path23.extname(relativePath)),
|
|
16784
17033
|
frontmatter: parsed.data,
|
|
16785
17034
|
content: parsed.content
|
|
16786
17035
|
};
|
|
@@ -16816,7 +17065,7 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
|
|
|
16816
17065
|
severity: "warning",
|
|
16817
17066
|
code: "stale_page",
|
|
16818
17067
|
message: `Page ${page.title} is stale because the vault schema changed.`,
|
|
16819
|
-
pagePath:
|
|
17068
|
+
pagePath: path23.join(paths.wikiDir, page.path),
|
|
16820
17069
|
relatedPageIds: [page.id]
|
|
16821
17070
|
});
|
|
16822
17071
|
}
|
|
@@ -16829,7 +17078,7 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
|
|
|
16829
17078
|
severity: "warning",
|
|
16830
17079
|
code: "stale_page",
|
|
16831
17080
|
message: `Page ${page.title} is stale because source ${sourceId} changed.`,
|
|
16832
|
-
pagePath:
|
|
17081
|
+
pagePath: path23.join(paths.wikiDir, page.path),
|
|
16833
17082
|
relatedSourceIds: [sourceId],
|
|
16834
17083
|
relatedPageIds: [page.id]
|
|
16835
17084
|
});
|
|
@@ -16840,13 +17089,13 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
|
|
|
16840
17089
|
severity: "info",
|
|
16841
17090
|
code: "orphan_page",
|
|
16842
17091
|
message: `Page ${page.title} has no backlinks.`,
|
|
16843
|
-
pagePath:
|
|
17092
|
+
pagePath: path23.join(paths.wikiDir, page.path),
|
|
16844
17093
|
relatedPageIds: [page.id]
|
|
16845
17094
|
});
|
|
16846
17095
|
}
|
|
16847
|
-
const absolutePath =
|
|
17096
|
+
const absolutePath = path23.join(paths.wikiDir, page.path);
|
|
16848
17097
|
if (await fileExists(absolutePath)) {
|
|
16849
|
-
const content = await
|
|
17098
|
+
const content = await fs19.readFile(absolutePath, "utf8");
|
|
16850
17099
|
if (content.includes("## Claims")) {
|
|
16851
17100
|
const uncited = content.split("\n").filter((line) => line.startsWith("- ") && !line.includes("[source:"));
|
|
16852
17101
|
if (uncited.length) {
|
|
@@ -16963,7 +17212,7 @@ async function bootstrapDemo(rootDir, input) {
|
|
|
16963
17212
|
}
|
|
16964
17213
|
|
|
16965
17214
|
// src/mcp.ts
|
|
16966
|
-
var SERVER_VERSION = "0.
|
|
17215
|
+
var SERVER_VERSION = "0.6.1";
|
|
16967
17216
|
async function createMcpServer(rootDir) {
|
|
16968
17217
|
const server = new McpServer({
|
|
16969
17218
|
name: "swarmvault",
|
|
@@ -17234,7 +17483,7 @@ async function createMcpServer(rootDir) {
|
|
|
17234
17483
|
},
|
|
17235
17484
|
async () => {
|
|
17236
17485
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17237
|
-
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(
|
|
17486
|
+
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path24.relative(paths.sessionsDir, filePath))).sort();
|
|
17238
17487
|
return asTextResource("swarmvault://sessions", JSON.stringify(files, null, 2));
|
|
17239
17488
|
}
|
|
17240
17489
|
);
|
|
@@ -17267,8 +17516,8 @@ async function createMcpServer(rootDir) {
|
|
|
17267
17516
|
return asTextResource(`swarmvault://pages/${encodedPath}`, `Page not found: ${relativePath}`);
|
|
17268
17517
|
}
|
|
17269
17518
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17270
|
-
const absolutePath =
|
|
17271
|
-
return asTextResource(`swarmvault://pages/${encodedPath}`, await
|
|
17519
|
+
const absolutePath = path24.resolve(paths.wikiDir, relativePath);
|
|
17520
|
+
return asTextResource(`swarmvault://pages/${encodedPath}`, await fs20.readFile(absolutePath, "utf8"));
|
|
17272
17521
|
}
|
|
17273
17522
|
);
|
|
17274
17523
|
server.registerResource(
|
|
@@ -17276,11 +17525,11 @@ async function createMcpServer(rootDir) {
|
|
|
17276
17525
|
new ResourceTemplate("swarmvault://sessions/{path}", {
|
|
17277
17526
|
list: async () => {
|
|
17278
17527
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17279
|
-
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(
|
|
17528
|
+
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path24.relative(paths.sessionsDir, filePath))).sort();
|
|
17280
17529
|
return {
|
|
17281
17530
|
resources: files.map((relativePath) => ({
|
|
17282
17531
|
uri: `swarmvault://sessions/${encodeURIComponent(relativePath)}`,
|
|
17283
|
-
name:
|
|
17532
|
+
name: path24.basename(relativePath, ".md"),
|
|
17284
17533
|
title: relativePath,
|
|
17285
17534
|
description: "SwarmVault session artifact",
|
|
17286
17535
|
mimeType: "text/markdown"
|
|
@@ -17297,11 +17546,11 @@ async function createMcpServer(rootDir) {
|
|
|
17297
17546
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17298
17547
|
const encodedPath = typeof variables.path === "string" ? variables.path : "";
|
|
17299
17548
|
const relativePath = decodeURIComponent(encodedPath);
|
|
17300
|
-
const absolutePath =
|
|
17549
|
+
const absolutePath = path24.resolve(paths.sessionsDir, relativePath);
|
|
17301
17550
|
if (!absolutePath.startsWith(paths.sessionsDir) || !await fileExists(absolutePath)) {
|
|
17302
17551
|
return asTextResource(`swarmvault://sessions/${encodedPath}`, `Session not found: ${relativePath}`);
|
|
17303
17552
|
}
|
|
17304
|
-
return asTextResource(`swarmvault://sessions/${encodedPath}`, await
|
|
17553
|
+
return asTextResource(`swarmvault://sessions/${encodedPath}`, await fs20.readFile(absolutePath, "utf8"));
|
|
17305
17554
|
}
|
|
17306
17555
|
);
|
|
17307
17556
|
return server;
|
|
@@ -17349,13 +17598,13 @@ function asTextResource(uri, text) {
|
|
|
17349
17598
|
}
|
|
17350
17599
|
|
|
17351
17600
|
// src/schedule.ts
|
|
17352
|
-
import
|
|
17353
|
-
import
|
|
17601
|
+
import fs21 from "fs/promises";
|
|
17602
|
+
import path25 from "path";
|
|
17354
17603
|
function scheduleStatePath(schedulesDir, jobId) {
|
|
17355
|
-
return
|
|
17604
|
+
return path25.join(schedulesDir, `${encodeURIComponent(jobId)}.json`);
|
|
17356
17605
|
}
|
|
17357
17606
|
function scheduleLockPath(schedulesDir, jobId) {
|
|
17358
|
-
return
|
|
17607
|
+
return path25.join(schedulesDir, `${encodeURIComponent(jobId)}.lock`);
|
|
17359
17608
|
}
|
|
17360
17609
|
function parseEveryDuration(value) {
|
|
17361
17610
|
const match = value.trim().match(/^(\d+)(m|h|d)$/i);
|
|
@@ -17458,13 +17707,13 @@ async function acquireJobLease(rootDir, jobId) {
|
|
|
17458
17707
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17459
17708
|
const leasePath = scheduleLockPath(paths.schedulesDir, jobId);
|
|
17460
17709
|
await ensureDir(paths.schedulesDir);
|
|
17461
|
-
const handle = await
|
|
17710
|
+
const handle = await fs21.open(leasePath, "wx");
|
|
17462
17711
|
await handle.writeFile(`${process.pid}
|
|
17463
17712
|
${(/* @__PURE__ */ new Date()).toISOString()}
|
|
17464
17713
|
`);
|
|
17465
17714
|
await handle.close();
|
|
17466
17715
|
return async () => {
|
|
17467
|
-
await
|
|
17716
|
+
await fs21.rm(leasePath, { force: true });
|
|
17468
17717
|
};
|
|
17469
17718
|
}
|
|
17470
17719
|
async function listSchedules(rootDir) {
|
|
@@ -17612,8 +17861,9 @@ async function serveSchedules(rootDir, pollMs = 3e4) {
|
|
|
17612
17861
|
|
|
17613
17862
|
// src/sources.ts
|
|
17614
17863
|
import { spawn as spawn2 } from "child_process";
|
|
17615
|
-
import
|
|
17616
|
-
import
|
|
17864
|
+
import fs22 from "fs/promises";
|
|
17865
|
+
import path26 from "path";
|
|
17866
|
+
import matter10 from "gray-matter";
|
|
17617
17867
|
import { JSDOM as JSDOM3 } from "jsdom";
|
|
17618
17868
|
var DEFAULT_CRAWL_MAX_PAGES = 12;
|
|
17619
17869
|
var DEFAULT_CRAWL_MAX_DEPTH = 2;
|
|
@@ -17640,24 +17890,24 @@ function normalizeManagedStatus(value) {
|
|
|
17640
17890
|
return value === "missing" || value === "error" ? value : "ready";
|
|
17641
17891
|
}
|
|
17642
17892
|
function withinRoot2(rootPath, targetPath) {
|
|
17643
|
-
const relative =
|
|
17644
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
17893
|
+
const relative = path26.relative(rootPath, targetPath);
|
|
17894
|
+
return relative === "" || !relative.startsWith("..") && !path26.isAbsolute(relative);
|
|
17645
17895
|
}
|
|
17646
17896
|
async function findNearestGitRoot3(startPath) {
|
|
17647
|
-
let current =
|
|
17897
|
+
let current = path26.resolve(startPath);
|
|
17648
17898
|
try {
|
|
17649
|
-
const stat = await
|
|
17899
|
+
const stat = await fs22.stat(current);
|
|
17650
17900
|
if (!stat.isDirectory()) {
|
|
17651
|
-
current =
|
|
17901
|
+
current = path26.dirname(current);
|
|
17652
17902
|
}
|
|
17653
17903
|
} catch {
|
|
17654
|
-
current =
|
|
17904
|
+
current = path26.dirname(current);
|
|
17655
17905
|
}
|
|
17656
17906
|
while (true) {
|
|
17657
|
-
if (await fileExists(
|
|
17907
|
+
if (await fileExists(path26.join(current, ".git"))) {
|
|
17658
17908
|
return current;
|
|
17659
17909
|
}
|
|
17660
|
-
const parent =
|
|
17910
|
+
const parent = path26.dirname(current);
|
|
17661
17911
|
if (parent === current) {
|
|
17662
17912
|
return null;
|
|
17663
17913
|
}
|
|
@@ -17731,7 +17981,7 @@ function isAllowedDocsCandidate(candidate, startUrl) {
|
|
|
17731
17981
|
if (candidate.origin !== startUrl.origin) {
|
|
17732
17982
|
return false;
|
|
17733
17983
|
}
|
|
17734
|
-
const extension =
|
|
17984
|
+
const extension = path26.extname(candidate.pathname).toLowerCase();
|
|
17735
17985
|
if (extension && extension !== ".html" && extension !== ".htm" && extension !== ".md") {
|
|
17736
17986
|
return false;
|
|
17737
17987
|
}
|
|
@@ -17820,14 +18070,14 @@ function matchesManagedSourceSpec(existing, input) {
|
|
|
17820
18070
|
return false;
|
|
17821
18071
|
}
|
|
17822
18072
|
if (input.kind === "directory" || input.kind === "file") {
|
|
17823
|
-
return
|
|
18073
|
+
return path26.resolve(existing.path ?? "") === path26.resolve(input.path);
|
|
17824
18074
|
}
|
|
17825
18075
|
return (existing.url ?? "") === input.url;
|
|
17826
18076
|
}
|
|
17827
18077
|
async function resolveManagedSourceInput(rootDir, input) {
|
|
17828
|
-
const absoluteInput =
|
|
18078
|
+
const absoluteInput = path26.resolve(rootDir, input);
|
|
17829
18079
|
if (!(input.startsWith("http://") || input.startsWith("https://"))) {
|
|
17830
|
-
const stat = await
|
|
18080
|
+
const stat = await fs22.stat(absoluteInput).catch(() => null);
|
|
17831
18081
|
if (!stat) {
|
|
17832
18082
|
throw new Error(`Source not found: ${input}`);
|
|
17833
18083
|
}
|
|
@@ -17835,7 +18085,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
17835
18085
|
return {
|
|
17836
18086
|
kind: "file",
|
|
17837
18087
|
path: absoluteInput,
|
|
17838
|
-
title:
|
|
18088
|
+
title: path26.basename(absoluteInput, path26.extname(absoluteInput)) || absoluteInput
|
|
17839
18089
|
};
|
|
17840
18090
|
}
|
|
17841
18091
|
if (!stat.isDirectory()) {
|
|
@@ -17847,7 +18097,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
17847
18097
|
kind: "directory",
|
|
17848
18098
|
path: absoluteInput,
|
|
17849
18099
|
repoRoot,
|
|
17850
|
-
title:
|
|
18100
|
+
title: path26.basename(absoluteInput) || absoluteInput
|
|
17851
18101
|
};
|
|
17852
18102
|
}
|
|
17853
18103
|
const github = normalizeGitHubRepoRootUrl(input);
|
|
@@ -17870,16 +18120,16 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
17870
18120
|
};
|
|
17871
18121
|
}
|
|
17872
18122
|
function directorySourceIdsFor(manifests, inputPath) {
|
|
17873
|
-
return manifests.filter((manifest) => manifest.originalPath && withinRoot2(
|
|
18123
|
+
return manifests.filter((manifest) => manifest.originalPath && withinRoot2(path26.resolve(inputPath), path26.resolve(manifest.originalPath))).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
|
|
17874
18124
|
}
|
|
17875
18125
|
function fileSourceIdsFor(manifests, inputPath) {
|
|
17876
|
-
const absoluteInput =
|
|
17877
|
-
return manifests.filter((manifest) => manifest.originalPath &&
|
|
18126
|
+
const absoluteInput = path26.resolve(inputPath);
|
|
18127
|
+
return manifests.filter((manifest) => manifest.originalPath && path26.resolve(manifest.originalPath) === absoluteInput).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
|
|
17878
18128
|
}
|
|
17879
18129
|
async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
17880
18130
|
const manifestsBefore = await listManifests(rootDir);
|
|
17881
18131
|
const previousInScope = manifestsBefore.filter(
|
|
17882
|
-
(manifest) => manifest.originalPath && withinRoot2(
|
|
18132
|
+
(manifest) => manifest.originalPath && withinRoot2(path26.resolve(inputPath), path26.resolve(manifest.originalPath))
|
|
17883
18133
|
);
|
|
17884
18134
|
const result = await ingestDirectory(rootDir, inputPath, { repoRoot });
|
|
17885
18135
|
const removed = [];
|
|
@@ -17887,7 +18137,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
17887
18137
|
if (!manifest.originalPath) {
|
|
17888
18138
|
continue;
|
|
17889
18139
|
}
|
|
17890
|
-
if (await fileExists(
|
|
18140
|
+
if (await fileExists(path26.resolve(manifest.originalPath))) {
|
|
17891
18141
|
continue;
|
|
17892
18142
|
}
|
|
17893
18143
|
const removedManifest = await removeManifestBySourceId(rootDir, manifest.sourceId);
|
|
@@ -17897,7 +18147,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
17897
18147
|
}
|
|
17898
18148
|
const manifestsAfter = await listManifests(rootDir);
|
|
17899
18149
|
return {
|
|
17900
|
-
title:
|
|
18150
|
+
title: path26.basename(inputPath) || inputPath,
|
|
17901
18151
|
sourceIds: directorySourceIdsFor(manifestsAfter, inputPath),
|
|
17902
18152
|
counts: {
|
|
17903
18153
|
scannedCount: result.scannedCount,
|
|
@@ -17913,7 +18163,7 @@ async function syncFileSource(rootDir, inputPath) {
|
|
|
17913
18163
|
const result = await ingestInputDetailed(rootDir, inputPath);
|
|
17914
18164
|
const manifestsAfter = await listManifests(rootDir);
|
|
17915
18165
|
return {
|
|
17916
|
-
title:
|
|
18166
|
+
title: path26.basename(inputPath, path26.extname(inputPath)) || inputPath,
|
|
17917
18167
|
sourceIds: fileSourceIdsFor(manifestsAfter, inputPath),
|
|
17918
18168
|
counts: {
|
|
17919
18169
|
scannedCount: result.scannedCount,
|
|
@@ -17947,8 +18197,8 @@ async function runGitCommand(cwd, args) {
|
|
|
17947
18197
|
}
|
|
17948
18198
|
async function syncGitHubRepoSource(rootDir, entry) {
|
|
17949
18199
|
const workingDir = await managedSourceWorkingDir(rootDir, entry.id);
|
|
17950
|
-
const checkoutDir =
|
|
17951
|
-
await
|
|
18200
|
+
const checkoutDir = path26.join(workingDir, "checkout");
|
|
18201
|
+
await fs22.rm(checkoutDir, { recursive: true, force: true });
|
|
17952
18202
|
await ensureDir(workingDir);
|
|
17953
18203
|
if (!entry.url) {
|
|
17954
18204
|
throw new Error(`Managed source ${entry.id} is missing its repository URL.`);
|
|
@@ -18075,7 +18325,7 @@ function scopedNodeIds(graph, sourceIds) {
|
|
|
18075
18325
|
async function loadSourceAnalyses(rootDir, sourceIds) {
|
|
18076
18326
|
const { paths } = await loadVaultConfig(rootDir);
|
|
18077
18327
|
const analyses = await Promise.all(
|
|
18078
|
-
sourceIds.map(async (sourceId) => await readJsonFile(
|
|
18328
|
+
sourceIds.map(async (sourceId) => await readJsonFile(path26.join(paths.analysesDir, `${sourceId}.json`)))
|
|
18079
18329
|
);
|
|
18080
18330
|
return analyses.filter((analysis) => Boolean(analysis?.sourceId));
|
|
18081
18331
|
}
|
|
@@ -18235,9 +18485,9 @@ async function writeSourceBriefForScope(rootDir, source) {
|
|
|
18235
18485
|
confidence: 0.82
|
|
18236
18486
|
}
|
|
18237
18487
|
});
|
|
18238
|
-
const absolutePath =
|
|
18239
|
-
await ensureDir(
|
|
18240
|
-
await
|
|
18488
|
+
const absolutePath = path26.join(paths.wikiDir, output.page.path);
|
|
18489
|
+
await ensureDir(path26.dirname(absolutePath));
|
|
18490
|
+
await fs22.writeFile(absolutePath, output.content, "utf8");
|
|
18241
18491
|
return absolutePath;
|
|
18242
18492
|
}
|
|
18243
18493
|
async function writeSourceBrief(rootDir, source) {
|
|
@@ -18256,6 +18506,96 @@ async function generateBriefsForSources(rootDir, sources) {
|
|
|
18256
18506
|
}
|
|
18257
18507
|
return briefPaths;
|
|
18258
18508
|
}
|
|
18509
|
+
var GUIDED_SESSION_QUESTIONS = [
|
|
18510
|
+
{
|
|
18511
|
+
id: "importance",
|
|
18512
|
+
prompt: "What matters most from this source for your wiki right now?"
|
|
18513
|
+
},
|
|
18514
|
+
{
|
|
18515
|
+
id: "exclude",
|
|
18516
|
+
prompt: "What should stay provisional, be ignored, or be kept out for now?"
|
|
18517
|
+
},
|
|
18518
|
+
{
|
|
18519
|
+
id: "targets",
|
|
18520
|
+
prompt: "Which canonical pages or topics should this source update?"
|
|
18521
|
+
},
|
|
18522
|
+
{
|
|
18523
|
+
id: "conflicts",
|
|
18524
|
+
prompt: "What feels new, reinforcing, or conflicting compared with what you already believe?"
|
|
18525
|
+
},
|
|
18526
|
+
{
|
|
18527
|
+
id: "followups",
|
|
18528
|
+
prompt: "What follow-up questions or next sources should stay open?"
|
|
18529
|
+
}
|
|
18530
|
+
];
|
|
18531
|
+
function defaultGuidedSessionQuestions() {
|
|
18532
|
+
return GUIDED_SESSION_QUESTIONS.map((question) => ({ ...question }));
|
|
18533
|
+
}
|
|
18534
|
+
function splitDelimitedDetail(value) {
|
|
18535
|
+
return value ? value.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
18536
|
+
}
|
|
18537
|
+
function normalizeGuidedAnswerValue(value) {
|
|
18538
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
18539
|
+
}
|
|
18540
|
+
function normalizeGuidedAnswers(input) {
|
|
18541
|
+
if (!input) {
|
|
18542
|
+
return {};
|
|
18543
|
+
}
|
|
18544
|
+
if (Array.isArray(input)) {
|
|
18545
|
+
return Object.fromEntries(
|
|
18546
|
+
GUIDED_SESSION_QUESTIONS.map((question, index) => [question.id, normalizeGuidedAnswerValue(input[index])]).filter(
|
|
18547
|
+
(entry) => Boolean(entry[1])
|
|
18548
|
+
)
|
|
18549
|
+
);
|
|
18550
|
+
}
|
|
18551
|
+
return Object.fromEntries(
|
|
18552
|
+
Object.entries(input).map(([key, value]) => [key, normalizeGuidedAnswerValue(value)]).filter((entry) => Boolean(entry[1]))
|
|
18553
|
+
);
|
|
18554
|
+
}
|
|
18555
|
+
function mergeGuidedSessionQuestions(questions, answers) {
|
|
18556
|
+
const normalizedAnswers = normalizeGuidedAnswers(answers);
|
|
18557
|
+
return questions.map((question) => ({
|
|
18558
|
+
...question,
|
|
18559
|
+
answer: normalizedAnswers[question.id] ?? question.answer
|
|
18560
|
+
}));
|
|
18561
|
+
}
|
|
18562
|
+
function answeredGuidedSessionQuestions(questions) {
|
|
18563
|
+
return questions.filter((question) => typeof question.answer === "string" && question.answer.trim().length > 0);
|
|
18564
|
+
}
|
|
18565
|
+
function questionStateForSession(session) {
|
|
18566
|
+
return answeredGuidedSessionQuestions(session.questions).length === session.questions.length ? "answered" : "awaiting_input";
|
|
18567
|
+
}
|
|
18568
|
+
function manifestsForScope(graph, scope) {
|
|
18569
|
+
if (!graph) {
|
|
18570
|
+
return [];
|
|
18571
|
+
}
|
|
18572
|
+
const scopeSet = new Set(scope.sourceIds);
|
|
18573
|
+
return graph.sources.filter((manifest) => scopeSet.has(manifest.sourceId));
|
|
18574
|
+
}
|
|
18575
|
+
function scopeSourceType(scope, manifests) {
|
|
18576
|
+
return scope.kind ?? manifests[0]?.sourceKind ?? manifests[0]?.sourceType;
|
|
18577
|
+
}
|
|
18578
|
+
function scopeOccurredAt(manifests) {
|
|
18579
|
+
return manifests.map((manifest) => manifest.details?.occurred_at).filter((value) => typeof value === "string" && value.trim().length > 0).sort((left, right) => right.localeCompare(left))[0];
|
|
18580
|
+
}
|
|
18581
|
+
function scopeParticipants(manifests) {
|
|
18582
|
+
return uniqueStrings4(manifests.flatMap((manifest) => splitDelimitedDetail(manifest.details?.participants)));
|
|
18583
|
+
}
|
|
18584
|
+
function scopeContainerTitle(manifests) {
|
|
18585
|
+
return manifests.find((manifest) => manifest.details?.container_title)?.details?.container_title ?? manifests[0]?.sourceGroupTitle;
|
|
18586
|
+
}
|
|
18587
|
+
function scopeConversationId(manifests) {
|
|
18588
|
+
return manifests.find((manifest) => manifest.details?.conversation_id)?.details?.conversation_id;
|
|
18589
|
+
}
|
|
18590
|
+
function classifyGuidedEvidenceState(scope, targetPage, contradictions) {
|
|
18591
|
+
if (contradictions.length) {
|
|
18592
|
+
return "conflicting";
|
|
18593
|
+
}
|
|
18594
|
+
if (!targetPage) {
|
|
18595
|
+
return "needs_judgment";
|
|
18596
|
+
}
|
|
18597
|
+
return targetPage.sourceIds.some((sourceId) => !scope.sourceIds.includes(sourceId)) ? "reinforcing" : "new";
|
|
18598
|
+
}
|
|
18259
18599
|
function renderDeterministicSourceReview(input) {
|
|
18260
18600
|
const canonicalPages = input.sourcePages.filter((page) => page.kind === "source" || page.kind === "concept" || page.kind === "entity").slice(0, 10);
|
|
18261
18601
|
const modulePages = input.sourcePages.filter((page) => page.kind === "module").slice(0, 8);
|
|
@@ -18356,12 +18696,13 @@ Entities: ${analysis.entities.map((entity) => entity.name).join(", ") || "none"}
|
|
|
18356
18696
|
}
|
|
18357
18697
|
}
|
|
18358
18698
|
async function buildSourceReviewStagedPage(rootDir, scope) {
|
|
18359
|
-
const { paths } = await loadVaultConfig(rootDir);
|
|
18699
|
+
const { config, paths } = await loadVaultConfig(rootDir);
|
|
18360
18700
|
const markdown = await generateSourceReviewMarkdown(rootDir, scope);
|
|
18361
18701
|
if (!markdown) {
|
|
18362
18702
|
throw new Error(`Could not generate a source review for ${scope.id}.`);
|
|
18363
18703
|
}
|
|
18364
18704
|
const graph = await readJsonFile(paths.graphPath);
|
|
18705
|
+
const scopeManifests = manifestsForScope(graph, scope);
|
|
18365
18706
|
const relatedPages = graph ? scopedSourcePages(graph, scope.sourceIds) : [];
|
|
18366
18707
|
const relatedPageIds = relatedPages.slice(0, 16).map((page) => page.id);
|
|
18367
18708
|
const relatedNodeIds = graph ? scopedNodeIds(graph, scope.sourceIds).slice(0, 24) : [];
|
|
@@ -18388,17 +18729,99 @@ async function buildSourceReviewStagedPage(rootDir, scope) {
|
|
|
18388
18729
|
compiledFrom: scope.sourceIds,
|
|
18389
18730
|
managedBy: "system",
|
|
18390
18731
|
confidence: 0.79
|
|
18732
|
+
},
|
|
18733
|
+
frontmatter: {
|
|
18734
|
+
profile_presets: config.profile.presets,
|
|
18735
|
+
source_type: scopeSourceType(scope, scopeManifests),
|
|
18736
|
+
occurred_at: scopeOccurredAt(scopeManifests),
|
|
18737
|
+
participants: scopeParticipants(scopeManifests),
|
|
18738
|
+
container_title: scopeContainerTitle(scopeManifests),
|
|
18739
|
+
conversation_id: scopeConversationId(scopeManifests),
|
|
18740
|
+
question_state: "answered",
|
|
18741
|
+
canonical_targets: relatedPages.filter((page) => page.kind === "source" || page.kind === "concept" || page.kind === "entity").slice(0, 8).map((page) => page.path),
|
|
18742
|
+
evidence_state: findContradictionsForScope(scope, await readGraphReport(rootDir)).length ? "conflicting" : "needs_judgment"
|
|
18391
18743
|
}
|
|
18392
18744
|
});
|
|
18393
18745
|
return { page: output.page, content: output.content };
|
|
18394
18746
|
}
|
|
18395
18747
|
function classifySourceGuidePageBuckets(sourcePages, scopeSourceIds) {
|
|
18396
18748
|
const scopeSet = new Set(scopeSourceIds);
|
|
18397
|
-
const canonicalPages = sourcePages.filter(
|
|
18749
|
+
const canonicalPages = sourcePages.filter(
|
|
18750
|
+
(page) => (page.kind === "source" || page.kind === "concept" || page.kind === "entity") && (page.kind === "source" || page.status !== "candidate")
|
|
18751
|
+
).slice(0, 12);
|
|
18398
18752
|
const newPages = canonicalPages.filter((page) => page.sourceIds.every((sourceId) => scopeSet.has(sourceId))).slice(0, 6);
|
|
18399
18753
|
const reinforcingPages = canonicalPages.filter((page) => page.sourceIds.some((sourceId) => !scopeSet.has(sourceId))).slice(0, 6);
|
|
18400
18754
|
return { canonicalPages, newPages, reinforcingPages };
|
|
18401
18755
|
}
|
|
18756
|
+
function findContradictionsForScope(scope, report) {
|
|
18757
|
+
return report?.contradictions.filter(
|
|
18758
|
+
(contradiction) => scope.sourceIds.includes(contradiction.sourceIdA) || scope.sourceIds.includes(contradiction.sourceIdB)
|
|
18759
|
+
) ?? [];
|
|
18760
|
+
}
|
|
18761
|
+
function selectGuidedTargetPages(scope, sourcePages, questions) {
|
|
18762
|
+
const { canonicalPages } = classifySourceGuidePageBuckets(sourcePages, scope.sourceIds);
|
|
18763
|
+
if (!canonicalPages.length) {
|
|
18764
|
+
return [];
|
|
18765
|
+
}
|
|
18766
|
+
const desiredTargets = normalizeWhitespace(
|
|
18767
|
+
questions.find((question) => question.id === "targets")?.answer ?? questions.find((question) => question.id === "importance")?.answer ?? ""
|
|
18768
|
+
).toLowerCase();
|
|
18769
|
+
const matchedTargets = desiredTargets ? canonicalPages.filter((page) => {
|
|
18770
|
+
const title = page.title.toLowerCase();
|
|
18771
|
+
const relative = page.path.replace(/\.md$/, "").toLowerCase();
|
|
18772
|
+
return desiredTargets.includes(title) || desiredTargets.includes(relative) || title.includes(desiredTargets);
|
|
18773
|
+
}) : [];
|
|
18774
|
+
return (matchedTargets.length ? matchedTargets : canonicalPages).slice(0, 6);
|
|
18775
|
+
}
|
|
18776
|
+
function insightRelativePathForTarget(page, scope) {
|
|
18777
|
+
const basename = path26.basename(page.path);
|
|
18778
|
+
if (page.kind === "concept") {
|
|
18779
|
+
return `insights/concepts/${basename}`;
|
|
18780
|
+
}
|
|
18781
|
+
if (page.kind === "entity") {
|
|
18782
|
+
return `insights/entities/${basename}`;
|
|
18783
|
+
}
|
|
18784
|
+
if (page.kind === "source") {
|
|
18785
|
+
return `insights/sources/${slugify(page.title || scope.title)}.md`;
|
|
18786
|
+
}
|
|
18787
|
+
return `insights/topics/${slugify(page.title || scope.title)}.md`;
|
|
18788
|
+
}
|
|
18789
|
+
function insightTitleForTarget(page, scope) {
|
|
18790
|
+
if (page.kind === "concept" || page.kind === "entity") {
|
|
18791
|
+
return page.title;
|
|
18792
|
+
}
|
|
18793
|
+
if (page.kind === "source") {
|
|
18794
|
+
return `Source Notes: ${page.title}`;
|
|
18795
|
+
}
|
|
18796
|
+
return `${scope.title} Notes`;
|
|
18797
|
+
}
|
|
18798
|
+
function insightTagsForTarget(page) {
|
|
18799
|
+
return uniqueStrings4(["insight", "guided-session", `guided/${page?.kind ?? "topic"}`]);
|
|
18800
|
+
}
|
|
18801
|
+
function guidedUpdateMarker(scopeId) {
|
|
18802
|
+
return {
|
|
18803
|
+
start: `<!-- swarmvault-guided-source:${scopeId}:start -->`,
|
|
18804
|
+
end: `<!-- swarmvault-guided-source:${scopeId}:end -->`
|
|
18805
|
+
};
|
|
18806
|
+
}
|
|
18807
|
+
function replaceMarkedSection(content, scopeId, replacement) {
|
|
18808
|
+
const marker = guidedUpdateMarker(scopeId);
|
|
18809
|
+
const block = `${marker.start}
|
|
18810
|
+
${replacement.trim()}
|
|
18811
|
+
${marker.end}`;
|
|
18812
|
+
const startIndex = content.indexOf(marker.start);
|
|
18813
|
+
const endIndex = content.indexOf(marker.end);
|
|
18814
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
18815
|
+
return `${content.slice(0, startIndex).trimEnd()}
|
|
18816
|
+
|
|
18817
|
+
${block}
|
|
18818
|
+
`;
|
|
18819
|
+
}
|
|
18820
|
+
return `${content.trimEnd()}
|
|
18821
|
+
|
|
18822
|
+
${block}
|
|
18823
|
+
`;
|
|
18824
|
+
}
|
|
18402
18825
|
function renderDeterministicSourceGuide(input) {
|
|
18403
18826
|
const { canonicalPages, newPages, reinforcingPages } = classifySourceGuidePageBuckets(input.sourcePages, input.scope.sourceIds);
|
|
18404
18827
|
const modulePages = input.sourcePages.filter((page) => page.kind === "module").slice(0, 6);
|
|
@@ -18518,13 +18941,16 @@ Entities: ${analysis.entities.map((entity) => entity.name).join(", ") || "none"}
|
|
|
18518
18941
|
}
|
|
18519
18942
|
}
|
|
18520
18943
|
async function buildSourceGuideStagedPage(rootDir, scope) {
|
|
18521
|
-
const { paths } = await loadVaultConfig(rootDir);
|
|
18944
|
+
const { config, paths } = await loadVaultConfig(rootDir);
|
|
18522
18945
|
const markdown = await generateSourceGuideMarkdown(rootDir, scope);
|
|
18523
18946
|
if (!markdown) {
|
|
18524
18947
|
throw new Error(`Could not generate a source guide for ${scope.id}.`);
|
|
18525
18948
|
}
|
|
18526
18949
|
const graph = await readJsonFile(paths.graphPath);
|
|
18950
|
+
const scopeManifests = manifestsForScope(graph, scope);
|
|
18527
18951
|
const relatedPages = graph ? scopedSourcePages(graph, scope.sourceIds) : [];
|
|
18952
|
+
const contradictions = findContradictionsForScope(scope, await readGraphReport(rootDir));
|
|
18953
|
+
const selectedTargets = selectGuidedTargetPages(scope, relatedPages, defaultGuidedSessionQuestions());
|
|
18528
18954
|
const relatedPageIds = relatedPages.slice(0, 18).map((page) => page.id);
|
|
18529
18955
|
const relatedNodeIds = graph ? scopedNodeIds(graph, scope.sourceIds).slice(0, 28) : [];
|
|
18530
18956
|
const projectIds = uniqueStrings4(relatedPages.flatMap((page) => page.projectIds));
|
|
@@ -18550,6 +18976,17 @@ async function buildSourceGuideStagedPage(rootDir, scope) {
|
|
|
18550
18976
|
compiledFrom: scope.sourceIds,
|
|
18551
18977
|
managedBy: "system",
|
|
18552
18978
|
confidence: 0.8
|
|
18979
|
+
},
|
|
18980
|
+
frontmatter: {
|
|
18981
|
+
profile_presets: config.profile.presets,
|
|
18982
|
+
source_type: scopeSourceType(scope, scopeManifests),
|
|
18983
|
+
occurred_at: scopeOccurredAt(scopeManifests),
|
|
18984
|
+
participants: scopeParticipants(scopeManifests),
|
|
18985
|
+
container_title: scopeContainerTitle(scopeManifests),
|
|
18986
|
+
conversation_id: scopeConversationId(scopeManifests),
|
|
18987
|
+
question_state: "answered",
|
|
18988
|
+
canonical_targets: selectedTargets.map((page) => page.path),
|
|
18989
|
+
evidence_state: contradictions.length ? "conflicting" : selectedTargets.some((page) => page.sourceIds.some((sourceId) => !scope.sourceIds.includes(sourceId))) ? "reinforcing" : selectedTargets.length ? "new" : "needs_judgment"
|
|
18553
18990
|
}
|
|
18554
18991
|
});
|
|
18555
18992
|
return { page: output.page, content: output.content };
|
|
@@ -18563,40 +19000,378 @@ async function stageSourceReviewForScope(rootDir, scope) {
|
|
|
18563
19000
|
return {
|
|
18564
19001
|
sourceId: scope.id,
|
|
18565
19002
|
pageId: output.page.id,
|
|
18566
|
-
reviewPath:
|
|
19003
|
+
reviewPath: path26.join(approval.approvalDir, "wiki", output.page.path),
|
|
18567
19004
|
staged: true,
|
|
18568
19005
|
approvalId: approval.approvalId,
|
|
18569
19006
|
approvalDir: approval.approvalDir
|
|
18570
19007
|
};
|
|
18571
19008
|
}
|
|
18572
|
-
|
|
18573
|
-
|
|
19009
|
+
function nextGuidedSourceSessionId(scope) {
|
|
19010
|
+
return `source-session-${slugify(scope.id)}-${sha256(`${scope.id}:${(/* @__PURE__ */ new Date()).toISOString()}`).slice(0, 8)}`;
|
|
19011
|
+
}
|
|
19012
|
+
function shouldReuseGuidedSourceSession(session) {
|
|
19013
|
+
return Boolean(session && session.status === "awaiting_input");
|
|
19014
|
+
}
|
|
19015
|
+
function questionAnswer(questions, id, fallback) {
|
|
19016
|
+
return normalizeGuidedAnswerValue(questions.find((question) => question.id === id)?.answer) ?? fallback;
|
|
19017
|
+
}
|
|
19018
|
+
async function prepareGuidedSourceSession(rootDir, scope, answers) {
|
|
19019
|
+
const existing = await findLatestGuidedSourceSessionByScope(rootDir, scope.id);
|
|
19020
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19021
|
+
const session = shouldReuseGuidedSourceSession(existing) ? {
|
|
19022
|
+
...existing,
|
|
19023
|
+
scopeTitle: scope.title,
|
|
19024
|
+
sourceIds: scope.sourceIds,
|
|
19025
|
+
kind: scope.kind,
|
|
19026
|
+
questions: mergeGuidedSessionQuestions(existing.questions, answers),
|
|
19027
|
+
updatedAt: now
|
|
19028
|
+
} : {
|
|
19029
|
+
sessionId: nextGuidedSourceSessionId(scope),
|
|
19030
|
+
scopeId: scope.id,
|
|
19031
|
+
scopeTitle: scope.title,
|
|
19032
|
+
sourceIds: scope.sourceIds,
|
|
19033
|
+
kind: scope.kind,
|
|
19034
|
+
status: "awaiting_input",
|
|
19035
|
+
createdAt: now,
|
|
19036
|
+
updatedAt: now,
|
|
19037
|
+
questions: mergeGuidedSessionQuestions(defaultGuidedSessionQuestions(), answers),
|
|
19038
|
+
briefPath: scope.briefPath,
|
|
19039
|
+
targetedPagePaths: [],
|
|
19040
|
+
stagedUpdatePaths: []
|
|
19041
|
+
};
|
|
19042
|
+
const statePath = await guidedSourceSessionStatePath(rootDir, session.sessionId);
|
|
19043
|
+
return { session, statePath };
|
|
19044
|
+
}
|
|
19045
|
+
async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
19046
|
+
const { config, paths } = await loadVaultConfig(rootDir);
|
|
19047
|
+
let graph = await readJsonFile(paths.graphPath);
|
|
19048
|
+
if (!graph) {
|
|
19049
|
+
await compileVault(rootDir, {});
|
|
19050
|
+
graph = await readJsonFile(paths.graphPath);
|
|
19051
|
+
}
|
|
19052
|
+
const scopeManifests = manifestsForScope(graph, scope);
|
|
19053
|
+
const sourcePages = graph ? scopedSourcePages(graph, scope.sourceIds) : [];
|
|
19054
|
+
const analyses = await loadSourceAnalyses(rootDir, scope.sourceIds);
|
|
19055
|
+
const report = await readGraphReport(rootDir);
|
|
19056
|
+
const contradictions = findContradictionsForScope(scope, report);
|
|
19057
|
+
const relatedPageIds = uniqueStrings4([
|
|
19058
|
+
...sourcePages.slice(0, 18).map((page) => page.id),
|
|
19059
|
+
...session.targetedPagePaths.map((relativePath) => {
|
|
19060
|
+
const page = graph?.pages.find((candidate) => candidate.path === relativePath);
|
|
19061
|
+
return page?.id ?? "";
|
|
19062
|
+
})
|
|
19063
|
+
]);
|
|
19064
|
+
const relatedNodeIds = graph ? scopedNodeIds(graph, scope.sourceIds).slice(0, 28) : [];
|
|
19065
|
+
const projectIds = uniqueStrings4(sourcePages.flatMap((page) => page.projectIds));
|
|
19066
|
+
const evidenceState = contradictions.length > 0 ? "conflicting" : session.targetedPagePaths.some(
|
|
19067
|
+
(targetPath) => sourcePages.some((page) => page.path === targetPath && page.sourceIds.some((sourceId) => !scope.sourceIds.includes(sourceId)))
|
|
19068
|
+
) ? "reinforcing" : session.targetedPagePaths.length ? "new" : "needs_judgment";
|
|
19069
|
+
const relativeBriefPath = session.briefPath && path26.isAbsolute(session.briefPath) ? path26.relative(paths.wikiDir, session.briefPath) : session.briefPath;
|
|
19070
|
+
const sessionMarkdown = [
|
|
19071
|
+
`# Guided Session: ${scope.title}`,
|
|
19072
|
+
"",
|
|
19073
|
+
`Status: \`${session.status}\``,
|
|
19074
|
+
`Session ID: \`${session.sessionId}\``,
|
|
19075
|
+
...session.approvalId ? [`Approval Bundle: \`${session.approvalId}\``] : [],
|
|
19076
|
+
...relativeBriefPath ? [`Brief: \`${relativeBriefPath}\``] : [],
|
|
19077
|
+
"",
|
|
19078
|
+
"## What This Source Is",
|
|
19079
|
+
"",
|
|
19080
|
+
...analyses.length ? analyses.slice(0, 6).map((analysis) => `- ${analysis.title}: ${analysis.summary}`) : ["- Awaiting compile context."],
|
|
19081
|
+
"",
|
|
19082
|
+
"## Guided Questions",
|
|
19083
|
+
"",
|
|
19084
|
+
...session.questions.flatMap((question) => [`### ${question.prompt}`, "", question.answer ?? "_Awaiting input._", ""]),
|
|
19085
|
+
"## Proposed Wiki Targets",
|
|
19086
|
+
"",
|
|
19087
|
+
...session.targetedPagePaths.length ? session.targetedPagePaths.map((targetPath) => `- [[${targetPath.replace(/\.md$/, "")}]]`) : ["- No canonical update targets selected yet."],
|
|
19088
|
+
"",
|
|
19089
|
+
"## Conflicts And Judgment Calls",
|
|
19090
|
+
"",
|
|
19091
|
+
...contradictions.length ? contradictions.map((contradiction) => `- ${contradiction.claimA} / ${contradiction.claimB}`) : ["- No contradictions are currently flagged for this source scope."],
|
|
19092
|
+
"",
|
|
19093
|
+
"## Follow-up Questions",
|
|
19094
|
+
"",
|
|
19095
|
+
...(() => {
|
|
19096
|
+
const followups = questionAnswer(session.questions, "followups", "");
|
|
19097
|
+
if (followups) {
|
|
19098
|
+
return followups.split(/\n+/).map((line) => line.trim()).filter(Boolean).map((line) => `- ${line.replace(/^-+\s*/, "")}`);
|
|
19099
|
+
}
|
|
19100
|
+
const analysisQuestions = uniqueStrings4(analyses.flatMap((analysis) => analysis.questions)).slice(0, 6);
|
|
19101
|
+
return analysisQuestions.length ? analysisQuestions.map((question) => `- ${question}`) : ["- No follow-up questions recorded yet."];
|
|
19102
|
+
})(),
|
|
19103
|
+
"",
|
|
19104
|
+
"## Related Artifacts",
|
|
19105
|
+
"",
|
|
19106
|
+
`- [[outputs/source-briefs/${scope.id}|Source Brief]]`,
|
|
19107
|
+
`- [[outputs/source-reviews/${scope.id}|Source Review]]`,
|
|
19108
|
+
`- [[outputs/source-guides/${scope.id}|Source Guide]]`,
|
|
19109
|
+
""
|
|
19110
|
+
].join("\n");
|
|
19111
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19112
|
+
const output = buildOutputPage({
|
|
19113
|
+
title: `Guided Session: ${scope.title}`,
|
|
19114
|
+
question: `Guided Session ${scope.title}`,
|
|
19115
|
+
answer: sessionMarkdown,
|
|
19116
|
+
citations: scope.sourceIds,
|
|
19117
|
+
schemaHash: graph?.generatedAt ?? "",
|
|
19118
|
+
outputFormat: "report",
|
|
19119
|
+
relatedPageIds,
|
|
19120
|
+
relatedNodeIds,
|
|
19121
|
+
relatedSourceIds: scope.sourceIds,
|
|
19122
|
+
projectIds,
|
|
19123
|
+
extraTags: ["source-session", "guided-session"],
|
|
19124
|
+
origin: "query",
|
|
19125
|
+
slug: `source-sessions/${scope.id}`,
|
|
19126
|
+
metadata: {
|
|
19127
|
+
status: "active",
|
|
19128
|
+
createdAt: now,
|
|
19129
|
+
updatedAt: now,
|
|
19130
|
+
compiledFrom: scope.sourceIds,
|
|
19131
|
+
managedBy: "system",
|
|
19132
|
+
confidence: 0.81
|
|
19133
|
+
},
|
|
19134
|
+
frontmatter: {
|
|
19135
|
+
profile_presets: config.profile.presets,
|
|
19136
|
+
source_type: scopeSourceType(scope, scopeManifests),
|
|
19137
|
+
occurred_at: scopeOccurredAt(scopeManifests),
|
|
19138
|
+
participants: scopeParticipants(scopeManifests),
|
|
19139
|
+
container_title: scopeContainerTitle(scopeManifests),
|
|
19140
|
+
conversation_id: scopeConversationId(scopeManifests),
|
|
19141
|
+
session_status: session.status,
|
|
19142
|
+
question_state: questionStateForSession(session),
|
|
19143
|
+
canonical_targets: session.targetedPagePaths,
|
|
19144
|
+
evidence_state: evidenceState
|
|
19145
|
+
}
|
|
19146
|
+
});
|
|
19147
|
+
return { page: output.page, content: output.content };
|
|
19148
|
+
}
|
|
19149
|
+
async function persistSourceSessionPage(rootDir, scope, session) {
|
|
19150
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
19151
|
+
const output = await buildSourceSessionSavedPage(rootDir, scope, session);
|
|
19152
|
+
const absolutePath = path26.join(paths.wikiDir, output.page.path);
|
|
19153
|
+
await ensureDir(path26.dirname(absolutePath));
|
|
19154
|
+
await fs22.writeFile(absolutePath, output.content, "utf8");
|
|
19155
|
+
return { pageId: output.page.id, sessionPath: absolutePath };
|
|
19156
|
+
}
|
|
19157
|
+
async function buildGuidedUpdatePages(rootDir, scope, session) {
|
|
19158
|
+
const { config, paths } = await loadVaultConfig(rootDir);
|
|
19159
|
+
let graph = await readJsonFile(paths.graphPath);
|
|
19160
|
+
if (!graph) {
|
|
19161
|
+
await compileVault(rootDir, {});
|
|
19162
|
+
graph = await readJsonFile(paths.graphPath);
|
|
19163
|
+
}
|
|
19164
|
+
if (!graph) {
|
|
19165
|
+
return [];
|
|
19166
|
+
}
|
|
19167
|
+
const sourcePages = scopedSourcePages(graph, scope.sourceIds);
|
|
19168
|
+
const scopeManifests = manifestsForScope(graph, scope);
|
|
19169
|
+
const analyses = await loadSourceAnalyses(rootDir, scope.sourceIds);
|
|
19170
|
+
const report = await readGraphReport(rootDir);
|
|
19171
|
+
const contradictions = findContradictionsForScope(scope, report);
|
|
19172
|
+
const selectedTargets = selectGuidedTargetPages(scope, sourcePages, session.questions);
|
|
19173
|
+
const useCanonicalTargets = config.profile.guidedSessionMode === "canonical_review" && selectedTargets.length > 0;
|
|
19174
|
+
const targetPages = useCanonicalTargets ? selectedTargets : [selectedTargets[0] ?? null];
|
|
19175
|
+
session.targetedPagePaths = uniqueStrings4(
|
|
19176
|
+
useCanonicalTargets ? selectedTargets.map((page) => page.path) : selectedTargets.length ? selectedTargets.map((page) => page.path) : session.targetedPagePaths
|
|
19177
|
+
);
|
|
19178
|
+
return await Promise.all(
|
|
19179
|
+
targetPages.map(async (targetPage) => {
|
|
19180
|
+
const evidenceState = classifyGuidedEvidenceState(scope, targetPage, contradictions);
|
|
19181
|
+
const relativePath = useCanonicalTargets && targetPage ? targetPage.path : targetPage ? insightRelativePathForTarget(targetPage, scope) : `insights/topics/${slugify(scope.title)}.md`;
|
|
19182
|
+
const absolutePath = path26.join(paths.wikiDir, relativePath);
|
|
19183
|
+
const existingContent = await fileExists(absolutePath) ? await fs22.readFile(absolutePath, "utf8") : "";
|
|
19184
|
+
const parsed = existingContent ? matter10(existingContent) : { data: {}, content: "" };
|
|
19185
|
+
const existingData = parsed.data;
|
|
19186
|
+
const existingSourceIds = Array.isArray(existingData.source_ids) ? existingData.source_ids.filter((value) => typeof value === "string") : [];
|
|
19187
|
+
const existingProjectIds = Array.isArray(existingData.project_ids) ? existingData.project_ids.filter((value) => typeof value === "string") : [];
|
|
19188
|
+
const existingNodeIds = Array.isArray(existingData.node_ids) ? existingData.node_ids.filter((value) => typeof value === "string") : [];
|
|
19189
|
+
const existingBacklinks = Array.isArray(existingData.backlinks) ? existingData.backlinks.filter((value) => typeof value === "string") : [];
|
|
19190
|
+
const createdAt = typeof existingData.created_at === "string" && existingData.created_at.trim() ? existingData.created_at : (/* @__PURE__ */ new Date()).toISOString();
|
|
19191
|
+
const title = typeof existingData.title === "string" && existingData.title.trim() || (useCanonicalTargets && targetPage ? targetPage.title : targetPage ? insightTitleForTarget(targetPage, scope) : `${scope.title} Notes`);
|
|
19192
|
+
const baseBody = parsed.content.trim() ? parsed.content.trim() : [
|
|
19193
|
+
`# ${title}`,
|
|
19194
|
+
"",
|
|
19195
|
+
useCanonicalTargets ? "Canonical page maintained by SwarmVault. Guided sessions stage replaceable update blocks here for approval." : "Human-curated insight page. Guided sessions stage replaceable update blocks here.",
|
|
19196
|
+
""
|
|
19197
|
+
].join("\n");
|
|
19198
|
+
const importance = questionAnswer(
|
|
19199
|
+
session.questions,
|
|
19200
|
+
"importance",
|
|
19201
|
+
"Capture the most important new ideas from this source before treating them as canonical."
|
|
19202
|
+
);
|
|
19203
|
+
const exclude = questionAnswer(
|
|
19204
|
+
session.questions,
|
|
19205
|
+
"exclude",
|
|
19206
|
+
"Keep uncertain or incidental details provisional until they matter to the research thread."
|
|
19207
|
+
);
|
|
19208
|
+
const conflictNotes = questionAnswer(
|
|
19209
|
+
session.questions,
|
|
19210
|
+
"conflicts",
|
|
19211
|
+
contradictions.length ? "Review the conflicting evidence before accepting any canonical summary changes." : "No explicit conflicts were called out."
|
|
19212
|
+
);
|
|
19213
|
+
const followups = questionAnswer(session.questions, "followups", "Track follow-up questions on the source session page.");
|
|
19214
|
+
const updateBlock = [
|
|
19215
|
+
`## Guided Session Update: ${scope.title}`,
|
|
19216
|
+
"",
|
|
19217
|
+
`Evidence State: \`${evidenceState}\``,
|
|
19218
|
+
`Session: [[outputs/source-sessions/${scope.id}|Guided Session]]`,
|
|
19219
|
+
`Source Guide: [[outputs/source-guides/${scope.id}|Source Guide]]`,
|
|
19220
|
+
"",
|
|
19221
|
+
"### What Matters Now",
|
|
19222
|
+
"",
|
|
19223
|
+
importance,
|
|
19224
|
+
"",
|
|
19225
|
+
"### Proposed Integration",
|
|
19226
|
+
"",
|
|
19227
|
+
targetPage ? `- Fold the strongest source-backed takeaways into [[${targetPage.path.replace(/\.md$/, "")}|${targetPage.title}]].` : `- Start a durable topic note for ${scope.title}.`,
|
|
19228
|
+
...analyses.slice(0, 5).map((analysis) => `- ${truncate(normalizeWhitespace(analysis.summary), 180)}`),
|
|
19229
|
+
"",
|
|
19230
|
+
"### Keep Provisional Or Out",
|
|
19231
|
+
"",
|
|
19232
|
+
exclude,
|
|
19233
|
+
"",
|
|
19234
|
+
"### Reinforcing Or Conflicting Notes",
|
|
19235
|
+
"",
|
|
19236
|
+
conflictNotes,
|
|
19237
|
+
...contradictions.length ? ["", ...contradictions.slice(0, 4).map((contradiction) => `- ${contradiction.claimA} / ${contradiction.claimB}`)] : [],
|
|
19238
|
+
"",
|
|
19239
|
+
"### Follow-up Questions",
|
|
19240
|
+
"",
|
|
19241
|
+
followups,
|
|
19242
|
+
""
|
|
19243
|
+
].join("\n");
|
|
19244
|
+
const nextBody = replaceMarkedSection(baseBody, scope.id, updateBlock);
|
|
19245
|
+
const content = matter10.stringify(
|
|
19246
|
+
`${nextBody.trimEnd()}
|
|
19247
|
+
`,
|
|
19248
|
+
JSON.parse(
|
|
19249
|
+
JSON.stringify({
|
|
19250
|
+
...existingData,
|
|
19251
|
+
page_id: typeof existingData.page_id === "string" && existingData.page_id.trim() || (useCanonicalTargets && targetPage ? targetPage.id : `insight:${slugify(relativePath.replace(/\.md$/, ""))}`),
|
|
19252
|
+
kind: useCanonicalTargets && targetPage ? targetPage.kind : "insight",
|
|
19253
|
+
title,
|
|
19254
|
+
tags: uniqueStrings4([
|
|
19255
|
+
...Array.isArray(existingData.tags) ? existingData.tags.filter((value) => typeof value === "string") : [],
|
|
19256
|
+
...useCanonicalTargets ? ["guided-session", `guided/${targetPage?.kind ?? "page"}`] : insightTagsForTarget(targetPage)
|
|
19257
|
+
]),
|
|
19258
|
+
source_ids: uniqueStrings4([...existingSourceIds, ...scope.sourceIds]),
|
|
19259
|
+
project_ids: uniqueStrings4([...existingProjectIds, ...targetPage?.projectIds ?? []]),
|
|
19260
|
+
node_ids: uniqueStrings4([...existingNodeIds, ...targetPage?.nodeIds ?? []]),
|
|
19261
|
+
freshness: "fresh",
|
|
19262
|
+
status: existingData.status === "archived" ? "archived" : "active",
|
|
19263
|
+
confidence: 0.83,
|
|
19264
|
+
created_at: createdAt,
|
|
19265
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19266
|
+
compiled_from: uniqueStrings4([
|
|
19267
|
+
...Array.isArray(existingData.compiled_from) ? existingData.compiled_from.filter((value) => typeof value === "string") : [],
|
|
19268
|
+
...scope.sourceIds
|
|
19269
|
+
]),
|
|
19270
|
+
managed_by: typeof existingData.managed_by === "string" && (existingData.managed_by === "human" || existingData.managed_by === "system") ? existingData.managed_by : useCanonicalTargets ? "system" : "human",
|
|
19271
|
+
backlinks: uniqueStrings4([
|
|
19272
|
+
...existingBacklinks,
|
|
19273
|
+
...targetPage ? [targetPage.id] : [],
|
|
19274
|
+
`output:source-sessions/${scope.id}`,
|
|
19275
|
+
`output:source-guides/${scope.id}`
|
|
19276
|
+
]),
|
|
19277
|
+
schema_hash: typeof existingData.schema_hash === "string" ? existingData.schema_hash : "",
|
|
19278
|
+
source_hashes: existingData.source_hashes && typeof existingData.source_hashes === "object" ? existingData.source_hashes : {},
|
|
19279
|
+
source_semantic_hashes: existingData.source_semantic_hashes && typeof existingData.source_semantic_hashes === "object" ? existingData.source_semantic_hashes : {},
|
|
19280
|
+
profile_presets: config.profile.presets,
|
|
19281
|
+
source_type: scopeSourceType(scope, scopeManifests),
|
|
19282
|
+
occurred_at: scopeOccurredAt(scopeManifests),
|
|
19283
|
+
participants: scopeParticipants(scopeManifests),
|
|
19284
|
+
container_title: scopeContainerTitle(scopeManifests),
|
|
19285
|
+
conversation_id: scopeConversationId(scopeManifests),
|
|
19286
|
+
session_status: session.status,
|
|
19287
|
+
question_state: questionStateForSession(session),
|
|
19288
|
+
canonical_targets: useCanonicalTargets ? selectedTargets.map((page2) => page2.path) : [],
|
|
19289
|
+
evidence_state: evidenceState
|
|
19290
|
+
})
|
|
19291
|
+
)
|
|
19292
|
+
);
|
|
19293
|
+
const page = parseStoredPage(relativePath, content, {
|
|
19294
|
+
createdAt,
|
|
19295
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
19296
|
+
});
|
|
19297
|
+
if (!useCanonicalTargets && !selectedTargets.length) {
|
|
19298
|
+
session.targetedPagePaths = uniqueStrings4([...session.targetedPagePaths, relativePath]);
|
|
19299
|
+
}
|
|
19300
|
+
return { page, content, label: "guided-update" };
|
|
19301
|
+
})
|
|
19302
|
+
);
|
|
19303
|
+
}
|
|
19304
|
+
async function stageSourceGuideForScope(rootDir, scope, options = {}) {
|
|
19305
|
+
const { session, statePath } = await prepareGuidedSourceSession(rootDir, scope, options.answers);
|
|
19306
|
+
const briefPath = scope.briefPath ?? session.briefPath ?? await writeSourceBriefForScope(rootDir, scope) ?? void 0;
|
|
19307
|
+
session.briefPath = briefPath;
|
|
18574
19308
|
if (briefPath) {
|
|
18575
19309
|
await refreshVaultAfterOutputSave(rootDir);
|
|
18576
19310
|
}
|
|
19311
|
+
if (answeredGuidedSessionQuestions(session.questions).length === 0) {
|
|
19312
|
+
session.status = "awaiting_input";
|
|
19313
|
+
const persisted2 = await persistSourceSessionPage(rootDir, scope, session);
|
|
19314
|
+
session.sessionPath = persisted2.sessionPath;
|
|
19315
|
+
await writeGuidedSourceSession(rootDir, session);
|
|
19316
|
+
await refreshVaultAfterOutputSave(rootDir);
|
|
19317
|
+
return {
|
|
19318
|
+
sourceId: scope.id,
|
|
19319
|
+
sessionId: session.sessionId,
|
|
19320
|
+
sessionPath: persisted2.sessionPath,
|
|
19321
|
+
sessionStatePath: statePath,
|
|
19322
|
+
status: session.status,
|
|
19323
|
+
questions: session.questions,
|
|
19324
|
+
awaitingInput: true,
|
|
19325
|
+
targetedPagePaths: session.targetedPagePaths,
|
|
19326
|
+
stagedUpdatePaths: session.stagedUpdatePaths,
|
|
19327
|
+
briefPath,
|
|
19328
|
+
staged: false
|
|
19329
|
+
};
|
|
19330
|
+
}
|
|
19331
|
+
session.status = "ready_to_stage";
|
|
19332
|
+
await writeGuidedSourceSession(rootDir, session);
|
|
18577
19333
|
const reviewOutput = await buildSourceReviewStagedPage(rootDir, scope);
|
|
18578
19334
|
const guideOutput = await buildSourceGuideStagedPage(rootDir, {
|
|
18579
19335
|
...scope,
|
|
18580
19336
|
briefPath
|
|
18581
19337
|
});
|
|
19338
|
+
const guidedUpdates = await buildGuidedUpdatePages(rootDir, scope, session);
|
|
19339
|
+
session.stagedUpdatePaths = guidedUpdates.map((item) => item.page.path);
|
|
18582
19340
|
const approval = await stageGeneratedOutputPages(
|
|
18583
19341
|
rootDir,
|
|
18584
19342
|
[
|
|
18585
19343
|
{ page: reviewOutput.page, content: reviewOutput.content, label: "source-review" },
|
|
18586
|
-
{ page: guideOutput.page, content: guideOutput.content, label: "source-guide" }
|
|
19344
|
+
{ page: guideOutput.page, content: guideOutput.content, label: "source-guide" },
|
|
19345
|
+
...guidedUpdates
|
|
18587
19346
|
],
|
|
18588
19347
|
{
|
|
18589
|
-
bundleType: "
|
|
18590
|
-
title: `Guided
|
|
19348
|
+
bundleType: "guided_session",
|
|
19349
|
+
title: `Guided Session: ${scope.title}`,
|
|
19350
|
+
sourceSessionId: session.sessionId
|
|
18591
19351
|
}
|
|
18592
19352
|
);
|
|
19353
|
+
session.status = "staged";
|
|
19354
|
+
session.reviewPath = path26.join(approval.approvalDir, "wiki", reviewOutput.page.path);
|
|
19355
|
+
session.guidePath = path26.join(approval.approvalDir, "wiki", guideOutput.page.path);
|
|
19356
|
+
session.approvalId = approval.approvalId;
|
|
19357
|
+
session.approvalDir = approval.approvalDir;
|
|
19358
|
+
const persisted = await persistSourceSessionPage(rootDir, scope, session);
|
|
19359
|
+
session.sessionPath = persisted.sessionPath;
|
|
19360
|
+
await writeGuidedSourceSession(rootDir, session);
|
|
18593
19361
|
await refreshVaultAfterOutputSave(rootDir);
|
|
18594
19362
|
return {
|
|
18595
19363
|
sourceId: scope.id,
|
|
18596
19364
|
pageId: guideOutput.page.id,
|
|
18597
|
-
guidePath:
|
|
19365
|
+
guidePath: session.guidePath,
|
|
18598
19366
|
reviewPageId: reviewOutput.page.id,
|
|
18599
|
-
reviewPath:
|
|
19367
|
+
reviewPath: session.reviewPath,
|
|
19368
|
+
sessionId: session.sessionId,
|
|
19369
|
+
sessionPath: persisted.sessionPath,
|
|
19370
|
+
sessionStatePath: statePath,
|
|
19371
|
+
status: session.status,
|
|
19372
|
+
questions: session.questions,
|
|
19373
|
+
targetedPagePaths: session.targetedPagePaths,
|
|
19374
|
+
stagedUpdatePaths: session.stagedUpdatePaths,
|
|
18600
19375
|
briefPath,
|
|
18601
19376
|
staged: true,
|
|
18602
19377
|
approvalId: approval.approvalId,
|
|
@@ -18612,53 +19387,82 @@ function scopeFromManagedSource(source) {
|
|
|
18612
19387
|
briefPath: source.briefPath
|
|
18613
19388
|
};
|
|
18614
19389
|
}
|
|
18615
|
-
|
|
18616
|
-
|
|
18617
|
-
|
|
18618
|
-
|
|
18619
|
-
return await stageSourceGuideForScope(rootDir, scope);
|
|
18620
|
-
}
|
|
18621
|
-
async function reviewManagedSource(rootDir, id) {
|
|
18622
|
-
const managedSources = await loadManagedSources(rootDir);
|
|
18623
|
-
const managedSource = managedSources.find((source) => source.id === id);
|
|
18624
|
-
if (managedSource) {
|
|
18625
|
-
if (!await loadVaultConfig(rootDir).then(({ paths }) => fileExists(paths.graphPath))) {
|
|
18626
|
-
await compileVault(rootDir, {});
|
|
18627
|
-
}
|
|
18628
|
-
return await stageSourceReviewForScope(rootDir, scopeFromManagedSource(managedSource));
|
|
18629
|
-
}
|
|
18630
|
-
const manifests = await listManifests(rootDir);
|
|
18631
|
-
const manifest = manifests.find((candidate) => candidate.sourceId === id);
|
|
18632
|
-
if (!manifest) {
|
|
18633
|
-
throw new Error(`Managed source or source id not found: ${id}`);
|
|
18634
|
-
}
|
|
18635
|
-
return await stageSourceReviewForScope(rootDir, {
|
|
18636
|
-
id: manifest.sourceGroupId ?? manifest.sourceId,
|
|
19390
|
+
function scopeFromManifest(manifest, manifests) {
|
|
19391
|
+
const groupId = manifest.sourceGroupId ?? manifest.sourceId;
|
|
19392
|
+
return {
|
|
19393
|
+
id: groupId,
|
|
18637
19394
|
title: manifest.sourceGroupTitle ?? manifest.title,
|
|
18638
19395
|
sourceIds: manifest.sourceGroupId ? manifests.filter((candidate) => candidate.sourceGroupId === manifest.sourceGroupId).map((candidate) => candidate.sourceId) : [manifest.sourceId],
|
|
18639
19396
|
kind: manifest.sourceKind
|
|
18640
|
-
}
|
|
19397
|
+
};
|
|
18641
19398
|
}
|
|
18642
|
-
async function
|
|
19399
|
+
async function resolveSourceScope(rootDir, id) {
|
|
18643
19400
|
const managedSources = await loadManagedSources(rootDir);
|
|
18644
19401
|
const managedSource = managedSources.find((source) => source.id === id);
|
|
18645
19402
|
if (managedSource) {
|
|
18646
|
-
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
|
|
19403
|
+
return scopeFromManagedSource(managedSource);
|
|
19404
|
+
}
|
|
19405
|
+
const latestSession = await findLatestGuidedSourceSessionByScope(rootDir, id);
|
|
19406
|
+
if (latestSession) {
|
|
19407
|
+
return {
|
|
19408
|
+
id: latestSession.scopeId,
|
|
19409
|
+
title: latestSession.scopeTitle,
|
|
19410
|
+
sourceIds: latestSession.sourceIds
|
|
19411
|
+
};
|
|
18650
19412
|
}
|
|
18651
19413
|
const manifests = await listManifests(rootDir);
|
|
18652
|
-
const manifest = manifests.find((candidate) => candidate.sourceId === id);
|
|
19414
|
+
const manifest = manifests.find((candidate) => candidate.sourceId === id) ?? manifests.find((candidate) => candidate.sourceGroupId === id);
|
|
18653
19415
|
if (!manifest) {
|
|
19416
|
+
return null;
|
|
19417
|
+
}
|
|
19418
|
+
return scopeFromManifest(manifest, manifests);
|
|
19419
|
+
}
|
|
19420
|
+
async function reviewSourceScope(rootDir, scope) {
|
|
19421
|
+
return await stageSourceReviewForScope(rootDir, scope);
|
|
19422
|
+
}
|
|
19423
|
+
async function guideSourceScope(rootDir, scope, options = {}) {
|
|
19424
|
+
return await stageSourceGuideForScope(rootDir, scope, options);
|
|
19425
|
+
}
|
|
19426
|
+
async function reviewManagedSource(rootDir, id) {
|
|
19427
|
+
const scope = await resolveSourceScope(rootDir, id);
|
|
19428
|
+
if (!scope) {
|
|
18654
19429
|
throw new Error(`Managed source or source id not found: ${id}`);
|
|
18655
19430
|
}
|
|
18656
|
-
|
|
18657
|
-
|
|
18658
|
-
|
|
18659
|
-
|
|
18660
|
-
|
|
18661
|
-
|
|
19431
|
+
if (!await loadVaultConfig(rootDir).then(({ paths }) => fileExists(paths.graphPath))) {
|
|
19432
|
+
await compileVault(rootDir, {});
|
|
19433
|
+
}
|
|
19434
|
+
return await stageSourceReviewForScope(rootDir, scope);
|
|
19435
|
+
}
|
|
19436
|
+
async function guideManagedSource(rootDir, id, options = {}) {
|
|
19437
|
+
const scope = await resolveSourceScope(rootDir, id);
|
|
19438
|
+
if (!scope) {
|
|
19439
|
+
throw new Error(`Managed source or source id not found: ${id}`);
|
|
19440
|
+
}
|
|
19441
|
+
if (!await loadVaultConfig(rootDir).then(({ paths }) => fileExists(paths.graphPath))) {
|
|
19442
|
+
await compileVault(rootDir, {});
|
|
19443
|
+
}
|
|
19444
|
+
return await stageSourceGuideForScope(rootDir, scope, options);
|
|
19445
|
+
}
|
|
19446
|
+
async function resumeSourceSession(rootDir, id, options = {}) {
|
|
19447
|
+
const existingSession = await readGuidedSourceSession(rootDir, id);
|
|
19448
|
+
if (existingSession) {
|
|
19449
|
+
return await stageSourceGuideForScope(
|
|
19450
|
+
rootDir,
|
|
19451
|
+
{
|
|
19452
|
+
id: existingSession.scopeId,
|
|
19453
|
+
title: existingSession.scopeTitle,
|
|
19454
|
+
sourceIds: existingSession.sourceIds,
|
|
19455
|
+
kind: existingSession.kind,
|
|
19456
|
+
briefPath: existingSession.briefPath
|
|
19457
|
+
},
|
|
19458
|
+
options
|
|
19459
|
+
);
|
|
19460
|
+
}
|
|
19461
|
+
const scope = await resolveSourceScope(rootDir, id);
|
|
19462
|
+
if (!scope) {
|
|
19463
|
+
throw new Error(`Managed source, source scope, or guided session not found: ${id}`);
|
|
19464
|
+
}
|
|
19465
|
+
return await stageSourceGuideForScope(rootDir, scope, options);
|
|
18662
19466
|
}
|
|
18663
19467
|
function shouldCompile(changedSources, graphExists, compileRequested) {
|
|
18664
19468
|
return compileRequested && (!graphExists || changedSources.length > 0);
|
|
@@ -18677,7 +19481,7 @@ async function addManagedSource(rootDir, input, options = {}) {
|
|
|
18677
19481
|
const existing = sources.find((candidate) => matchesManagedSourceSpec(candidate, resolved));
|
|
18678
19482
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18679
19483
|
const source = existing ?? {
|
|
18680
|
-
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind,
|
|
19484
|
+
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind, path26.resolve(resolved.path), resolved.title) : stableManagedSourceId(resolved.kind, resolved.url, resolved.title),
|
|
18681
19485
|
kind: resolved.kind,
|
|
18682
19486
|
title: resolved.title,
|
|
18683
19487
|
path: resolved.kind === "directory" || resolved.kind === "file" ? resolved.path : void 0,
|
|
@@ -18712,10 +19516,14 @@ async function addManagedSource(rootDir, input, options = {}) {
|
|
|
18712
19516
|
const nextSources = existing ? sources.map((candidate) => candidate.id === nextSource.id ? nextSource : candidate) : [...sources, nextSource];
|
|
18713
19517
|
await saveManagedSources(rootDir, nextSources);
|
|
18714
19518
|
const review = reviewRequested && nextSource.status === "ready" ? await stageSourceReviewForScope(rootDir, scopeFromManagedSource(nextSource)) : void 0;
|
|
18715
|
-
const guide = guideRequested && nextSource.status === "ready" ? await stageSourceGuideForScope(
|
|
18716
|
-
|
|
18717
|
-
|
|
18718
|
-
|
|
19519
|
+
const guide = guideRequested && nextSource.status === "ready" ? await stageSourceGuideForScope(
|
|
19520
|
+
rootDir,
|
|
19521
|
+
{
|
|
19522
|
+
...scopeFromManagedSource(nextSource),
|
|
19523
|
+
briefPath: nextSource.briefPath
|
|
19524
|
+
},
|
|
19525
|
+
{ answers: options.guideAnswers }
|
|
19526
|
+
) : void 0;
|
|
18719
19527
|
return {
|
|
18720
19528
|
source: nextSource,
|
|
18721
19529
|
compile,
|
|
@@ -18769,10 +19577,14 @@ async function reloadManagedSources(rootDir, options = {}) {
|
|
|
18769
19577
|
) : [];
|
|
18770
19578
|
const guides = guideRequested ? await Promise.all(
|
|
18771
19579
|
nextSources.filter((source) => selected.some((candidate) => candidate.id === source.id)).filter((source) => source.status === "ready").map(
|
|
18772
|
-
async (source) => await stageSourceGuideForScope(
|
|
18773
|
-
|
|
18774
|
-
|
|
18775
|
-
|
|
19580
|
+
async (source) => await stageSourceGuideForScope(
|
|
19581
|
+
rootDir,
|
|
19582
|
+
{
|
|
19583
|
+
...scopeFromManagedSource(source),
|
|
19584
|
+
briefPath: source.briefPath
|
|
19585
|
+
},
|
|
19586
|
+
{ answers: options.guideAnswers }
|
|
19587
|
+
)
|
|
18776
19588
|
)
|
|
18777
19589
|
) : [];
|
|
18778
19590
|
return {
|
|
@@ -18794,17 +19606,17 @@ async function deleteManagedSource(rootDir, id) {
|
|
|
18794
19606
|
sources.filter((source) => source.id !== id)
|
|
18795
19607
|
);
|
|
18796
19608
|
const workingDir = await managedSourceWorkingDir(rootDir, id);
|
|
18797
|
-
await
|
|
19609
|
+
await fs22.rm(workingDir, { recursive: true, force: true });
|
|
18798
19610
|
return { removed: target };
|
|
18799
19611
|
}
|
|
18800
19612
|
|
|
18801
19613
|
// src/viewer.ts
|
|
18802
19614
|
import { execFile } from "child_process";
|
|
18803
|
-
import
|
|
19615
|
+
import fs23 from "fs/promises";
|
|
18804
19616
|
import http from "http";
|
|
18805
|
-
import
|
|
19617
|
+
import path28 from "path";
|
|
18806
19618
|
import { promisify } from "util";
|
|
18807
|
-
import
|
|
19619
|
+
import matter11 from "gray-matter";
|
|
18808
19620
|
import mime2 from "mime-types";
|
|
18809
19621
|
|
|
18810
19622
|
// src/graph-presentation.ts
|
|
@@ -18926,7 +19738,7 @@ function buildViewerGraphArtifact(graph, options = {}) {
|
|
|
18926
19738
|
}
|
|
18927
19739
|
|
|
18928
19740
|
// src/watch.ts
|
|
18929
|
-
import
|
|
19741
|
+
import path27 from "path";
|
|
18930
19742
|
import process3 from "process";
|
|
18931
19743
|
import chokidar from "chokidar";
|
|
18932
19744
|
var MAX_BACKOFF_MS = 3e4;
|
|
@@ -18934,15 +19746,15 @@ var BACKOFF_THRESHOLD = 3;
|
|
|
18934
19746
|
var CRITICAL_THRESHOLD = 10;
|
|
18935
19747
|
var REPO_WATCH_IGNORES = /* @__PURE__ */ new Set([".git", ".venv"]);
|
|
18936
19748
|
function withinRoot3(rootPath, targetPath) {
|
|
18937
|
-
const relative =
|
|
18938
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
19749
|
+
const relative = path27.relative(rootPath, targetPath);
|
|
19750
|
+
return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
|
|
18939
19751
|
}
|
|
18940
19752
|
function hasIgnoredRepoSegment(baseDir, targetPath) {
|
|
18941
|
-
const relativePath =
|
|
19753
|
+
const relativePath = path27.relative(baseDir, targetPath);
|
|
18942
19754
|
if (!relativePath || relativePath.startsWith("..")) {
|
|
18943
19755
|
return false;
|
|
18944
19756
|
}
|
|
18945
|
-
return relativePath.split(
|
|
19757
|
+
return relativePath.split(path27.sep).some((segment) => REPO_WATCH_IGNORES.has(segment));
|
|
18946
19758
|
}
|
|
18947
19759
|
function workspaceIgnoreRoots(rootDir, paths) {
|
|
18948
19760
|
return [
|
|
@@ -18951,16 +19763,16 @@ function workspaceIgnoreRoots(rootDir, paths) {
|
|
|
18951
19763
|
paths.stateDir,
|
|
18952
19764
|
paths.agentDir,
|
|
18953
19765
|
paths.inboxDir,
|
|
18954
|
-
|
|
18955
|
-
|
|
18956
|
-
|
|
18957
|
-
].map((candidate) =>
|
|
19766
|
+
path27.join(rootDir, ".claude"),
|
|
19767
|
+
path27.join(rootDir, ".cursor"),
|
|
19768
|
+
path27.join(rootDir, ".obsidian")
|
|
19769
|
+
].map((candidate) => path27.resolve(candidate));
|
|
18958
19770
|
}
|
|
18959
19771
|
async function resolveWatchTargets(rootDir, paths, options) {
|
|
18960
|
-
const targets = /* @__PURE__ */ new Set([
|
|
19772
|
+
const targets = /* @__PURE__ */ new Set([path27.resolve(paths.inboxDir)]);
|
|
18961
19773
|
if (options.repo) {
|
|
18962
19774
|
for (const repoRoot of await listTrackedRepoRoots(rootDir)) {
|
|
18963
|
-
targets.add(
|
|
19775
|
+
targets.add(path27.resolve(repoRoot));
|
|
18964
19776
|
}
|
|
18965
19777
|
}
|
|
18966
19778
|
return [...targets].sort((left, right) => left.localeCompare(right));
|
|
@@ -19090,7 +19902,7 @@ async function watchVault(rootDir, options = {}) {
|
|
|
19090
19902
|
const { paths } = await initWorkspace(rootDir);
|
|
19091
19903
|
const baseDebounceMs = options.debounceMs ?? 900;
|
|
19092
19904
|
const ignoredRoots = workspaceIgnoreRoots(rootDir, paths);
|
|
19093
|
-
const inboxWatchRoot =
|
|
19905
|
+
const inboxWatchRoot = path27.resolve(paths.inboxDir);
|
|
19094
19906
|
let watchTargets = await resolveWatchTargets(rootDir, paths, options);
|
|
19095
19907
|
let timer;
|
|
19096
19908
|
let running = false;
|
|
@@ -19105,7 +19917,7 @@ async function watchVault(rootDir, options = {}) {
|
|
|
19105
19917
|
usePolling: true,
|
|
19106
19918
|
interval: 100,
|
|
19107
19919
|
ignored: (targetPath) => {
|
|
19108
|
-
const absolutePath =
|
|
19920
|
+
const absolutePath = path27.resolve(targetPath);
|
|
19109
19921
|
const primaryTarget = watchTargets.filter((watchTarget) => withinRoot3(watchTarget, absolutePath)).sort((left, right) => right.length - left.length)[0] ?? null;
|
|
19110
19922
|
if (!primaryTarget) {
|
|
19111
19923
|
return false;
|
|
@@ -19294,8 +20106,8 @@ async function watchVault(rootDir, options = {}) {
|
|
|
19294
20106
|
}
|
|
19295
20107
|
};
|
|
19296
20108
|
const reasonForPath = (targetPath) => {
|
|
19297
|
-
const baseDir = watchTargets.filter((watchTarget) => withinRoot3(watchTarget,
|
|
19298
|
-
return
|
|
20109
|
+
const baseDir = watchTargets.filter((watchTarget) => withinRoot3(watchTarget, path27.resolve(targetPath))).sort((left, right) => right.length - left.length)[0] ?? paths.inboxDir;
|
|
20110
|
+
return path27.relative(baseDir, targetPath) || ".";
|
|
19299
20111
|
};
|
|
19300
20112
|
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)}`));
|
|
19301
20113
|
await new Promise((resolve, reject) => {
|
|
@@ -19337,15 +20149,15 @@ async function getWatchStatus(rootDir) {
|
|
|
19337
20149
|
var execFileAsync = promisify(execFile);
|
|
19338
20150
|
async function readViewerPage(rootDir, relativePath) {
|
|
19339
20151
|
const { paths } = await loadVaultConfig(rootDir);
|
|
19340
|
-
const absolutePath =
|
|
20152
|
+
const absolutePath = path28.resolve(paths.wikiDir, relativePath);
|
|
19341
20153
|
if (!absolutePath.startsWith(paths.wikiDir) || !await fileExists(absolutePath)) {
|
|
19342
20154
|
return null;
|
|
19343
20155
|
}
|
|
19344
|
-
const raw = await
|
|
19345
|
-
const parsed =
|
|
20156
|
+
const raw = await fs23.readFile(absolutePath, "utf8");
|
|
20157
|
+
const parsed = matter11(raw);
|
|
19346
20158
|
return {
|
|
19347
20159
|
path: relativePath,
|
|
19348
|
-
title: typeof parsed.data.title === "string" ? parsed.data.title :
|
|
20160
|
+
title: typeof parsed.data.title === "string" ? parsed.data.title : path28.basename(relativePath, path28.extname(relativePath)),
|
|
19349
20161
|
frontmatter: parsed.data,
|
|
19350
20162
|
content: parsed.content,
|
|
19351
20163
|
assets: normalizeOutputAssets(parsed.data.output_assets)
|
|
@@ -19353,12 +20165,12 @@ async function readViewerPage(rootDir, relativePath) {
|
|
|
19353
20165
|
}
|
|
19354
20166
|
async function readViewerAsset(rootDir, relativePath) {
|
|
19355
20167
|
const { paths } = await loadVaultConfig(rootDir);
|
|
19356
|
-
const absolutePath =
|
|
20168
|
+
const absolutePath = path28.resolve(paths.wikiDir, relativePath);
|
|
19357
20169
|
if (!absolutePath.startsWith(paths.wikiDir) || !await fileExists(absolutePath)) {
|
|
19358
20170
|
return null;
|
|
19359
20171
|
}
|
|
19360
20172
|
return {
|
|
19361
|
-
buffer: await
|
|
20173
|
+
buffer: await fs23.readFile(absolutePath),
|
|
19362
20174
|
mimeType: mime2.lookup(absolutePath) || "application/octet-stream"
|
|
19363
20175
|
};
|
|
19364
20176
|
}
|
|
@@ -19381,12 +20193,12 @@ async function readJsonBody(request) {
|
|
|
19381
20193
|
return JSON.parse(raw);
|
|
19382
20194
|
}
|
|
19383
20195
|
async function ensureViewerDist(viewerDistDir) {
|
|
19384
|
-
const indexPath =
|
|
20196
|
+
const indexPath = path28.join(viewerDistDir, "index.html");
|
|
19385
20197
|
if (await fileExists(indexPath)) {
|
|
19386
20198
|
return;
|
|
19387
20199
|
}
|
|
19388
|
-
const viewerProjectDir =
|
|
19389
|
-
if (await fileExists(
|
|
20200
|
+
const viewerProjectDir = path28.dirname(viewerDistDir);
|
|
20201
|
+
if (await fileExists(path28.join(viewerProjectDir, "package.json"))) {
|
|
19390
20202
|
await execFileAsync("pnpm", ["build"], { cwd: viewerProjectDir });
|
|
19391
20203
|
}
|
|
19392
20204
|
}
|
|
@@ -19408,7 +20220,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19408
20220
|
response.end(JSON.stringify({ error: "Graph artifact not found. Run `swarmvault compile` first." }));
|
|
19409
20221
|
return;
|
|
19410
20222
|
}
|
|
19411
|
-
const reportPath =
|
|
20223
|
+
const reportPath = path28.join(paths.wikiDir, "graph", "report.json");
|
|
19412
20224
|
const report = await readJsonFile(reportPath) ?? null;
|
|
19413
20225
|
response.writeHead(200, { "content-type": "application/json" });
|
|
19414
20226
|
response.end(JSON.stringify(buildViewerGraphArtifact(graph, { report, full: options.full ?? false })));
|
|
@@ -19468,14 +20280,14 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19468
20280
|
return;
|
|
19469
20281
|
}
|
|
19470
20282
|
if (url.pathname === "/api/graph-report") {
|
|
19471
|
-
const reportPath =
|
|
20283
|
+
const reportPath = path28.join(paths.wikiDir, "graph", "report.json");
|
|
19472
20284
|
if (!await fileExists(reportPath)) {
|
|
19473
20285
|
response.writeHead(404, { "content-type": "application/json" });
|
|
19474
20286
|
response.end(JSON.stringify({ error: "Graph report artifact not found. Run `swarmvault compile` first." }));
|
|
19475
20287
|
return;
|
|
19476
20288
|
}
|
|
19477
20289
|
response.writeHead(200, { "content-type": "application/json" });
|
|
19478
|
-
response.end(await
|
|
20290
|
+
response.end(await fs23.readFile(reportPath, "utf8"));
|
|
19479
20291
|
return;
|
|
19480
20292
|
}
|
|
19481
20293
|
if (url.pathname === "/api/watch-status") {
|
|
@@ -19558,8 +20370,8 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19558
20370
|
return;
|
|
19559
20371
|
}
|
|
19560
20372
|
const relativePath = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
|
|
19561
|
-
const target =
|
|
19562
|
-
const fallback =
|
|
20373
|
+
const target = path28.join(paths.viewerDistDir, relativePath);
|
|
20374
|
+
const fallback = path28.join(paths.viewerDistDir, "index.html");
|
|
19563
20375
|
const filePath = await fileExists(target) ? target : fallback;
|
|
19564
20376
|
if (!await fileExists(filePath)) {
|
|
19565
20377
|
response.writeHead(503, { "content-type": "text/plain" });
|
|
@@ -19567,7 +20379,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19567
20379
|
return;
|
|
19568
20380
|
}
|
|
19569
20381
|
response.writeHead(200, { "content-type": mime2.lookup(filePath) || "text/plain" });
|
|
19570
|
-
response.end(await
|
|
20382
|
+
response.end(await fs23.readFile(filePath));
|
|
19571
20383
|
});
|
|
19572
20384
|
await new Promise((resolve) => {
|
|
19573
20385
|
server.listen(effectivePort, resolve);
|
|
@@ -19594,7 +20406,7 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
19594
20406
|
throw new Error("Graph artifact not found. Run `swarmvault compile` first.");
|
|
19595
20407
|
}
|
|
19596
20408
|
await ensureViewerDist(paths.viewerDistDir);
|
|
19597
|
-
const indexPath =
|
|
20409
|
+
const indexPath = path28.join(paths.viewerDistDir, "index.html");
|
|
19598
20410
|
if (!await fileExists(indexPath)) {
|
|
19599
20411
|
throw new Error("Viewer build not found. Run `pnpm build` first.");
|
|
19600
20412
|
}
|
|
@@ -19620,17 +20432,17 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
19620
20432
|
} : null;
|
|
19621
20433
|
})
|
|
19622
20434
|
);
|
|
19623
|
-
const rawHtml = await
|
|
20435
|
+
const rawHtml = await fs23.readFile(indexPath, "utf8");
|
|
19624
20436
|
const scriptMatch = rawHtml.match(/<script type="module" crossorigin src="([^"]+)"><\/script>/);
|
|
19625
20437
|
const styleMatch = rawHtml.match(/<link rel="stylesheet" crossorigin href="([^"]+)">/);
|
|
19626
|
-
const scriptPath = scriptMatch?.[1] ?
|
|
19627
|
-
const stylePath = styleMatch?.[1] ?
|
|
20438
|
+
const scriptPath = scriptMatch?.[1] ? path28.join(paths.viewerDistDir, scriptMatch[1].replace(/^\//, "")) : null;
|
|
20439
|
+
const stylePath = styleMatch?.[1] ? path28.join(paths.viewerDistDir, styleMatch[1].replace(/^\//, "")) : null;
|
|
19628
20440
|
if (!scriptPath || !await fileExists(scriptPath)) {
|
|
19629
20441
|
throw new Error("Viewer script bundle not found. Run `pnpm build` first.");
|
|
19630
20442
|
}
|
|
19631
|
-
const script = await
|
|
19632
|
-
const style = stylePath && await fileExists(stylePath) ? await
|
|
19633
|
-
const report = await readJsonFile(
|
|
20443
|
+
const script = await fs23.readFile(scriptPath, "utf8");
|
|
20444
|
+
const style = stylePath && await fileExists(stylePath) ? await fs23.readFile(stylePath, "utf8") : "";
|
|
20445
|
+
const report = await readJsonFile(path28.join(paths.wikiDir, "graph", "report.json"));
|
|
19634
20446
|
const embeddedData = JSON.stringify(
|
|
19635
20447
|
{ graph: buildViewerGraphArtifact(graph, { report, full: options.full ?? false }), pages: pages.filter(Boolean), report },
|
|
19636
20448
|
null,
|
|
@@ -19653,9 +20465,9 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
19653
20465
|
"</html>",
|
|
19654
20466
|
""
|
|
19655
20467
|
].filter(Boolean).join("\n");
|
|
19656
|
-
await
|
|
19657
|
-
await
|
|
19658
|
-
return
|
|
20468
|
+
await fs23.mkdir(path28.dirname(outputPath), { recursive: true });
|
|
20469
|
+
await fs23.writeFile(outputPath, html, "utf8");
|
|
20470
|
+
return path28.resolve(outputPath);
|
|
19659
20471
|
}
|
|
19660
20472
|
export {
|
|
19661
20473
|
acceptApproval,
|
|
@@ -19717,6 +20529,7 @@ export {
|
|
|
19717
20529
|
rejectApproval,
|
|
19718
20530
|
reloadManagedSources,
|
|
19719
20531
|
resolvePaths,
|
|
20532
|
+
resumeSourceSession,
|
|
19720
20533
|
reviewManagedSource,
|
|
19721
20534
|
reviewSourceScope,
|
|
19722
20535
|
runSchedule,
|