@swarmvaultai/engine 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-FD3LJQ4T.js +1216 -0
- package/dist/index.d.ts +54 -8
- package/dist/index.js +909 -315
- package/dist/registry-XOPLQNZY.js +12 -0
- package/package.json +1 -1
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-FD3LJQ4T.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
|
|
|
@@ -11137,15 +11137,15 @@ function sourceTypeForNode(node, pagesById) {
|
|
|
11137
11137
|
return pagesById.get(node.pageId)?.sourceType;
|
|
11138
11138
|
}
|
|
11139
11139
|
function supportingPathDetails(graph, edge) {
|
|
11140
|
-
const
|
|
11140
|
+
const path29 = shortestGraphPath(graph, edge.source, edge.target);
|
|
11141
11141
|
const edgesById = new Map(graph.edges.map((item) => [item.id, item]));
|
|
11142
|
-
const pathEdges =
|
|
11142
|
+
const pathEdges = path29.edgeIds.map((edgeId) => edgesById.get(edgeId)).filter((item) => Boolean(item));
|
|
11143
11143
|
return {
|
|
11144
|
-
pathNodeIds:
|
|
11145
|
-
pathEdgeIds:
|
|
11144
|
+
pathNodeIds: path29.nodeIds,
|
|
11145
|
+
pathEdgeIds: path29.edgeIds,
|
|
11146
11146
|
pathRelations: pathEdges.map((item) => item.relation),
|
|
11147
11147
|
pathEvidenceClasses: pathEdges.map((item) => item.evidenceClass),
|
|
11148
|
-
pathSummary:
|
|
11148
|
+
pathSummary: path29.summary
|
|
11149
11149
|
};
|
|
11150
11150
|
}
|
|
11151
11151
|
function surpriseScore(edge, graph, pagesById, hyperedgesByNodeId) {
|
|
@@ -11214,7 +11214,7 @@ function topSurprisingConnections(graph, pagesById) {
|
|
|
11214
11214
|
}).map((edge) => {
|
|
11215
11215
|
const source = nodesById.get(edge.source);
|
|
11216
11216
|
const target = nodesById.get(edge.target);
|
|
11217
|
-
const
|
|
11217
|
+
const path29 = supportingPathDetails(graph, edge);
|
|
11218
11218
|
const scored = surpriseScore(edge, graph, pagesById, hyperedgesByNodeId);
|
|
11219
11219
|
return {
|
|
11220
11220
|
id: edge.id,
|
|
@@ -11225,11 +11225,11 @@ function topSurprisingConnections(graph, pagesById) {
|
|
|
11225
11225
|
relation: edge.relation,
|
|
11226
11226
|
evidenceClass: edge.evidenceClass,
|
|
11227
11227
|
confidence: edge.confidence,
|
|
11228
|
-
pathNodeIds:
|
|
11229
|
-
pathEdgeIds:
|
|
11230
|
-
pathRelations:
|
|
11231
|
-
pathEvidenceClasses:
|
|
11232
|
-
pathSummary:
|
|
11228
|
+
pathNodeIds: path29.pathNodeIds,
|
|
11229
|
+
pathEdgeIds: path29.pathEdgeIds,
|
|
11230
|
+
pathRelations: path29.pathRelations,
|
|
11231
|
+
pathEvidenceClasses: path29.pathEvidenceClasses,
|
|
11232
|
+
pathSummary: path29.pathSummary,
|
|
11233
11233
|
why: scored.why,
|
|
11234
11234
|
explanation: scored.explanation,
|
|
11235
11235
|
surpriseScore: scored.score
|
|
@@ -12691,6 +12691,58 @@ function searchPages(dbPath, query, limitOrOptions = 5) {
|
|
|
12691
12691
|
}));
|
|
12692
12692
|
}
|
|
12693
12693
|
|
|
12694
|
+
// src/source-sessions.ts
|
|
12695
|
+
import fs18 from "fs/promises";
|
|
12696
|
+
import path22 from "path";
|
|
12697
|
+
function sessionStatePathFor(paths, sessionId) {
|
|
12698
|
+
return path22.join(paths.sourceSessionsDir, `${sessionId}.json`);
|
|
12699
|
+
}
|
|
12700
|
+
async function listGuidedSourceSessions(rootDir) {
|
|
12701
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12702
|
+
const entries = await fs18.readdir(paths.sourceSessionsDir, { withFileTypes: true }).catch(() => []);
|
|
12703
|
+
const sessions = await Promise.all(
|
|
12704
|
+
entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => await readJsonFile(path22.join(paths.sourceSessionsDir, entry.name)))
|
|
12705
|
+
);
|
|
12706
|
+
return sessions.filter((session) => Boolean(session)).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
12707
|
+
}
|
|
12708
|
+
async function readGuidedSourceSession(rootDir, sessionId) {
|
|
12709
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12710
|
+
return await readJsonFile(sessionStatePathFor(paths, sessionId));
|
|
12711
|
+
}
|
|
12712
|
+
async function findLatestGuidedSourceSessionByScope(rootDir, scopeId) {
|
|
12713
|
+
const sessions = await listGuidedSourceSessions(rootDir);
|
|
12714
|
+
return sessions.find((session) => session.scopeId === scopeId) ?? null;
|
|
12715
|
+
}
|
|
12716
|
+
async function writeGuidedSourceSession(rootDir, session) {
|
|
12717
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12718
|
+
await ensureDir(paths.sourceSessionsDir);
|
|
12719
|
+
const next = {
|
|
12720
|
+
...session,
|
|
12721
|
+
updatedAt: session.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
12722
|
+
};
|
|
12723
|
+
const filePath = sessionStatePathFor(paths, session.sessionId);
|
|
12724
|
+
await fs18.writeFile(filePath, `${JSON.stringify(next, null, 2)}
|
|
12725
|
+
`, "utf8");
|
|
12726
|
+
return filePath;
|
|
12727
|
+
}
|
|
12728
|
+
async function updateGuidedSourceSessionStatus(rootDir, sessionId, status) {
|
|
12729
|
+
const existing = await readGuidedSourceSession(rootDir, sessionId);
|
|
12730
|
+
if (!existing) {
|
|
12731
|
+
return null;
|
|
12732
|
+
}
|
|
12733
|
+
const next = {
|
|
12734
|
+
...existing,
|
|
12735
|
+
status,
|
|
12736
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12737
|
+
};
|
|
12738
|
+
await writeGuidedSourceSession(rootDir, next);
|
|
12739
|
+
return next;
|
|
12740
|
+
}
|
|
12741
|
+
async function guidedSourceSessionStatePath(rootDir, sessionId) {
|
|
12742
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
12743
|
+
return sessionStatePathFor(paths, sessionId);
|
|
12744
|
+
}
|
|
12745
|
+
|
|
12694
12746
|
// src/vault.ts
|
|
12695
12747
|
var COMPILE_PROGRESS_THRESHOLD = 120;
|
|
12696
12748
|
var COMPILE_PROGRESS_UPDATE_INTERVAL = 50;
|
|
@@ -12745,7 +12797,7 @@ function outputFormatInstruction(format) {
|
|
|
12745
12797
|
}
|
|
12746
12798
|
}
|
|
12747
12799
|
function outputAssetPath(slug, fileName) {
|
|
12748
|
-
return toPosix(
|
|
12800
|
+
return toPosix(path23.join("outputs", "assets", slug, fileName));
|
|
12749
12801
|
}
|
|
12750
12802
|
function outputAssetId(slug, role) {
|
|
12751
12803
|
return `output:${slug}:asset:${role}`;
|
|
@@ -12885,7 +12937,7 @@ async function resolveImageGenerationProvider(rootDir) {
|
|
|
12885
12937
|
if (!providerConfig) {
|
|
12886
12938
|
throw new Error(`No provider configured with id "${preferredProviderId}" for task "imageProvider".`);
|
|
12887
12939
|
}
|
|
12888
|
-
const { createProvider: createProvider2 } = await import("./registry-
|
|
12940
|
+
const { createProvider: createProvider2 } = await import("./registry-XOPLQNZY.js");
|
|
12889
12941
|
return createProvider2(preferredProviderId, providerConfig, rootDir);
|
|
12890
12942
|
}
|
|
12891
12943
|
async function generateOutputArtifacts(rootDir, input) {
|
|
@@ -13083,7 +13135,7 @@ async function generateOutputArtifacts(rootDir, input) {
|
|
|
13083
13135
|
};
|
|
13084
13136
|
}
|
|
13085
13137
|
function normalizeProjectRoot(root) {
|
|
13086
|
-
const normalized = toPosix(
|
|
13138
|
+
const normalized = toPosix(path23.posix.normalize(root.replace(/\\/g, "/"))).replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
13087
13139
|
return normalized;
|
|
13088
13140
|
}
|
|
13089
13141
|
function projectEntries(config) {
|
|
@@ -13109,10 +13161,10 @@ function manifestPathForProject(rootDir, manifest) {
|
|
|
13109
13161
|
if (!rawPath) {
|
|
13110
13162
|
return toPosix(manifest.storedPath);
|
|
13111
13163
|
}
|
|
13112
|
-
if (!
|
|
13164
|
+
if (!path23.isAbsolute(rawPath)) {
|
|
13113
13165
|
return normalizeProjectRoot(rawPath);
|
|
13114
13166
|
}
|
|
13115
|
-
const relative = toPosix(
|
|
13167
|
+
const relative = toPosix(path23.relative(rootDir, rawPath));
|
|
13116
13168
|
return relative.startsWith("..") ? toPosix(rawPath) : normalizeProjectRoot(relative);
|
|
13117
13169
|
}
|
|
13118
13170
|
function prefixMatches(value, prefix) {
|
|
@@ -13265,6 +13317,7 @@ function approvalSummary(manifest) {
|
|
|
13265
13317
|
createdAt: manifest.createdAt,
|
|
13266
13318
|
bundleType: manifest.bundleType,
|
|
13267
13319
|
title: manifest.title,
|
|
13320
|
+
sourceSessionId: manifest.sourceSessionId,
|
|
13268
13321
|
entryCount: manifest.entries.length,
|
|
13269
13322
|
pendingCount: manifest.entries.filter((entry) => entry.status === "pending").length,
|
|
13270
13323
|
acceptedCount: manifest.entries.filter((entry) => entry.status === "accepted").length,
|
|
@@ -13288,7 +13341,7 @@ function pageHashes(pages) {
|
|
|
13288
13341
|
return Object.fromEntries(pages.map((page) => [page.page.id, page.contentHash]));
|
|
13289
13342
|
}
|
|
13290
13343
|
async function buildManagedGraphPage(absolutePath, defaults, build) {
|
|
13291
|
-
const existingContent = await fileExists(absolutePath) ? await
|
|
13344
|
+
const existingContent = await fileExists(absolutePath) ? await fs19.readFile(absolutePath, "utf8") : null;
|
|
13292
13345
|
let existing = await loadExistingManagedPageState(absolutePath, {
|
|
13293
13346
|
status: defaults.status ?? "active",
|
|
13294
13347
|
managedBy: defaults.managedBy
|
|
@@ -13326,7 +13379,7 @@ async function buildManagedGraphPage(absolutePath, defaults, build) {
|
|
|
13326
13379
|
return built;
|
|
13327
13380
|
}
|
|
13328
13381
|
async function buildManagedContent(absolutePath, defaults, build) {
|
|
13329
|
-
const existingContent = await fileExists(absolutePath) ? await
|
|
13382
|
+
const existingContent = await fileExists(absolutePath) ? await fs19.readFile(absolutePath, "utf8") : null;
|
|
13330
13383
|
let existing = await loadExistingManagedPageState(absolutePath, {
|
|
13331
13384
|
status: defaults.status ?? "active",
|
|
13332
13385
|
managedBy: defaults.managedBy
|
|
@@ -13368,7 +13421,7 @@ function manifestDetailValue(manifest, key) {
|
|
|
13368
13421
|
}
|
|
13369
13422
|
async function loadAnalysesBySourceIds(paths, sourceIds) {
|
|
13370
13423
|
const analyses = await Promise.all(
|
|
13371
|
-
sourceIds.map(async (sourceId) => await readJsonFile(
|
|
13424
|
+
sourceIds.map(async (sourceId) => await readJsonFile(path23.join(paths.analysesDir, `${sourceId}.json`)))
|
|
13372
13425
|
);
|
|
13373
13426
|
return analyses.filter((analysis) => Boolean(analysis?.sourceId));
|
|
13374
13427
|
}
|
|
@@ -13377,6 +13430,7 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13377
13430
|
const reviewPages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-reviews/"));
|
|
13378
13431
|
const briefPages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-briefs/"));
|
|
13379
13432
|
const guidePages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-guides/"));
|
|
13433
|
+
const sessionPages = graph.pages.filter((page) => page.kind === "output" && page.path.startsWith("outputs/source-sessions/"));
|
|
13380
13434
|
const conceptPages = graph.pages.filter((page) => page.kind === "concept" && page.status !== "candidate").slice(0, 16);
|
|
13381
13435
|
const entityPages = graph.pages.filter((page) => page.kind === "entity" && page.status !== "candidate").slice(0, 16);
|
|
13382
13436
|
const manifests = graph.sources;
|
|
@@ -13387,9 +13441,10 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13387
13441
|
const openQuestions = uniqueStrings3(
|
|
13388
13442
|
analyses.flatMap((analysis) => analysis.questions.map((question) => `${analysis.title}: ${question}`))
|
|
13389
13443
|
).slice(0, 20);
|
|
13444
|
+
const sourceSessions = await listGuidedSourceSessions(paths.rootDir);
|
|
13390
13445
|
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);
|
|
13446
|
+
(await fs19.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => await readJsonFile(approvalManifestPath(paths, entry.name)))
|
|
13447
|
+
)).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);
|
|
13393
13448
|
const dashboards = [
|
|
13394
13449
|
{
|
|
13395
13450
|
relativePath: "dashboards/index.md",
|
|
@@ -13401,6 +13456,7 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13401
13456
|
"- [[dashboards/recent-sources|Recent Sources]]",
|
|
13402
13457
|
"- [[dashboards/reading-log|Reading Log]]",
|
|
13403
13458
|
"- [[dashboards/timeline|Timeline]]",
|
|
13459
|
+
"- [[dashboards/source-sessions|Source Sessions]]",
|
|
13404
13460
|
"- [[dashboards/source-guides|Source Guides]]",
|
|
13405
13461
|
"- [[dashboards/research-map|Research Map]]",
|
|
13406
13462
|
"- [[dashboards/contradictions|Contradictions]]",
|
|
@@ -13487,6 +13543,14 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13487
13543
|
const participants = manifestDetailValue(manifest, "participants");
|
|
13488
13544
|
return `- ${occurredAt}: ${manifest.title}${participants ? ` (${participants})` : ""}`;
|
|
13489
13545
|
}) : recentSourcePages.map((page) => `- ${page.updatedAt}: [[${page.path.replace(/\.md$/, "")}|${page.title}]]`),
|
|
13546
|
+
...sourceSessions.length ? [
|
|
13547
|
+
"",
|
|
13548
|
+
"## Active Guided Sessions",
|
|
13549
|
+
"",
|
|
13550
|
+
...sourceSessions.slice(0, 8).map(
|
|
13551
|
+
(session) => `- ${session.updatedAt}: \`${session.status}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`
|
|
13552
|
+
)
|
|
13553
|
+
] : [],
|
|
13490
13554
|
"",
|
|
13491
13555
|
"```dataview",
|
|
13492
13556
|
"TABLE occurred_at, source_type, participants, container_title",
|
|
@@ -13561,6 +13625,59 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13561
13625
|
}
|
|
13562
13626
|
)
|
|
13563
13627
|
},
|
|
13628
|
+
{
|
|
13629
|
+
relativePath: "dashboards/source-sessions.md",
|
|
13630
|
+
title: "Source Sessions",
|
|
13631
|
+
content: (metadata) => matter9.stringify(
|
|
13632
|
+
[
|
|
13633
|
+
"# Source Sessions",
|
|
13634
|
+
"",
|
|
13635
|
+
"## Active Sessions",
|
|
13636
|
+
"",
|
|
13637
|
+
...sourceSessions.length ? sourceSessions.slice(0, 16).map(
|
|
13638
|
+
(session) => `- ${session.updatedAt}: \`${session.status}\` \`${session.sessionId}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`
|
|
13639
|
+
) : ["- No guided source sessions yet."],
|
|
13640
|
+
"",
|
|
13641
|
+
"## Pending Guided Bundles",
|
|
13642
|
+
"",
|
|
13643
|
+
...stagedGuideBundles.length ? stagedGuideBundles.map(
|
|
13644
|
+
(bundle) => `- ${bundle.createdAt}: \`${bundle.approvalId}\`${bundle.title ? ` ${bundle.title}` : ""} (${bundle.entries.length} staged entr${bundle.entries.length === 1 ? "y" : "ies"})`
|
|
13645
|
+
) : ["- No staged guided bundles right now."],
|
|
13646
|
+
"",
|
|
13647
|
+
"```dataview",
|
|
13648
|
+
'LIST FROM "outputs/source-sessions"',
|
|
13649
|
+
"SORT file.mtime desc",
|
|
13650
|
+
"```",
|
|
13651
|
+
""
|
|
13652
|
+
].join("\n"),
|
|
13653
|
+
{
|
|
13654
|
+
page_id: "dashboards:source-sessions",
|
|
13655
|
+
kind: "index",
|
|
13656
|
+
title: "Source Sessions",
|
|
13657
|
+
tags: ["index", "dashboard", "source-sessions"],
|
|
13658
|
+
source_ids: uniqueStrings3([
|
|
13659
|
+
...sessionPages.flatMap((page) => page.sourceIds),
|
|
13660
|
+
...sourceSessions.flatMap((session) => session.sourceIds)
|
|
13661
|
+
]),
|
|
13662
|
+
project_ids: [],
|
|
13663
|
+
node_ids: [],
|
|
13664
|
+
freshness: "fresh",
|
|
13665
|
+
status: metadata.status,
|
|
13666
|
+
confidence: 1,
|
|
13667
|
+
created_at: metadata.createdAt,
|
|
13668
|
+
updated_at: metadata.updatedAt,
|
|
13669
|
+
compiled_from: uniqueStrings3([
|
|
13670
|
+
...sessionPages.flatMap((page) => page.sourceIds),
|
|
13671
|
+
...sourceSessions.flatMap((session) => session.sourceIds)
|
|
13672
|
+
]),
|
|
13673
|
+
managed_by: metadata.managedBy,
|
|
13674
|
+
backlinks: [],
|
|
13675
|
+
schema_hash: schemaHash,
|
|
13676
|
+
source_hashes: {},
|
|
13677
|
+
source_semantic_hashes: {}
|
|
13678
|
+
}
|
|
13679
|
+
)
|
|
13680
|
+
},
|
|
13564
13681
|
{
|
|
13565
13682
|
relativePath: "dashboards/source-guides.md",
|
|
13566
13683
|
title: "Source Guides",
|
|
@@ -13628,6 +13745,10 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13628
13745
|
"## Recently Guided Sources",
|
|
13629
13746
|
"",
|
|
13630
13747
|
...guidePages.length ? guidePages.slice(0, 8).map((page) => `- [[${page.path.replace(/\.md$/, "")}|${page.title}]]`) : ["- No accepted source guides yet."],
|
|
13748
|
+
"",
|
|
13749
|
+
"## Active Source Sessions",
|
|
13750
|
+
"",
|
|
13751
|
+
...sourceSessions.length ? sourceSessions.slice(0, 8).map((session) => `- \`${session.status}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`) : ["- No active source sessions yet."],
|
|
13631
13752
|
...report?.suggestedQuestions?.length ? ["", "## Suggested Questions", "", ...report.suggestedQuestions.slice(0, 8).map((question) => `- ${question}`)] : [],
|
|
13632
13753
|
"",
|
|
13633
13754
|
"```dataview",
|
|
@@ -13722,9 +13843,15 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13722
13843
|
"# Open Questions",
|
|
13723
13844
|
"",
|
|
13724
13845
|
...openQuestions.length ? openQuestions.map((question) => `- ${question}`) : ["- No open questions are currently extracted."],
|
|
13846
|
+
...sourceSessions.length ? [
|
|
13847
|
+
"",
|
|
13848
|
+
"## Active Guided Sessions",
|
|
13849
|
+
"",
|
|
13850
|
+
...sourceSessions.filter((session) => session.status === "awaiting_input" || session.status === "staged").slice(0, 8).map((session) => `- \`${session.status}\` [[outputs/source-sessions/${session.scopeId}|${session.scopeTitle}]]`)
|
|
13851
|
+
] : [],
|
|
13725
13852
|
"",
|
|
13726
13853
|
"```dataview",
|
|
13727
|
-
'LIST FROM "outputs/source-briefs" OR "outputs/source-reviews" OR "outputs/source-guides"',
|
|
13854
|
+
'LIST FROM "outputs/source-briefs" OR "outputs/source-reviews" OR "outputs/source-guides" OR "outputs/source-sessions"',
|
|
13728
13855
|
"SORT file.mtime desc",
|
|
13729
13856
|
"```",
|
|
13730
13857
|
""
|
|
@@ -13754,7 +13881,7 @@ async function buildDashboardRecords(paths, graph, schemaHash, report) {
|
|
|
13754
13881
|
];
|
|
13755
13882
|
const records = [];
|
|
13756
13883
|
for (const dashboard of dashboards) {
|
|
13757
|
-
const absolutePath =
|
|
13884
|
+
const absolutePath = path23.join(paths.wikiDir, dashboard.relativePath);
|
|
13758
13885
|
const compiledFrom = dashboard.relativePath === "dashboards/recent-sources.md" ? recentSourcePages.flatMap((page) => page.sourceIds) : [];
|
|
13759
13886
|
const content = await buildManagedContent(
|
|
13760
13887
|
absolutePath,
|
|
@@ -13868,7 +13995,7 @@ function resetGraphNodeMetrics(nodes) {
|
|
|
13868
13995
|
return nodes.map(({ communityId: _communityId, degree: _degree, bridgeScore: _bridgeScore, isGodNode: _isGodNode, ...node }) => node);
|
|
13869
13996
|
}
|
|
13870
13997
|
function manifestRepoPath(manifest) {
|
|
13871
|
-
return toPosix(manifest.repoRelativePath ??
|
|
13998
|
+
return toPosix(manifest.repoRelativePath ?? path23.basename(manifest.originalPath ?? manifest.storedPath));
|
|
13872
13999
|
}
|
|
13873
14000
|
function goPackageScopeKey(manifest, analysis) {
|
|
13874
14001
|
if (analysis.code?.language !== "go") {
|
|
@@ -13878,7 +14005,7 @@ function goPackageScopeKey(manifest, analysis) {
|
|
|
13878
14005
|
if (!packageName) {
|
|
13879
14006
|
return null;
|
|
13880
14007
|
}
|
|
13881
|
-
return `${packageName}:${
|
|
14008
|
+
return `${packageName}:${path23.posix.dirname(manifestRepoPath(manifest))}`;
|
|
13882
14009
|
}
|
|
13883
14010
|
function buildGoPackageSymbolLookups(analyses, manifestsById) {
|
|
13884
14011
|
const lookups = /* @__PURE__ */ new Map();
|
|
@@ -14347,7 +14474,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
14347
14474
|
const benchmark = await readJsonFile(paths.benchmarkPath);
|
|
14348
14475
|
const communityRecords = [];
|
|
14349
14476
|
for (const community of graph.communities ?? []) {
|
|
14350
|
-
const absolutePath =
|
|
14477
|
+
const absolutePath = path23.join(paths.wikiDir, "graph", "communities", `${community.id.replace(/^community:/, "")}.md`);
|
|
14351
14478
|
communityRecords.push(
|
|
14352
14479
|
await buildManagedGraphPage(
|
|
14353
14480
|
absolutePath,
|
|
@@ -14376,7 +14503,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
14376
14503
|
graphHash: graphHash(graph),
|
|
14377
14504
|
contradictions
|
|
14378
14505
|
});
|
|
14379
|
-
const reportAbsolutePath =
|
|
14506
|
+
const reportAbsolutePath = path23.join(paths.wikiDir, "graph", "report.md");
|
|
14380
14507
|
const reportRecord = await buildManagedGraphPage(
|
|
14381
14508
|
reportAbsolutePath,
|
|
14382
14509
|
{
|
|
@@ -14397,7 +14524,7 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
14397
14524
|
};
|
|
14398
14525
|
}
|
|
14399
14526
|
async function writePage(wikiDir, relativePath, content, changedPages) {
|
|
14400
|
-
const absolutePath =
|
|
14527
|
+
const absolutePath = path23.resolve(wikiDir, relativePath);
|
|
14401
14528
|
const changed = await writeFileIfChanged(absolutePath, content);
|
|
14402
14529
|
if (changed) {
|
|
14403
14530
|
changedPages.push(relativePath);
|
|
@@ -14463,29 +14590,29 @@ async function requiredCompileArtifactsExist(paths) {
|
|
|
14463
14590
|
paths.graphPath,
|
|
14464
14591
|
paths.codeIndexPath,
|
|
14465
14592
|
paths.searchDbPath,
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14472
|
-
|
|
14473
|
-
|
|
14593
|
+
path23.join(paths.wikiDir, "index.md"),
|
|
14594
|
+
path23.join(paths.wikiDir, "sources", "index.md"),
|
|
14595
|
+
path23.join(paths.wikiDir, "code", "index.md"),
|
|
14596
|
+
path23.join(paths.wikiDir, "concepts", "index.md"),
|
|
14597
|
+
path23.join(paths.wikiDir, "entities", "index.md"),
|
|
14598
|
+
path23.join(paths.wikiDir, "outputs", "index.md"),
|
|
14599
|
+
path23.join(paths.wikiDir, "projects", "index.md"),
|
|
14600
|
+
path23.join(paths.wikiDir, "candidates", "index.md")
|
|
14474
14601
|
];
|
|
14475
14602
|
const checks = await Promise.all(requiredPaths.map((filePath) => fileExists(filePath)));
|
|
14476
14603
|
return checks.every(Boolean);
|
|
14477
14604
|
}
|
|
14478
14605
|
async function loadAvailableCachedAnalyses(paths, manifests) {
|
|
14479
14606
|
const analyses = await Promise.all(
|
|
14480
|
-
manifests.map(async (manifest) => readJsonFile(
|
|
14607
|
+
manifests.map(async (manifest) => readJsonFile(path23.join(paths.analysesDir, `${manifest.sourceId}.json`)))
|
|
14481
14608
|
);
|
|
14482
14609
|
return analyses.filter((analysis) => Boolean(analysis));
|
|
14483
14610
|
}
|
|
14484
14611
|
function approvalManifestPath(paths, approvalId) {
|
|
14485
|
-
return
|
|
14612
|
+
return path23.join(paths.approvalsDir, approvalId, "manifest.json");
|
|
14486
14613
|
}
|
|
14487
14614
|
function approvalGraphPath(paths, approvalId) {
|
|
14488
|
-
return
|
|
14615
|
+
return path23.join(paths.approvalsDir, approvalId, "state", "graph.json");
|
|
14489
14616
|
}
|
|
14490
14617
|
async function readApprovalManifest(paths, approvalId) {
|
|
14491
14618
|
const manifest = await readJsonFile(approvalManifestPath(paths, approvalId));
|
|
@@ -14495,7 +14622,7 @@ async function readApprovalManifest(paths, approvalId) {
|
|
|
14495
14622
|
return manifest;
|
|
14496
14623
|
}
|
|
14497
14624
|
async function writeApprovalManifest(paths, manifest) {
|
|
14498
|
-
await
|
|
14625
|
+
await fs19.writeFile(approvalManifestPath(paths, manifest.approvalId), `${JSON.stringify(manifest, null, 2)}
|
|
14499
14626
|
`, "utf8");
|
|
14500
14627
|
}
|
|
14501
14628
|
async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousGraph, graph, labelsByPath = /* @__PURE__ */ new Map()) {
|
|
@@ -14510,7 +14637,7 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
|
|
|
14510
14637
|
continue;
|
|
14511
14638
|
}
|
|
14512
14639
|
const previousPage = previousPagesById.get(nextPage.id);
|
|
14513
|
-
const currentExists = await fileExists(
|
|
14640
|
+
const currentExists = await fileExists(path23.join(paths.wikiDir, file.relativePath));
|
|
14514
14641
|
if (previousPage && previousPage.path !== nextPage.path) {
|
|
14515
14642
|
entries.push({
|
|
14516
14643
|
pageId: nextPage.id,
|
|
@@ -14545,7 +14672,7 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
|
|
|
14545
14672
|
const previousPage = previousPagesByPath.get(deletedPath);
|
|
14546
14673
|
entries.push({
|
|
14547
14674
|
pageId: previousPage?.id ?? `page:${slugify(deletedPath)}`,
|
|
14548
|
-
title: previousPage?.title ??
|
|
14675
|
+
title: previousPage?.title ?? path23.basename(deletedPath, ".md"),
|
|
14549
14676
|
kind: previousPage?.kind ?? "index",
|
|
14550
14677
|
changeType: "delete",
|
|
14551
14678
|
status: "pending",
|
|
@@ -14558,16 +14685,16 @@ async function buildApprovalEntries(paths, changedFiles, deletedPaths, previousG
|
|
|
14558
14685
|
}
|
|
14559
14686
|
async function stageApprovalBundle(paths, changedFiles, deletedPaths, previousGraph, graph) {
|
|
14560
14687
|
const approvalId = `compile-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
14561
|
-
const approvalDir =
|
|
14688
|
+
const approvalDir = path23.join(paths.approvalsDir, approvalId);
|
|
14562
14689
|
await ensureDir(approvalDir);
|
|
14563
|
-
await ensureDir(
|
|
14564
|
-
await ensureDir(
|
|
14690
|
+
await ensureDir(path23.join(approvalDir, "wiki"));
|
|
14691
|
+
await ensureDir(path23.join(approvalDir, "state"));
|
|
14565
14692
|
for (const file of changedFiles) {
|
|
14566
|
-
const targetPath =
|
|
14567
|
-
await ensureDir(
|
|
14568
|
-
await
|
|
14693
|
+
const targetPath = path23.join(approvalDir, "wiki", file.relativePath);
|
|
14694
|
+
await ensureDir(path23.dirname(targetPath));
|
|
14695
|
+
await fs19.writeFile(targetPath, file.content, "utf8");
|
|
14569
14696
|
}
|
|
14570
|
-
await
|
|
14697
|
+
await fs19.writeFile(path23.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
|
|
14571
14698
|
await writeApprovalManifest(paths, {
|
|
14572
14699
|
approvalId,
|
|
14573
14700
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -14633,7 +14760,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14633
14760
|
confidence: 1
|
|
14634
14761
|
});
|
|
14635
14762
|
const sourceRecord = await buildManagedGraphPage(
|
|
14636
|
-
|
|
14763
|
+
path23.join(paths.wikiDir, preview.path),
|
|
14637
14764
|
{
|
|
14638
14765
|
managedBy: "system",
|
|
14639
14766
|
confidence: 1,
|
|
@@ -14679,7 +14806,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14679
14806
|
);
|
|
14680
14807
|
records.push(
|
|
14681
14808
|
await buildManagedGraphPage(
|
|
14682
|
-
|
|
14809
|
+
path23.join(paths.wikiDir, modulePreview.path),
|
|
14683
14810
|
{
|
|
14684
14811
|
managedBy: "system",
|
|
14685
14812
|
confidence: 1,
|
|
@@ -14713,8 +14840,8 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14713
14840
|
const relativePath = promoted ? activeAggregatePath(itemKind, slug) : candidatePagePathFor(itemKind, slug);
|
|
14714
14841
|
const aggregateSourceClass2 = aggregateManifestSourceClass(input.manifests, sourceIds);
|
|
14715
14842
|
const fallbackPaths = [
|
|
14716
|
-
|
|
14717
|
-
|
|
14843
|
+
path23.join(paths.wikiDir, activeAggregatePath(itemKind, slug)),
|
|
14844
|
+
path23.join(paths.wikiDir, candidatePagePathFor(itemKind, slug))
|
|
14718
14845
|
];
|
|
14719
14846
|
const confidence = nodeConfidence(aggregate.sourceAnalyses.length);
|
|
14720
14847
|
const preview = emptyGraphPage({
|
|
@@ -14732,7 +14859,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14732
14859
|
status: promoted ? "active" : "candidate"
|
|
14733
14860
|
});
|
|
14734
14861
|
const pageRecord = await buildManagedGraphPage(
|
|
14735
|
-
|
|
14862
|
+
path23.join(paths.wikiDir, relativePath),
|
|
14736
14863
|
{
|
|
14737
14864
|
status: promoted ? "active" : "candidate",
|
|
14738
14865
|
managedBy: "system",
|
|
@@ -14861,7 +14988,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14861
14988
|
confidence: 1
|
|
14862
14989
|
}),
|
|
14863
14990
|
content: await buildManagedContent(
|
|
14864
|
-
|
|
14991
|
+
path23.join(paths.wikiDir, "projects", "index.md"),
|
|
14865
14992
|
{
|
|
14866
14993
|
managedBy: "system",
|
|
14867
14994
|
compiledFrom: indexCompiledFrom(projectIndexRefs)
|
|
@@ -14885,7 +15012,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14885
15012
|
records.push({
|
|
14886
15013
|
page: projectIndexRef,
|
|
14887
15014
|
content: await buildManagedContent(
|
|
14888
|
-
|
|
15015
|
+
path23.join(paths.wikiDir, projectIndexRef.path),
|
|
14889
15016
|
{
|
|
14890
15017
|
managedBy: "system",
|
|
14891
15018
|
compiledFrom: indexCompiledFrom(Object.values(sections).flat())
|
|
@@ -14913,7 +15040,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14913
15040
|
confidence: 1
|
|
14914
15041
|
}),
|
|
14915
15042
|
content: await buildManagedContent(
|
|
14916
|
-
|
|
15043
|
+
path23.join(paths.wikiDir, "index.md"),
|
|
14917
15044
|
{
|
|
14918
15045
|
managedBy: "system",
|
|
14919
15046
|
compiledFrom: indexCompiledFrom(allPages)
|
|
@@ -14949,7 +15076,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14949
15076
|
confidence: 1
|
|
14950
15077
|
}),
|
|
14951
15078
|
content: await buildManagedContent(
|
|
14952
|
-
|
|
15079
|
+
path23.join(paths.wikiDir, relativePath),
|
|
14953
15080
|
{
|
|
14954
15081
|
managedBy: "system",
|
|
14955
15082
|
compiledFrom: indexCompiledFrom(pages)
|
|
@@ -14960,12 +15087,12 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14960
15087
|
}
|
|
14961
15088
|
const nextPagePaths = new Set(records.map((record) => record.page.path));
|
|
14962
15089
|
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(
|
|
15090
|
+
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
15091
|
const obsoletePaths = uniqueStrings3([...obsoleteGraphPaths, ...existingProjectIndexPaths]);
|
|
14965
15092
|
const changedFiles = [];
|
|
14966
15093
|
for (const record of records) {
|
|
14967
|
-
const absolutePath =
|
|
14968
|
-
const current = await fileExists(absolutePath) ? await
|
|
15094
|
+
const absolutePath = path23.join(paths.wikiDir, record.page.path);
|
|
15095
|
+
const current = await fileExists(absolutePath) ? await fs19.readFile(absolutePath, "utf8") : null;
|
|
14969
15096
|
if (current !== record.content) {
|
|
14970
15097
|
changedPages.push(record.page.path);
|
|
14971
15098
|
changedFiles.push({ relativePath: record.page.path, content: record.content });
|
|
@@ -14990,10 +15117,10 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
14990
15117
|
await writePage(paths.wikiDir, record.page.path, record.content, writeChanges);
|
|
14991
15118
|
}
|
|
14992
15119
|
for (const relativePath of obsoletePaths) {
|
|
14993
|
-
await
|
|
15120
|
+
await fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true });
|
|
14994
15121
|
}
|
|
14995
15122
|
await writeJsonFile(paths.graphPath, graph);
|
|
14996
|
-
await writeJsonFile(
|
|
15123
|
+
await writeJsonFile(path23.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
|
|
14997
15124
|
await writeJsonFile(paths.codeIndexPath, input.codeIndex);
|
|
14998
15125
|
await writeJsonFile(paths.compileStatePath, {
|
|
14999
15126
|
generatedAt: graph.generatedAt,
|
|
@@ -15088,18 +15215,18 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15088
15215
|
})
|
|
15089
15216
|
);
|
|
15090
15217
|
await Promise.all([
|
|
15091
|
-
ensureDir(
|
|
15092
|
-
ensureDir(
|
|
15093
|
-
ensureDir(
|
|
15094
|
-
ensureDir(
|
|
15095
|
-
ensureDir(
|
|
15096
|
-
ensureDir(
|
|
15097
|
-
ensureDir(
|
|
15098
|
-
ensureDir(
|
|
15099
|
-
ensureDir(
|
|
15100
|
-
ensureDir(
|
|
15218
|
+
ensureDir(path23.join(paths.wikiDir, "sources")),
|
|
15219
|
+
ensureDir(path23.join(paths.wikiDir, "code")),
|
|
15220
|
+
ensureDir(path23.join(paths.wikiDir, "concepts")),
|
|
15221
|
+
ensureDir(path23.join(paths.wikiDir, "entities")),
|
|
15222
|
+
ensureDir(path23.join(paths.wikiDir, "outputs")),
|
|
15223
|
+
ensureDir(path23.join(paths.wikiDir, "dashboards")),
|
|
15224
|
+
ensureDir(path23.join(paths.wikiDir, "graph")),
|
|
15225
|
+
ensureDir(path23.join(paths.wikiDir, "graph", "communities")),
|
|
15226
|
+
ensureDir(path23.join(paths.wikiDir, "projects")),
|
|
15227
|
+
ensureDir(path23.join(paths.wikiDir, "candidates"))
|
|
15101
15228
|
]);
|
|
15102
|
-
const projectsIndexPath =
|
|
15229
|
+
const projectsIndexPath = path23.join(paths.wikiDir, "projects", "index.md");
|
|
15103
15230
|
await writeFileIfChanged(
|
|
15104
15231
|
projectsIndexPath,
|
|
15105
15232
|
await buildManagedContent(
|
|
@@ -15120,7 +15247,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15120
15247
|
outputs: pages.filter((page) => page.kind === "output" && page.projectIds.includes(project.id)),
|
|
15121
15248
|
candidates: pages.filter((page) => page.status === "candidate" && page.projectIds.includes(project.id))
|
|
15122
15249
|
};
|
|
15123
|
-
const absolutePath =
|
|
15250
|
+
const absolutePath = path23.join(paths.wikiDir, "projects", project.id, "index.md");
|
|
15124
15251
|
await writeFileIfChanged(
|
|
15125
15252
|
absolutePath,
|
|
15126
15253
|
await buildManagedContent(
|
|
@@ -15138,7 +15265,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15138
15265
|
)
|
|
15139
15266
|
);
|
|
15140
15267
|
}
|
|
15141
|
-
const rootIndexPath =
|
|
15268
|
+
const rootIndexPath = path23.join(paths.wikiDir, "index.md");
|
|
15142
15269
|
await writeFileIfChanged(
|
|
15143
15270
|
rootIndexPath,
|
|
15144
15271
|
await buildManagedContent(
|
|
@@ -15164,7 +15291,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15164
15291
|
["candidates/index.md", "candidates", pagesWithGraph.filter((page) => page.status === "candidate")],
|
|
15165
15292
|
["graph/index.md", "graph", pagesWithGraph.filter((page) => page.kind === "graph_report" || page.kind === "community_summary")]
|
|
15166
15293
|
]) {
|
|
15167
|
-
const absolutePath =
|
|
15294
|
+
const absolutePath = path23.join(paths.wikiDir, relativePath);
|
|
15168
15295
|
await writeFileIfChanged(
|
|
15169
15296
|
absolutePath,
|
|
15170
15297
|
await buildManagedContent(
|
|
@@ -15178,31 +15305,31 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
15178
15305
|
);
|
|
15179
15306
|
}
|
|
15180
15307
|
for (const record of graphOrientation.records) {
|
|
15181
|
-
await writeFileIfChanged(
|
|
15308
|
+
await writeFileIfChanged(path23.join(paths.wikiDir, record.page.path), record.content);
|
|
15182
15309
|
}
|
|
15183
15310
|
for (const record of dashboardRecords) {
|
|
15184
|
-
await writeFileIfChanged(
|
|
15311
|
+
await writeFileIfChanged(path23.join(paths.wikiDir, record.page.path), record.content);
|
|
15185
15312
|
}
|
|
15186
15313
|
if (graphOrientation.report) {
|
|
15187
|
-
await writeJsonFile(
|
|
15314
|
+
await writeJsonFile(path23.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
|
|
15188
15315
|
}
|
|
15189
|
-
const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(
|
|
15316
|
+
const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path23.relative(paths.wikiDir, absolutePath)));
|
|
15190
15317
|
const allowedProjectIndexPaths = /* @__PURE__ */ new Set([
|
|
15191
15318
|
"projects/index.md",
|
|
15192
15319
|
...configuredProjects.map((project) => `projects/${project.id}/index.md`)
|
|
15193
15320
|
]);
|
|
15194
15321
|
await Promise.all(
|
|
15195
|
-
existingProjectIndexPaths.filter((relativePath) => !allowedProjectIndexPaths.has(relativePath)).map((relativePath) =>
|
|
15322
|
+
existingProjectIndexPaths.filter((relativePath) => !allowedProjectIndexPaths.has(relativePath)).map((relativePath) => fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true }))
|
|
15196
15323
|
);
|
|
15197
|
-
const existingGraphPages = (await listFilesRecursive(
|
|
15324
|
+
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
15325
|
const allowedGraphPages = /* @__PURE__ */ new Set(["graph/index.md", ...graphOrientation.records.map((record) => record.page.path)]);
|
|
15199
15326
|
await Promise.all(
|
|
15200
|
-
existingGraphPages.filter((relativePath) => !allowedGraphPages.has(relativePath)).map((relativePath) =>
|
|
15327
|
+
existingGraphPages.filter((relativePath) => !allowedGraphPages.has(relativePath)).map((relativePath) => fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true }))
|
|
15201
15328
|
);
|
|
15202
|
-
const existingDashboardPages = (await listFilesRecursive(
|
|
15329
|
+
const existingDashboardPages = (await listFilesRecursive(path23.join(paths.wikiDir, "dashboards")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path23.relative(paths.wikiDir, absolutePath)));
|
|
15203
15330
|
const allowedDashboardPages = /* @__PURE__ */ new Set(["dashboards/index.md", ...dashboardRecords.map((record) => record.page.path)]);
|
|
15204
15331
|
await Promise.all(
|
|
15205
|
-
existingDashboardPages.filter((relativePath) => !allowedDashboardPages.has(relativePath)).map((relativePath) =>
|
|
15332
|
+
existingDashboardPages.filter((relativePath) => !allowedDashboardPages.has(relativePath)).map((relativePath) => fs19.rm(path23.join(paths.wikiDir, relativePath), { force: true }))
|
|
15206
15333
|
);
|
|
15207
15334
|
await rebuildSearchIndex(paths.searchDbPath, pagesWithGraph, paths.wikiDir);
|
|
15208
15335
|
}
|
|
@@ -15222,7 +15349,7 @@ async function prepareOutputPageSave(rootDir, input) {
|
|
|
15222
15349
|
confidence: 0.74
|
|
15223
15350
|
}
|
|
15224
15351
|
});
|
|
15225
|
-
const absolutePath =
|
|
15352
|
+
const absolutePath = path23.join(paths.wikiDir, output.page.path);
|
|
15226
15353
|
return {
|
|
15227
15354
|
page: output.page,
|
|
15228
15355
|
savedPath: absolutePath,
|
|
@@ -15234,15 +15361,15 @@ async function prepareOutputPageSave(rootDir, input) {
|
|
|
15234
15361
|
async function persistOutputPage(rootDir, input) {
|
|
15235
15362
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15236
15363
|
const prepared = await prepareOutputPageSave(rootDir, input);
|
|
15237
|
-
await ensureDir(
|
|
15238
|
-
await
|
|
15364
|
+
await ensureDir(path23.dirname(prepared.savedPath));
|
|
15365
|
+
await fs19.writeFile(prepared.savedPath, prepared.content, "utf8");
|
|
15239
15366
|
for (const assetFile of prepared.assetFiles) {
|
|
15240
|
-
const assetPath =
|
|
15241
|
-
await ensureDir(
|
|
15367
|
+
const assetPath = path23.join(paths.wikiDir, assetFile.relativePath);
|
|
15368
|
+
await ensureDir(path23.dirname(assetPath));
|
|
15242
15369
|
if (typeof assetFile.content === "string") {
|
|
15243
|
-
await
|
|
15370
|
+
await fs19.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
|
|
15244
15371
|
} else {
|
|
15245
|
-
await
|
|
15372
|
+
await fs19.writeFile(assetPath, assetFile.content);
|
|
15246
15373
|
}
|
|
15247
15374
|
}
|
|
15248
15375
|
return { page: prepared.page, savedPath: prepared.savedPath, outputAssets: prepared.outputAssets };
|
|
@@ -15263,7 +15390,7 @@ async function prepareExploreHubSave(rootDir, input) {
|
|
|
15263
15390
|
confidence: 0.76
|
|
15264
15391
|
}
|
|
15265
15392
|
});
|
|
15266
|
-
const absolutePath =
|
|
15393
|
+
const absolutePath = path23.join(paths.wikiDir, hub.page.path);
|
|
15267
15394
|
return {
|
|
15268
15395
|
page: hub.page,
|
|
15269
15396
|
savedPath: absolutePath,
|
|
@@ -15275,15 +15402,15 @@ async function prepareExploreHubSave(rootDir, input) {
|
|
|
15275
15402
|
async function persistExploreHub(rootDir, input) {
|
|
15276
15403
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15277
15404
|
const prepared = await prepareExploreHubSave(rootDir, input);
|
|
15278
|
-
await ensureDir(
|
|
15279
|
-
await
|
|
15405
|
+
await ensureDir(path23.dirname(prepared.savedPath));
|
|
15406
|
+
await fs19.writeFile(prepared.savedPath, prepared.content, "utf8");
|
|
15280
15407
|
for (const assetFile of prepared.assetFiles) {
|
|
15281
|
-
const assetPath =
|
|
15282
|
-
await ensureDir(
|
|
15408
|
+
const assetPath = path23.join(paths.wikiDir, assetFile.relativePath);
|
|
15409
|
+
await ensureDir(path23.dirname(assetPath));
|
|
15283
15410
|
if (typeof assetFile.content === "string") {
|
|
15284
|
-
await
|
|
15411
|
+
await fs19.writeFile(assetPath, assetFile.content, assetFile.encoding ?? "utf8");
|
|
15285
15412
|
} else {
|
|
15286
|
-
await
|
|
15413
|
+
await fs19.writeFile(assetPath, assetFile.content);
|
|
15287
15414
|
}
|
|
15288
15415
|
}
|
|
15289
15416
|
return { page: prepared.page, savedPath: prepared.savedPath, outputAssets: prepared.outputAssets };
|
|
@@ -15301,17 +15428,17 @@ async function stageOutputApprovalBundle(rootDir, stagedPages, options = {}) {
|
|
|
15301
15428
|
]);
|
|
15302
15429
|
const labelsByPath = new Map(stagedPages.filter((item) => item.label).map((item) => [item.page.path, item.label]));
|
|
15303
15430
|
const approvalId = `schedule-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
15304
|
-
const approvalDir =
|
|
15431
|
+
const approvalDir = path23.join(paths.approvalsDir, approvalId);
|
|
15305
15432
|
await ensureDir(approvalDir);
|
|
15306
|
-
await ensureDir(
|
|
15307
|
-
await ensureDir(
|
|
15433
|
+
await ensureDir(path23.join(approvalDir, "wiki"));
|
|
15434
|
+
await ensureDir(path23.join(approvalDir, "state"));
|
|
15308
15435
|
for (const file of changedFiles) {
|
|
15309
|
-
const targetPath =
|
|
15310
|
-
await ensureDir(
|
|
15436
|
+
const targetPath = path23.join(approvalDir, "wiki", file.relativePath);
|
|
15437
|
+
await ensureDir(path23.dirname(targetPath));
|
|
15311
15438
|
if ("binary" in file && file.binary) {
|
|
15312
|
-
await
|
|
15439
|
+
await fs19.writeFile(targetPath, Buffer.from(file.content, "base64"));
|
|
15313
15440
|
} else {
|
|
15314
|
-
await
|
|
15441
|
+
await fs19.writeFile(targetPath, file.content, "utf8");
|
|
15315
15442
|
}
|
|
15316
15443
|
}
|
|
15317
15444
|
const nextPages = sortGraphPages([
|
|
@@ -15326,12 +15453,13 @@ async function stageOutputApprovalBundle(rootDir, stagedPages, options = {}) {
|
|
|
15326
15453
|
sources: previousGraph?.sources ?? [],
|
|
15327
15454
|
pages: nextPages
|
|
15328
15455
|
};
|
|
15329
|
-
await
|
|
15456
|
+
await fs19.writeFile(path23.join(approvalDir, "state", "graph.json"), JSON.stringify(graph, null, 2), "utf8");
|
|
15330
15457
|
await writeApprovalManifest(paths, {
|
|
15331
15458
|
approvalId,
|
|
15332
15459
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15333
15460
|
bundleType: options.bundleType ?? "generated_output",
|
|
15334
15461
|
title: options.title,
|
|
15462
|
+
sourceSessionId: options.sourceSessionId,
|
|
15335
15463
|
entries: await buildApprovalEntries(
|
|
15336
15464
|
paths,
|
|
15337
15465
|
stagedPages.map((item) => ({ relativePath: item.page.path, content: item.content })),
|
|
@@ -15361,9 +15489,9 @@ async function executeQuery(rootDir, question, format) {
|
|
|
15361
15489
|
const searchResults = searchPages(paths.searchDbPath, question, 5);
|
|
15362
15490
|
const excerpts = await Promise.all(
|
|
15363
15491
|
searchResults.map(async (result) => {
|
|
15364
|
-
const absolutePath =
|
|
15492
|
+
const absolutePath = path23.join(paths.wikiDir, result.path);
|
|
15365
15493
|
try {
|
|
15366
|
-
const content = await
|
|
15494
|
+
const content = await fs19.readFile(absolutePath, "utf8");
|
|
15367
15495
|
const parsed = matter9(content);
|
|
15368
15496
|
return `# ${result.title}
|
|
15369
15497
|
${truncate(normalizeWhitespace(parsed.content), 1200)}`;
|
|
@@ -15598,7 +15726,7 @@ function computeChangeSummary(current, staged, changeType) {
|
|
|
15598
15726
|
async function listApprovals(rootDir) {
|
|
15599
15727
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15600
15728
|
const manifests = await Promise.all(
|
|
15601
|
-
(await
|
|
15729
|
+
(await fs19.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => {
|
|
15602
15730
|
try {
|
|
15603
15731
|
return await readApprovalManifest(paths, entry.name);
|
|
15604
15732
|
} catch {
|
|
@@ -15614,8 +15742,8 @@ async function readApproval(rootDir, approvalId, options) {
|
|
|
15614
15742
|
const details = await Promise.all(
|
|
15615
15743
|
manifest.entries.map(async (entry) => {
|
|
15616
15744
|
const currentPath = entry.previousPath ?? entry.nextPath;
|
|
15617
|
-
const currentContent = currentPath ? await
|
|
15618
|
-
const stagedContent = entry.nextPath ? await
|
|
15745
|
+
const currentContent = currentPath ? await fs19.readFile(path23.join(paths.wikiDir, currentPath), "utf8").catch(() => void 0) : void 0;
|
|
15746
|
+
const stagedContent = entry.nextPath ? await fs19.readFile(path23.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath), "utf8").catch(() => void 0) : void 0;
|
|
15619
15747
|
const detail = {
|
|
15620
15748
|
...entry,
|
|
15621
15749
|
currentContent,
|
|
@@ -15648,26 +15776,26 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
|
|
|
15648
15776
|
if (!entry.nextPath) {
|
|
15649
15777
|
throw new Error(`Approval entry ${entry.pageId} is missing a staged path.`);
|
|
15650
15778
|
}
|
|
15651
|
-
const stagedAbsolutePath =
|
|
15652
|
-
const stagedContent = await
|
|
15653
|
-
const targetAbsolutePath =
|
|
15654
|
-
await ensureDir(
|
|
15655
|
-
await
|
|
15779
|
+
const stagedAbsolutePath = path23.join(paths.approvalsDir, approvalId, "wiki", entry.nextPath);
|
|
15780
|
+
const stagedContent = await fs19.readFile(stagedAbsolutePath, "utf8");
|
|
15781
|
+
const targetAbsolutePath = path23.join(paths.wikiDir, entry.nextPath);
|
|
15782
|
+
await ensureDir(path23.dirname(targetAbsolutePath));
|
|
15783
|
+
await fs19.writeFile(targetAbsolutePath, stagedContent, "utf8");
|
|
15656
15784
|
if (entry.changeType === "promote" && entry.previousPath) {
|
|
15657
|
-
await
|
|
15785
|
+
await fs19.rm(path23.join(paths.wikiDir, entry.previousPath), { force: true });
|
|
15658
15786
|
}
|
|
15659
15787
|
const nextPage = bundleGraph?.pages.find((page) => page.id === entry.pageId && page.path === entry.nextPath) ?? parseStoredPage(entry.nextPath, stagedContent);
|
|
15660
15788
|
if (nextPage.kind === "output" && nextPage.outputAssets?.length) {
|
|
15661
|
-
const outputAssetDir =
|
|
15662
|
-
await
|
|
15789
|
+
const outputAssetDir = path23.join(paths.wikiDir, "outputs", "assets", path23.basename(nextPage.path, ".md"));
|
|
15790
|
+
await fs19.rm(outputAssetDir, { recursive: true, force: true });
|
|
15663
15791
|
for (const asset of nextPage.outputAssets) {
|
|
15664
|
-
const stagedAssetPath =
|
|
15792
|
+
const stagedAssetPath = path23.join(paths.approvalsDir, approvalId, "wiki", asset.path);
|
|
15665
15793
|
if (!await fileExists(stagedAssetPath)) {
|
|
15666
15794
|
continue;
|
|
15667
15795
|
}
|
|
15668
|
-
const targetAssetPath =
|
|
15669
|
-
await ensureDir(
|
|
15670
|
-
await
|
|
15796
|
+
const targetAssetPath = path23.join(paths.wikiDir, asset.path);
|
|
15797
|
+
await ensureDir(path23.dirname(targetAssetPath));
|
|
15798
|
+
await fs19.copyFile(stagedAssetPath, targetAssetPath);
|
|
15671
15799
|
}
|
|
15672
15800
|
}
|
|
15673
15801
|
nextPages = nextPages.filter(
|
|
@@ -15678,10 +15806,10 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
|
|
|
15678
15806
|
} else {
|
|
15679
15807
|
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
15808
|
if (entry.previousPath) {
|
|
15681
|
-
await
|
|
15809
|
+
await fs19.rm(path23.join(paths.wikiDir, entry.previousPath), { force: true });
|
|
15682
15810
|
}
|
|
15683
15811
|
if (deletedPage?.kind === "output") {
|
|
15684
|
-
await
|
|
15812
|
+
await fs19.rm(path23.join(paths.wikiDir, "outputs", "assets", path23.basename(deletedPage.path, ".md")), {
|
|
15685
15813
|
recursive: true,
|
|
15686
15814
|
force: true
|
|
15687
15815
|
});
|
|
@@ -15704,6 +15832,9 @@ async function acceptApproval(rootDir, approvalId, targets = []) {
|
|
|
15704
15832
|
await writeJsonFile(paths.compileStatePath, compileState);
|
|
15705
15833
|
await refreshIndexesAndSearch(rootDir, nextGraph.pages);
|
|
15706
15834
|
await writeApprovalManifest(paths, manifest);
|
|
15835
|
+
if (manifest.sourceSessionId) {
|
|
15836
|
+
await updateGuidedSourceSessionStatus(rootDir, manifest.sourceSessionId, "accepted");
|
|
15837
|
+
}
|
|
15707
15838
|
await recordSession(rootDir, {
|
|
15708
15839
|
operation: "review",
|
|
15709
15840
|
title: `Accepted review entries from ${approvalId}`,
|
|
@@ -15730,6 +15861,9 @@ async function rejectApproval(rootDir, approvalId, targets = []) {
|
|
|
15730
15861
|
entry.status = "rejected";
|
|
15731
15862
|
}
|
|
15732
15863
|
await writeApprovalManifest(paths, manifest);
|
|
15864
|
+
if (manifest.sourceSessionId) {
|
|
15865
|
+
await updateGuidedSourceSessionStatus(rootDir, manifest.sourceSessionId, "rejected");
|
|
15866
|
+
}
|
|
15733
15867
|
await recordSession(rootDir, {
|
|
15734
15868
|
operation: "review",
|
|
15735
15869
|
title: `Rejected review entries from ${approvalId}`,
|
|
@@ -15772,7 +15906,7 @@ async function promoteCandidate(rootDir, target) {
|
|
|
15772
15906
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15773
15907
|
const graph = await readJsonFile(paths.graphPath);
|
|
15774
15908
|
const candidate = resolveCandidateTarget(graph?.pages ?? [], target);
|
|
15775
|
-
const raw = await
|
|
15909
|
+
const raw = await fs19.readFile(path23.join(paths.wikiDir, candidate.path), "utf8");
|
|
15776
15910
|
const parsed = matter9(raw);
|
|
15777
15911
|
const nextUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15778
15912
|
const nextContent = matter9.stringify(parsed.content, {
|
|
@@ -15784,10 +15918,10 @@ async function promoteCandidate(rootDir, target) {
|
|
|
15784
15918
|
)
|
|
15785
15919
|
});
|
|
15786
15920
|
const nextPath = candidateActivePath(candidate);
|
|
15787
|
-
const nextAbsolutePath =
|
|
15788
|
-
await ensureDir(
|
|
15789
|
-
await
|
|
15790
|
-
await
|
|
15921
|
+
const nextAbsolutePath = path23.join(paths.wikiDir, nextPath);
|
|
15922
|
+
await ensureDir(path23.dirname(nextAbsolutePath));
|
|
15923
|
+
await fs19.writeFile(nextAbsolutePath, nextContent, "utf8");
|
|
15924
|
+
await fs19.rm(path23.join(paths.wikiDir, candidate.path), { force: true });
|
|
15791
15925
|
const nextPage = parseStoredPage(nextPath, nextContent, { createdAt: candidate.createdAt, updatedAt: nextUpdatedAt });
|
|
15792
15926
|
const nextPages = sortGraphPages(
|
|
15793
15927
|
(graph?.pages ?? []).filter((page) => page.id !== candidate.id && page.path !== candidate.path).concat(nextPage)
|
|
@@ -15832,7 +15966,7 @@ async function archiveCandidate(rootDir, target) {
|
|
|
15832
15966
|
const { paths } = await loadVaultConfig(rootDir);
|
|
15833
15967
|
const graph = await readJsonFile(paths.graphPath);
|
|
15834
15968
|
const candidate = resolveCandidateTarget(graph?.pages ?? [], target);
|
|
15835
|
-
await
|
|
15969
|
+
await fs19.rm(path23.join(paths.wikiDir, candidate.path), { force: true });
|
|
15836
15970
|
const nextPages = sortGraphPages((graph?.pages ?? []).filter((page) => page.id !== candidate.id && page.path !== candidate.path));
|
|
15837
15971
|
const nextGraph = {
|
|
15838
15972
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15871,18 +16005,18 @@ async function archiveCandidate(rootDir, target) {
|
|
|
15871
16005
|
}
|
|
15872
16006
|
async function ensureObsidianWorkspace(rootDir) {
|
|
15873
16007
|
const { config } = await loadVaultConfig(rootDir);
|
|
15874
|
-
const obsidianDir =
|
|
16008
|
+
const obsidianDir = path23.join(rootDir, ".obsidian");
|
|
15875
16009
|
const projectIds = projectEntries(config).map((project) => project.id);
|
|
15876
16010
|
await ensureDir(obsidianDir);
|
|
15877
16011
|
await Promise.all([
|
|
15878
|
-
writeJsonFile(
|
|
16012
|
+
writeJsonFile(path23.join(obsidianDir, "app.json"), {
|
|
15879
16013
|
alwaysUpdateLinks: true,
|
|
15880
16014
|
newFileLocation: "folder",
|
|
15881
16015
|
newFileFolderPath: "wiki/insights",
|
|
15882
16016
|
useMarkdownLinks: false,
|
|
15883
16017
|
attachmentFolderPath: "raw/assets"
|
|
15884
16018
|
}),
|
|
15885
|
-
writeJsonFile(
|
|
16019
|
+
writeJsonFile(path23.join(obsidianDir, "core-plugins.json"), [
|
|
15886
16020
|
"file-explorer",
|
|
15887
16021
|
"global-search",
|
|
15888
16022
|
"switcher",
|
|
@@ -15892,7 +16026,7 @@ async function ensureObsidianWorkspace(rootDir) {
|
|
|
15892
16026
|
"tag-pane",
|
|
15893
16027
|
"page-preview"
|
|
15894
16028
|
]),
|
|
15895
|
-
writeJsonFile(
|
|
16029
|
+
writeJsonFile(path23.join(obsidianDir, "graph.json"), {
|
|
15896
16030
|
"collapse-filter": false,
|
|
15897
16031
|
search: "",
|
|
15898
16032
|
showTags: true,
|
|
@@ -15904,7 +16038,7 @@ async function ensureObsidianWorkspace(rootDir) {
|
|
|
15904
16038
|
})),
|
|
15905
16039
|
localJumps: false
|
|
15906
16040
|
}),
|
|
15907
|
-
writeJsonFile(
|
|
16041
|
+
writeJsonFile(path23.join(obsidianDir, "workspace.json"), {
|
|
15908
16042
|
active: "root",
|
|
15909
16043
|
lastOpenFiles: ["wiki/index.md", "wiki/projects/index.md", "wiki/candidates/index.md", "wiki/insights/index.md"],
|
|
15910
16044
|
left: {
|
|
@@ -15920,7 +16054,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15920
16054
|
const profile = options.profile ?? "default";
|
|
15921
16055
|
const { paths } = await initWorkspace(rootDir, { profile });
|
|
15922
16056
|
await installConfiguredAgents(rootDir);
|
|
15923
|
-
const insightsIndexPath =
|
|
16057
|
+
const insightsIndexPath = path23.join(paths.wikiDir, "insights", "index.md");
|
|
15924
16058
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15925
16059
|
await writeFileIfChanged(
|
|
15926
16060
|
insightsIndexPath,
|
|
@@ -15931,7 +16065,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15931
16065
|
"Human-authored research notes live here.",
|
|
15932
16066
|
"",
|
|
15933
16067
|
"- Use this folder for thesis notes, reading reflections, synthesis drafts, and decisions you want to keep explicitly human-authored.",
|
|
15934
|
-
"- Guided
|
|
16068
|
+
"- Guided sessions can stage `wiki/insights/` updates through the approval queue, but SwarmVault never applies them without review.",
|
|
15935
16069
|
"- Treat these pages as the human judgment layer for your vault.",
|
|
15936
16070
|
""
|
|
15937
16071
|
] : [
|
|
@@ -15940,7 +16074,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15940
16074
|
"Human-authored notes live here.",
|
|
15941
16075
|
"",
|
|
15942
16076
|
"- SwarmVault can read these pages during compile and query.",
|
|
15943
|
-
"- SwarmVault
|
|
16077
|
+
"- SwarmVault can stage insight-page updates through guided sessions, but it never applies them without review.",
|
|
15944
16078
|
""
|
|
15945
16079
|
]).join("\n"),
|
|
15946
16080
|
{
|
|
@@ -15966,7 +16100,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15966
16100
|
)
|
|
15967
16101
|
);
|
|
15968
16102
|
await writeFileIfChanged(
|
|
15969
|
-
|
|
16103
|
+
path23.join(paths.wikiDir, "projects", "index.md"),
|
|
15970
16104
|
matter9.stringify(["# Projects", "", "- Run `swarmvault compile` to build project rollups.", ""].join("\n"), {
|
|
15971
16105
|
page_id: "projects:index",
|
|
15972
16106
|
kind: "index",
|
|
@@ -15989,7 +16123,7 @@ async function initVault(rootDir, options = {}) {
|
|
|
15989
16123
|
})
|
|
15990
16124
|
);
|
|
15991
16125
|
await writeFileIfChanged(
|
|
15992
|
-
|
|
16126
|
+
path23.join(paths.wikiDir, "candidates", "index.md"),
|
|
15993
16127
|
matter9.stringify(["# Candidates", "", "- Run `swarmvault compile` to stage candidate pages.", ""].join("\n"), {
|
|
15994
16128
|
page_id: "candidates:index",
|
|
15995
16129
|
kind: "index",
|
|
@@ -16016,13 +16150,14 @@ async function initVault(rootDir, options = {}) {
|
|
|
16016
16150
|
}
|
|
16017
16151
|
if (profile === "personal-research") {
|
|
16018
16152
|
await writeFileIfChanged(
|
|
16019
|
-
|
|
16153
|
+
path23.join(paths.wikiDir, "insights", "research-playbook.md"),
|
|
16020
16154
|
matter9.stringify(
|
|
16021
16155
|
[
|
|
16022
16156
|
"# Personal Research Playbook",
|
|
16023
16157
|
"",
|
|
16024
16158
|
"- Add one source at a time with `swarmvault ingest <input> --guide` or `swarmvault source add <input> --guide`.",
|
|
16025
|
-
"-
|
|
16159
|
+
"- Resume a guided session with `swarmvault source session <source-id-or-session-id>` whenever you want to answer the session prompts directly.",
|
|
16160
|
+
"- Review `wiki/outputs/source-briefs/`, `wiki/outputs/source-reviews/`, `wiki/outputs/source-guides/`, and `wiki/outputs/source-sessions/` before accepting staged updates.",
|
|
16026
16161
|
"- Keep unresolved questions visible in `wiki/dashboards/open-questions.md`.",
|
|
16027
16162
|
"- Use `swarmvault review list` and `swarmvault review show --diff` to decide what becomes canonical.",
|
|
16028
16163
|
""
|
|
@@ -16165,7 +16300,7 @@ async function compileVault(rootDir, options = {}) {
|
|
|
16165
16300
|
),
|
|
16166
16301
|
Promise.all(
|
|
16167
16302
|
clean.map(async (manifest) => {
|
|
16168
|
-
const cached = await readJsonFile(
|
|
16303
|
+
const cached = await readJsonFile(path23.join(paths.analysesDir, `${manifest.sourceId}.json`));
|
|
16169
16304
|
if (cached) {
|
|
16170
16305
|
analysisProgress.tick(manifest.title);
|
|
16171
16306
|
return cached;
|
|
@@ -16193,22 +16328,22 @@ async function compileVault(rootDir, options = {}) {
|
|
|
16193
16328
|
}
|
|
16194
16329
|
const enriched = enrichResolvedCodeImports(manifest, analysis, codeIndex);
|
|
16195
16330
|
if (analysisSignature(enriched) !== analysisSignature(analysis)) {
|
|
16196
|
-
await writeJsonFile(
|
|
16331
|
+
await writeJsonFile(path23.join(paths.analysesDir, `${analysis.sourceId}.json`), enriched);
|
|
16197
16332
|
}
|
|
16198
16333
|
return enriched;
|
|
16199
16334
|
})
|
|
16200
16335
|
);
|
|
16201
16336
|
await Promise.all([
|
|
16202
|
-
ensureDir(
|
|
16203
|
-
ensureDir(
|
|
16204
|
-
ensureDir(
|
|
16205
|
-
ensureDir(
|
|
16206
|
-
ensureDir(
|
|
16207
|
-
ensureDir(
|
|
16208
|
-
ensureDir(
|
|
16209
|
-
ensureDir(
|
|
16210
|
-
ensureDir(
|
|
16211
|
-
ensureDir(
|
|
16337
|
+
ensureDir(path23.join(paths.wikiDir, "sources")),
|
|
16338
|
+
ensureDir(path23.join(paths.wikiDir, "code")),
|
|
16339
|
+
ensureDir(path23.join(paths.wikiDir, "concepts")),
|
|
16340
|
+
ensureDir(path23.join(paths.wikiDir, "entities")),
|
|
16341
|
+
ensureDir(path23.join(paths.wikiDir, "outputs")),
|
|
16342
|
+
ensureDir(path23.join(paths.wikiDir, "projects")),
|
|
16343
|
+
ensureDir(path23.join(paths.wikiDir, "insights")),
|
|
16344
|
+
ensureDir(path23.join(paths.wikiDir, "candidates")),
|
|
16345
|
+
ensureDir(path23.join(paths.wikiDir, "candidates", "concepts")),
|
|
16346
|
+
ensureDir(path23.join(paths.wikiDir, "candidates", "entities"))
|
|
16212
16347
|
]);
|
|
16213
16348
|
const sync = await syncVaultArtifacts(rootDir, {
|
|
16214
16349
|
schemas,
|
|
@@ -16355,7 +16490,7 @@ async function queryVault(rootDir, options) {
|
|
|
16355
16490
|
assetFiles: staged.assetFiles
|
|
16356
16491
|
}
|
|
16357
16492
|
]);
|
|
16358
|
-
stagedPath =
|
|
16493
|
+
stagedPath = path23.join(approval.approvalDir, "wiki", staged.page.path);
|
|
16359
16494
|
savedPageId = staged.page.id;
|
|
16360
16495
|
approvalId = approval.approvalId;
|
|
16361
16496
|
approvalDir = approval.approvalDir;
|
|
@@ -16611,9 +16746,9 @@ ${orchestrationNotes.join("\n")}
|
|
|
16611
16746
|
approvalId = approval.approvalId;
|
|
16612
16747
|
approvalDir = approval.approvalDir;
|
|
16613
16748
|
stepResults.forEach((result, index) => {
|
|
16614
|
-
result.stagedPath =
|
|
16749
|
+
result.stagedPath = path23.join(approval.approvalDir, "wiki", stagedStepPages[index]?.page.path ?? "");
|
|
16615
16750
|
});
|
|
16616
|
-
stagedHubPath =
|
|
16751
|
+
stagedHubPath = path23.join(approval.approvalDir, "wiki", hubPage.path);
|
|
16617
16752
|
} else {
|
|
16618
16753
|
await refreshVaultAfterOutputSave(rootDir);
|
|
16619
16754
|
}
|
|
@@ -16700,11 +16835,11 @@ async function benchmarkVault(rootDir, options = {}) {
|
|
|
16700
16835
|
}
|
|
16701
16836
|
}
|
|
16702
16837
|
for (const page of graph.pages) {
|
|
16703
|
-
const absolutePath =
|
|
16838
|
+
const absolutePath = path23.join(paths.wikiDir, page.path);
|
|
16704
16839
|
if (!await fileExists(absolutePath)) {
|
|
16705
16840
|
continue;
|
|
16706
16841
|
}
|
|
16707
|
-
const parsed = matter9(await
|
|
16842
|
+
const parsed = matter9(await fs19.readFile(absolutePath, "utf8"));
|
|
16708
16843
|
pageContentsById.set(page.id, parsed.content);
|
|
16709
16844
|
}
|
|
16710
16845
|
const configuredQuestions = (config.benchmark?.questions ?? []).map((question) => normalizeWhitespace(question)).filter(Boolean);
|
|
@@ -16759,7 +16894,7 @@ async function listGraphHyperedges(rootDir, target, limit = 25) {
|
|
|
16759
16894
|
}
|
|
16760
16895
|
async function readGraphReport(rootDir) {
|
|
16761
16896
|
const { paths } = await loadVaultConfig(rootDir);
|
|
16762
|
-
return readJsonFile(
|
|
16897
|
+
return readJsonFile(path23.join(paths.wikiDir, "graph", "report.json"));
|
|
16763
16898
|
}
|
|
16764
16899
|
async function listGodNodes(rootDir, limit = 10) {
|
|
16765
16900
|
const graph = await ensureCompiledGraph(rootDir);
|
|
@@ -16772,15 +16907,15 @@ async function listPages(rootDir) {
|
|
|
16772
16907
|
}
|
|
16773
16908
|
async function readPage(rootDir, relativePath) {
|
|
16774
16909
|
const { paths } = await loadVaultConfig(rootDir);
|
|
16775
|
-
const absolutePath =
|
|
16910
|
+
const absolutePath = path23.resolve(paths.wikiDir, relativePath);
|
|
16776
16911
|
if (!absolutePath.startsWith(paths.wikiDir) || !await fileExists(absolutePath)) {
|
|
16777
16912
|
return null;
|
|
16778
16913
|
}
|
|
16779
|
-
const raw = await
|
|
16914
|
+
const raw = await fs19.readFile(absolutePath, "utf8");
|
|
16780
16915
|
const parsed = matter9(raw);
|
|
16781
16916
|
return {
|
|
16782
16917
|
path: relativePath,
|
|
16783
|
-
title: typeof parsed.data.title === "string" ? parsed.data.title :
|
|
16918
|
+
title: typeof parsed.data.title === "string" ? parsed.data.title : path23.basename(relativePath, path23.extname(relativePath)),
|
|
16784
16919
|
frontmatter: parsed.data,
|
|
16785
16920
|
content: parsed.content
|
|
16786
16921
|
};
|
|
@@ -16816,7 +16951,7 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
|
|
|
16816
16951
|
severity: "warning",
|
|
16817
16952
|
code: "stale_page",
|
|
16818
16953
|
message: `Page ${page.title} is stale because the vault schema changed.`,
|
|
16819
|
-
pagePath:
|
|
16954
|
+
pagePath: path23.join(paths.wikiDir, page.path),
|
|
16820
16955
|
relatedPageIds: [page.id]
|
|
16821
16956
|
});
|
|
16822
16957
|
}
|
|
@@ -16829,7 +16964,7 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
|
|
|
16829
16964
|
severity: "warning",
|
|
16830
16965
|
code: "stale_page",
|
|
16831
16966
|
message: `Page ${page.title} is stale because source ${sourceId} changed.`,
|
|
16832
|
-
pagePath:
|
|
16967
|
+
pagePath: path23.join(paths.wikiDir, page.path),
|
|
16833
16968
|
relatedSourceIds: [sourceId],
|
|
16834
16969
|
relatedPageIds: [page.id]
|
|
16835
16970
|
});
|
|
@@ -16840,13 +16975,13 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
|
|
|
16840
16975
|
severity: "info",
|
|
16841
16976
|
code: "orphan_page",
|
|
16842
16977
|
message: `Page ${page.title} has no backlinks.`,
|
|
16843
|
-
pagePath:
|
|
16978
|
+
pagePath: path23.join(paths.wikiDir, page.path),
|
|
16844
16979
|
relatedPageIds: [page.id]
|
|
16845
16980
|
});
|
|
16846
16981
|
}
|
|
16847
|
-
const absolutePath =
|
|
16982
|
+
const absolutePath = path23.join(paths.wikiDir, page.path);
|
|
16848
16983
|
if (await fileExists(absolutePath)) {
|
|
16849
|
-
const content = await
|
|
16984
|
+
const content = await fs19.readFile(absolutePath, "utf8");
|
|
16850
16985
|
if (content.includes("## Claims")) {
|
|
16851
16986
|
const uncited = content.split("\n").filter((line) => line.startsWith("- ") && !line.includes("[source:"));
|
|
16852
16987
|
if (uncited.length) {
|
|
@@ -16963,7 +17098,7 @@ async function bootstrapDemo(rootDir, input) {
|
|
|
16963
17098
|
}
|
|
16964
17099
|
|
|
16965
17100
|
// src/mcp.ts
|
|
16966
|
-
var SERVER_VERSION = "0.
|
|
17101
|
+
var SERVER_VERSION = "0.6.0";
|
|
16967
17102
|
async function createMcpServer(rootDir) {
|
|
16968
17103
|
const server = new McpServer({
|
|
16969
17104
|
name: "swarmvault",
|
|
@@ -17234,7 +17369,7 @@ async function createMcpServer(rootDir) {
|
|
|
17234
17369
|
},
|
|
17235
17370
|
async () => {
|
|
17236
17371
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17237
|
-
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(
|
|
17372
|
+
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path24.relative(paths.sessionsDir, filePath))).sort();
|
|
17238
17373
|
return asTextResource("swarmvault://sessions", JSON.stringify(files, null, 2));
|
|
17239
17374
|
}
|
|
17240
17375
|
);
|
|
@@ -17267,8 +17402,8 @@ async function createMcpServer(rootDir) {
|
|
|
17267
17402
|
return asTextResource(`swarmvault://pages/${encodedPath}`, `Page not found: ${relativePath}`);
|
|
17268
17403
|
}
|
|
17269
17404
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17270
|
-
const absolutePath =
|
|
17271
|
-
return asTextResource(`swarmvault://pages/${encodedPath}`, await
|
|
17405
|
+
const absolutePath = path24.resolve(paths.wikiDir, relativePath);
|
|
17406
|
+
return asTextResource(`swarmvault://pages/${encodedPath}`, await fs20.readFile(absolutePath, "utf8"));
|
|
17272
17407
|
}
|
|
17273
17408
|
);
|
|
17274
17409
|
server.registerResource(
|
|
@@ -17276,11 +17411,11 @@ async function createMcpServer(rootDir) {
|
|
|
17276
17411
|
new ResourceTemplate("swarmvault://sessions/{path}", {
|
|
17277
17412
|
list: async () => {
|
|
17278
17413
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17279
|
-
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(
|
|
17414
|
+
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path24.relative(paths.sessionsDir, filePath))).sort();
|
|
17280
17415
|
return {
|
|
17281
17416
|
resources: files.map((relativePath) => ({
|
|
17282
17417
|
uri: `swarmvault://sessions/${encodeURIComponent(relativePath)}`,
|
|
17283
|
-
name:
|
|
17418
|
+
name: path24.basename(relativePath, ".md"),
|
|
17284
17419
|
title: relativePath,
|
|
17285
17420
|
description: "SwarmVault session artifact",
|
|
17286
17421
|
mimeType: "text/markdown"
|
|
@@ -17297,11 +17432,11 @@ async function createMcpServer(rootDir) {
|
|
|
17297
17432
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17298
17433
|
const encodedPath = typeof variables.path === "string" ? variables.path : "";
|
|
17299
17434
|
const relativePath = decodeURIComponent(encodedPath);
|
|
17300
|
-
const absolutePath =
|
|
17435
|
+
const absolutePath = path24.resolve(paths.sessionsDir, relativePath);
|
|
17301
17436
|
if (!absolutePath.startsWith(paths.sessionsDir) || !await fileExists(absolutePath)) {
|
|
17302
17437
|
return asTextResource(`swarmvault://sessions/${encodedPath}`, `Session not found: ${relativePath}`);
|
|
17303
17438
|
}
|
|
17304
|
-
return asTextResource(`swarmvault://sessions/${encodedPath}`, await
|
|
17439
|
+
return asTextResource(`swarmvault://sessions/${encodedPath}`, await fs20.readFile(absolutePath, "utf8"));
|
|
17305
17440
|
}
|
|
17306
17441
|
);
|
|
17307
17442
|
return server;
|
|
@@ -17349,13 +17484,13 @@ function asTextResource(uri, text) {
|
|
|
17349
17484
|
}
|
|
17350
17485
|
|
|
17351
17486
|
// src/schedule.ts
|
|
17352
|
-
import
|
|
17353
|
-
import
|
|
17487
|
+
import fs21 from "fs/promises";
|
|
17488
|
+
import path25 from "path";
|
|
17354
17489
|
function scheduleStatePath(schedulesDir, jobId) {
|
|
17355
|
-
return
|
|
17490
|
+
return path25.join(schedulesDir, `${encodeURIComponent(jobId)}.json`);
|
|
17356
17491
|
}
|
|
17357
17492
|
function scheduleLockPath(schedulesDir, jobId) {
|
|
17358
|
-
return
|
|
17493
|
+
return path25.join(schedulesDir, `${encodeURIComponent(jobId)}.lock`);
|
|
17359
17494
|
}
|
|
17360
17495
|
function parseEveryDuration(value) {
|
|
17361
17496
|
const match = value.trim().match(/^(\d+)(m|h|d)$/i);
|
|
@@ -17458,13 +17593,13 @@ async function acquireJobLease(rootDir, jobId) {
|
|
|
17458
17593
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17459
17594
|
const leasePath = scheduleLockPath(paths.schedulesDir, jobId);
|
|
17460
17595
|
await ensureDir(paths.schedulesDir);
|
|
17461
|
-
const handle = await
|
|
17596
|
+
const handle = await fs21.open(leasePath, "wx");
|
|
17462
17597
|
await handle.writeFile(`${process.pid}
|
|
17463
17598
|
${(/* @__PURE__ */ new Date()).toISOString()}
|
|
17464
17599
|
`);
|
|
17465
17600
|
await handle.close();
|
|
17466
17601
|
return async () => {
|
|
17467
|
-
await
|
|
17602
|
+
await fs21.rm(leasePath, { force: true });
|
|
17468
17603
|
};
|
|
17469
17604
|
}
|
|
17470
17605
|
async function listSchedules(rootDir) {
|
|
@@ -17612,8 +17747,9 @@ async function serveSchedules(rootDir, pollMs = 3e4) {
|
|
|
17612
17747
|
|
|
17613
17748
|
// src/sources.ts
|
|
17614
17749
|
import { spawn as spawn2 } from "child_process";
|
|
17615
|
-
import
|
|
17616
|
-
import
|
|
17750
|
+
import fs22 from "fs/promises";
|
|
17751
|
+
import path26 from "path";
|
|
17752
|
+
import matter10 from "gray-matter";
|
|
17617
17753
|
import { JSDOM as JSDOM3 } from "jsdom";
|
|
17618
17754
|
var DEFAULT_CRAWL_MAX_PAGES = 12;
|
|
17619
17755
|
var DEFAULT_CRAWL_MAX_DEPTH = 2;
|
|
@@ -17640,24 +17776,24 @@ function normalizeManagedStatus(value) {
|
|
|
17640
17776
|
return value === "missing" || value === "error" ? value : "ready";
|
|
17641
17777
|
}
|
|
17642
17778
|
function withinRoot2(rootPath, targetPath) {
|
|
17643
|
-
const relative =
|
|
17644
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
17779
|
+
const relative = path26.relative(rootPath, targetPath);
|
|
17780
|
+
return relative === "" || !relative.startsWith("..") && !path26.isAbsolute(relative);
|
|
17645
17781
|
}
|
|
17646
17782
|
async function findNearestGitRoot3(startPath) {
|
|
17647
|
-
let current =
|
|
17783
|
+
let current = path26.resolve(startPath);
|
|
17648
17784
|
try {
|
|
17649
|
-
const stat = await
|
|
17785
|
+
const stat = await fs22.stat(current);
|
|
17650
17786
|
if (!stat.isDirectory()) {
|
|
17651
|
-
current =
|
|
17787
|
+
current = path26.dirname(current);
|
|
17652
17788
|
}
|
|
17653
17789
|
} catch {
|
|
17654
|
-
current =
|
|
17790
|
+
current = path26.dirname(current);
|
|
17655
17791
|
}
|
|
17656
17792
|
while (true) {
|
|
17657
|
-
if (await fileExists(
|
|
17793
|
+
if (await fileExists(path26.join(current, ".git"))) {
|
|
17658
17794
|
return current;
|
|
17659
17795
|
}
|
|
17660
|
-
const parent =
|
|
17796
|
+
const parent = path26.dirname(current);
|
|
17661
17797
|
if (parent === current) {
|
|
17662
17798
|
return null;
|
|
17663
17799
|
}
|
|
@@ -17731,7 +17867,7 @@ function isAllowedDocsCandidate(candidate, startUrl) {
|
|
|
17731
17867
|
if (candidate.origin !== startUrl.origin) {
|
|
17732
17868
|
return false;
|
|
17733
17869
|
}
|
|
17734
|
-
const extension =
|
|
17870
|
+
const extension = path26.extname(candidate.pathname).toLowerCase();
|
|
17735
17871
|
if (extension && extension !== ".html" && extension !== ".htm" && extension !== ".md") {
|
|
17736
17872
|
return false;
|
|
17737
17873
|
}
|
|
@@ -17820,14 +17956,14 @@ function matchesManagedSourceSpec(existing, input) {
|
|
|
17820
17956
|
return false;
|
|
17821
17957
|
}
|
|
17822
17958
|
if (input.kind === "directory" || input.kind === "file") {
|
|
17823
|
-
return
|
|
17959
|
+
return path26.resolve(existing.path ?? "") === path26.resolve(input.path);
|
|
17824
17960
|
}
|
|
17825
17961
|
return (existing.url ?? "") === input.url;
|
|
17826
17962
|
}
|
|
17827
17963
|
async function resolveManagedSourceInput(rootDir, input) {
|
|
17828
|
-
const absoluteInput =
|
|
17964
|
+
const absoluteInput = path26.resolve(rootDir, input);
|
|
17829
17965
|
if (!(input.startsWith("http://") || input.startsWith("https://"))) {
|
|
17830
|
-
const stat = await
|
|
17966
|
+
const stat = await fs22.stat(absoluteInput).catch(() => null);
|
|
17831
17967
|
if (!stat) {
|
|
17832
17968
|
throw new Error(`Source not found: ${input}`);
|
|
17833
17969
|
}
|
|
@@ -17835,7 +17971,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
17835
17971
|
return {
|
|
17836
17972
|
kind: "file",
|
|
17837
17973
|
path: absoluteInput,
|
|
17838
|
-
title:
|
|
17974
|
+
title: path26.basename(absoluteInput, path26.extname(absoluteInput)) || absoluteInput
|
|
17839
17975
|
};
|
|
17840
17976
|
}
|
|
17841
17977
|
if (!stat.isDirectory()) {
|
|
@@ -17847,7 +17983,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
17847
17983
|
kind: "directory",
|
|
17848
17984
|
path: absoluteInput,
|
|
17849
17985
|
repoRoot,
|
|
17850
|
-
title:
|
|
17986
|
+
title: path26.basename(absoluteInput) || absoluteInput
|
|
17851
17987
|
};
|
|
17852
17988
|
}
|
|
17853
17989
|
const github = normalizeGitHubRepoRootUrl(input);
|
|
@@ -17870,16 +18006,16 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
17870
18006
|
};
|
|
17871
18007
|
}
|
|
17872
18008
|
function directorySourceIdsFor(manifests, inputPath) {
|
|
17873
|
-
return manifests.filter((manifest) => manifest.originalPath && withinRoot2(
|
|
18009
|
+
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
18010
|
}
|
|
17875
18011
|
function fileSourceIdsFor(manifests, inputPath) {
|
|
17876
|
-
const absoluteInput =
|
|
17877
|
-
return manifests.filter((manifest) => manifest.originalPath &&
|
|
18012
|
+
const absoluteInput = path26.resolve(inputPath);
|
|
18013
|
+
return manifests.filter((manifest) => manifest.originalPath && path26.resolve(manifest.originalPath) === absoluteInput).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
|
|
17878
18014
|
}
|
|
17879
18015
|
async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
17880
18016
|
const manifestsBefore = await listManifests(rootDir);
|
|
17881
18017
|
const previousInScope = manifestsBefore.filter(
|
|
17882
|
-
(manifest) => manifest.originalPath && withinRoot2(
|
|
18018
|
+
(manifest) => manifest.originalPath && withinRoot2(path26.resolve(inputPath), path26.resolve(manifest.originalPath))
|
|
17883
18019
|
);
|
|
17884
18020
|
const result = await ingestDirectory(rootDir, inputPath, { repoRoot });
|
|
17885
18021
|
const removed = [];
|
|
@@ -17887,7 +18023,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
17887
18023
|
if (!manifest.originalPath) {
|
|
17888
18024
|
continue;
|
|
17889
18025
|
}
|
|
17890
|
-
if (await fileExists(
|
|
18026
|
+
if (await fileExists(path26.resolve(manifest.originalPath))) {
|
|
17891
18027
|
continue;
|
|
17892
18028
|
}
|
|
17893
18029
|
const removedManifest = await removeManifestBySourceId(rootDir, manifest.sourceId);
|
|
@@ -17897,7 +18033,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
17897
18033
|
}
|
|
17898
18034
|
const manifestsAfter = await listManifests(rootDir);
|
|
17899
18035
|
return {
|
|
17900
|
-
title:
|
|
18036
|
+
title: path26.basename(inputPath) || inputPath,
|
|
17901
18037
|
sourceIds: directorySourceIdsFor(manifestsAfter, inputPath),
|
|
17902
18038
|
counts: {
|
|
17903
18039
|
scannedCount: result.scannedCount,
|
|
@@ -17913,7 +18049,7 @@ async function syncFileSource(rootDir, inputPath) {
|
|
|
17913
18049
|
const result = await ingestInputDetailed(rootDir, inputPath);
|
|
17914
18050
|
const manifestsAfter = await listManifests(rootDir);
|
|
17915
18051
|
return {
|
|
17916
|
-
title:
|
|
18052
|
+
title: path26.basename(inputPath, path26.extname(inputPath)) || inputPath,
|
|
17917
18053
|
sourceIds: fileSourceIdsFor(manifestsAfter, inputPath),
|
|
17918
18054
|
counts: {
|
|
17919
18055
|
scannedCount: result.scannedCount,
|
|
@@ -17947,8 +18083,8 @@ async function runGitCommand(cwd, args) {
|
|
|
17947
18083
|
}
|
|
17948
18084
|
async function syncGitHubRepoSource(rootDir, entry) {
|
|
17949
18085
|
const workingDir = await managedSourceWorkingDir(rootDir, entry.id);
|
|
17950
|
-
const checkoutDir =
|
|
17951
|
-
await
|
|
18086
|
+
const checkoutDir = path26.join(workingDir, "checkout");
|
|
18087
|
+
await fs22.rm(checkoutDir, { recursive: true, force: true });
|
|
17952
18088
|
await ensureDir(workingDir);
|
|
17953
18089
|
if (!entry.url) {
|
|
17954
18090
|
throw new Error(`Managed source ${entry.id} is missing its repository URL.`);
|
|
@@ -18075,7 +18211,7 @@ function scopedNodeIds(graph, sourceIds) {
|
|
|
18075
18211
|
async function loadSourceAnalyses(rootDir, sourceIds) {
|
|
18076
18212
|
const { paths } = await loadVaultConfig(rootDir);
|
|
18077
18213
|
const analyses = await Promise.all(
|
|
18078
|
-
sourceIds.map(async (sourceId) => await readJsonFile(
|
|
18214
|
+
sourceIds.map(async (sourceId) => await readJsonFile(path26.join(paths.analysesDir, `${sourceId}.json`)))
|
|
18079
18215
|
);
|
|
18080
18216
|
return analyses.filter((analysis) => Boolean(analysis?.sourceId));
|
|
18081
18217
|
}
|
|
@@ -18235,9 +18371,9 @@ async function writeSourceBriefForScope(rootDir, source) {
|
|
|
18235
18371
|
confidence: 0.82
|
|
18236
18372
|
}
|
|
18237
18373
|
});
|
|
18238
|
-
const absolutePath =
|
|
18239
|
-
await ensureDir(
|
|
18240
|
-
await
|
|
18374
|
+
const absolutePath = path26.join(paths.wikiDir, output.page.path);
|
|
18375
|
+
await ensureDir(path26.dirname(absolutePath));
|
|
18376
|
+
await fs22.writeFile(absolutePath, output.content, "utf8");
|
|
18241
18377
|
return absolutePath;
|
|
18242
18378
|
}
|
|
18243
18379
|
async function writeSourceBrief(rootDir, source) {
|
|
@@ -18256,6 +18392,59 @@ async function generateBriefsForSources(rootDir, sources) {
|
|
|
18256
18392
|
}
|
|
18257
18393
|
return briefPaths;
|
|
18258
18394
|
}
|
|
18395
|
+
var GUIDED_SESSION_QUESTIONS = [
|
|
18396
|
+
{
|
|
18397
|
+
id: "importance",
|
|
18398
|
+
prompt: "What matters most from this source for your wiki right now?"
|
|
18399
|
+
},
|
|
18400
|
+
{
|
|
18401
|
+
id: "exclude",
|
|
18402
|
+
prompt: "What should stay provisional, be ignored, or be kept out for now?"
|
|
18403
|
+
},
|
|
18404
|
+
{
|
|
18405
|
+
id: "targets",
|
|
18406
|
+
prompt: "Which canonical pages or topics should this source update?"
|
|
18407
|
+
},
|
|
18408
|
+
{
|
|
18409
|
+
id: "conflicts",
|
|
18410
|
+
prompt: "What feels new, reinforcing, or conflicting compared with what you already believe?"
|
|
18411
|
+
},
|
|
18412
|
+
{
|
|
18413
|
+
id: "followups",
|
|
18414
|
+
prompt: "What follow-up questions or next sources should stay open?"
|
|
18415
|
+
}
|
|
18416
|
+
];
|
|
18417
|
+
function defaultGuidedSessionQuestions() {
|
|
18418
|
+
return GUIDED_SESSION_QUESTIONS.map((question) => ({ ...question }));
|
|
18419
|
+
}
|
|
18420
|
+
function normalizeGuidedAnswerValue(value) {
|
|
18421
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
18422
|
+
}
|
|
18423
|
+
function normalizeGuidedAnswers(input) {
|
|
18424
|
+
if (!input) {
|
|
18425
|
+
return {};
|
|
18426
|
+
}
|
|
18427
|
+
if (Array.isArray(input)) {
|
|
18428
|
+
return Object.fromEntries(
|
|
18429
|
+
GUIDED_SESSION_QUESTIONS.map((question, index) => [question.id, normalizeGuidedAnswerValue(input[index])]).filter(
|
|
18430
|
+
(entry) => Boolean(entry[1])
|
|
18431
|
+
)
|
|
18432
|
+
);
|
|
18433
|
+
}
|
|
18434
|
+
return Object.fromEntries(
|
|
18435
|
+
Object.entries(input).map(([key, value]) => [key, normalizeGuidedAnswerValue(value)]).filter((entry) => Boolean(entry[1]))
|
|
18436
|
+
);
|
|
18437
|
+
}
|
|
18438
|
+
function mergeGuidedSessionQuestions(questions, answers) {
|
|
18439
|
+
const normalizedAnswers = normalizeGuidedAnswers(answers);
|
|
18440
|
+
return questions.map((question) => ({
|
|
18441
|
+
...question,
|
|
18442
|
+
answer: normalizedAnswers[question.id] ?? question.answer
|
|
18443
|
+
}));
|
|
18444
|
+
}
|
|
18445
|
+
function answeredGuidedSessionQuestions(questions) {
|
|
18446
|
+
return questions.filter((question) => typeof question.answer === "string" && question.answer.trim().length > 0);
|
|
18447
|
+
}
|
|
18259
18448
|
function renderDeterministicSourceReview(input) {
|
|
18260
18449
|
const canonicalPages = input.sourcePages.filter((page) => page.kind === "source" || page.kind === "concept" || page.kind === "entity").slice(0, 10);
|
|
18261
18450
|
const modulePages = input.sourcePages.filter((page) => page.kind === "module").slice(0, 8);
|
|
@@ -18399,6 +18588,75 @@ function classifySourceGuidePageBuckets(sourcePages, scopeSourceIds) {
|
|
|
18399
18588
|
const reinforcingPages = canonicalPages.filter((page) => page.sourceIds.some((sourceId) => !scopeSet.has(sourceId))).slice(0, 6);
|
|
18400
18589
|
return { canonicalPages, newPages, reinforcingPages };
|
|
18401
18590
|
}
|
|
18591
|
+
function findContradictionsForScope(scope, report) {
|
|
18592
|
+
return report?.contradictions.filter(
|
|
18593
|
+
(contradiction) => scope.sourceIds.includes(contradiction.sourceIdA) || scope.sourceIds.includes(contradiction.sourceIdB)
|
|
18594
|
+
) ?? [];
|
|
18595
|
+
}
|
|
18596
|
+
function selectGuidedTargetPages(scope, sourcePages, questions) {
|
|
18597
|
+
const { canonicalPages } = classifySourceGuidePageBuckets(sourcePages, scope.sourceIds);
|
|
18598
|
+
if (!canonicalPages.length) {
|
|
18599
|
+
return [];
|
|
18600
|
+
}
|
|
18601
|
+
const desiredTargets = normalizeWhitespace(
|
|
18602
|
+
questions.find((question) => question.id === "targets")?.answer ?? questions.find((question) => question.id === "importance")?.answer ?? ""
|
|
18603
|
+
).toLowerCase();
|
|
18604
|
+
const matchedTargets = desiredTargets ? canonicalPages.filter((page) => {
|
|
18605
|
+
const title = page.title.toLowerCase();
|
|
18606
|
+
const relative = page.path.replace(/\.md$/, "").toLowerCase();
|
|
18607
|
+
return desiredTargets.includes(title) || desiredTargets.includes(relative) || title.includes(desiredTargets);
|
|
18608
|
+
}) : [];
|
|
18609
|
+
return (matchedTargets.length ? matchedTargets : canonicalPages).slice(0, 6);
|
|
18610
|
+
}
|
|
18611
|
+
function insightRelativePathForTarget(page, scope) {
|
|
18612
|
+
const basename = path26.basename(page.path);
|
|
18613
|
+
if (page.kind === "concept") {
|
|
18614
|
+
return `insights/concepts/${basename}`;
|
|
18615
|
+
}
|
|
18616
|
+
if (page.kind === "entity") {
|
|
18617
|
+
return `insights/entities/${basename}`;
|
|
18618
|
+
}
|
|
18619
|
+
if (page.kind === "source") {
|
|
18620
|
+
return `insights/sources/${slugify(page.title || scope.title)}.md`;
|
|
18621
|
+
}
|
|
18622
|
+
return `insights/topics/${slugify(page.title || scope.title)}.md`;
|
|
18623
|
+
}
|
|
18624
|
+
function insightTitleForTarget(page, scope) {
|
|
18625
|
+
if (page.kind === "concept" || page.kind === "entity") {
|
|
18626
|
+
return page.title;
|
|
18627
|
+
}
|
|
18628
|
+
if (page.kind === "source") {
|
|
18629
|
+
return `Source Notes: ${page.title}`;
|
|
18630
|
+
}
|
|
18631
|
+
return `${scope.title} Notes`;
|
|
18632
|
+
}
|
|
18633
|
+
function insightTagsForTarget(page) {
|
|
18634
|
+
return uniqueStrings4(["insight", "guided-session", `guided/${page?.kind ?? "topic"}`]);
|
|
18635
|
+
}
|
|
18636
|
+
function guidedUpdateMarker(scopeId) {
|
|
18637
|
+
return {
|
|
18638
|
+
start: `<!-- swarmvault-guided-source:${scopeId}:start -->`,
|
|
18639
|
+
end: `<!-- swarmvault-guided-source:${scopeId}:end -->`
|
|
18640
|
+
};
|
|
18641
|
+
}
|
|
18642
|
+
function replaceMarkedSection(content, scopeId, replacement) {
|
|
18643
|
+
const marker = guidedUpdateMarker(scopeId);
|
|
18644
|
+
const block = `${marker.start}
|
|
18645
|
+
${replacement.trim()}
|
|
18646
|
+
${marker.end}`;
|
|
18647
|
+
const startIndex = content.indexOf(marker.start);
|
|
18648
|
+
const endIndex = content.indexOf(marker.end);
|
|
18649
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
18650
|
+
return `${content.slice(0, startIndex).trimEnd()}
|
|
18651
|
+
|
|
18652
|
+
${block}
|
|
18653
|
+
`;
|
|
18654
|
+
}
|
|
18655
|
+
return `${content.trimEnd()}
|
|
18656
|
+
|
|
18657
|
+
${block}
|
|
18658
|
+
`;
|
|
18659
|
+
}
|
|
18402
18660
|
function renderDeterministicSourceGuide(input) {
|
|
18403
18661
|
const { canonicalPages, newPages, reinforcingPages } = classifySourceGuidePageBuckets(input.sourcePages, input.scope.sourceIds);
|
|
18404
18662
|
const modulePages = input.sourcePages.filter((page) => page.kind === "module").slice(0, 6);
|
|
@@ -18563,40 +18821,338 @@ async function stageSourceReviewForScope(rootDir, scope) {
|
|
|
18563
18821
|
return {
|
|
18564
18822
|
sourceId: scope.id,
|
|
18565
18823
|
pageId: output.page.id,
|
|
18566
|
-
reviewPath:
|
|
18824
|
+
reviewPath: path26.join(approval.approvalDir, "wiki", output.page.path),
|
|
18567
18825
|
staged: true,
|
|
18568
18826
|
approvalId: approval.approvalId,
|
|
18569
18827
|
approvalDir: approval.approvalDir
|
|
18570
18828
|
};
|
|
18571
18829
|
}
|
|
18572
|
-
|
|
18573
|
-
|
|
18830
|
+
function nextGuidedSourceSessionId(scope) {
|
|
18831
|
+
return `source-session-${slugify(scope.id)}-${sha256(`${scope.id}:${(/* @__PURE__ */ new Date()).toISOString()}`).slice(0, 8)}`;
|
|
18832
|
+
}
|
|
18833
|
+
function shouldReuseGuidedSourceSession(session) {
|
|
18834
|
+
return Boolean(session && session.status === "awaiting_input");
|
|
18835
|
+
}
|
|
18836
|
+
function questionAnswer(questions, id, fallback) {
|
|
18837
|
+
return normalizeGuidedAnswerValue(questions.find((question) => question.id === id)?.answer) ?? fallback;
|
|
18838
|
+
}
|
|
18839
|
+
async function prepareGuidedSourceSession(rootDir, scope, answers) {
|
|
18840
|
+
const existing = await findLatestGuidedSourceSessionByScope(rootDir, scope.id);
|
|
18841
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18842
|
+
const session = shouldReuseGuidedSourceSession(existing) ? {
|
|
18843
|
+
...existing,
|
|
18844
|
+
scopeTitle: scope.title,
|
|
18845
|
+
sourceIds: scope.sourceIds,
|
|
18846
|
+
kind: scope.kind,
|
|
18847
|
+
questions: mergeGuidedSessionQuestions(existing.questions, answers),
|
|
18848
|
+
updatedAt: now
|
|
18849
|
+
} : {
|
|
18850
|
+
sessionId: nextGuidedSourceSessionId(scope),
|
|
18851
|
+
scopeId: scope.id,
|
|
18852
|
+
scopeTitle: scope.title,
|
|
18853
|
+
sourceIds: scope.sourceIds,
|
|
18854
|
+
kind: scope.kind,
|
|
18855
|
+
status: "awaiting_input",
|
|
18856
|
+
createdAt: now,
|
|
18857
|
+
updatedAt: now,
|
|
18858
|
+
questions: mergeGuidedSessionQuestions(defaultGuidedSessionQuestions(), answers),
|
|
18859
|
+
briefPath: scope.briefPath,
|
|
18860
|
+
targetedPagePaths: [],
|
|
18861
|
+
stagedUpdatePaths: []
|
|
18862
|
+
};
|
|
18863
|
+
const statePath = await guidedSourceSessionStatePath(rootDir, session.sessionId);
|
|
18864
|
+
return { session, statePath };
|
|
18865
|
+
}
|
|
18866
|
+
async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
18867
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
18868
|
+
let graph = await readJsonFile(paths.graphPath);
|
|
18869
|
+
if (!graph) {
|
|
18870
|
+
await compileVault(rootDir, {});
|
|
18871
|
+
graph = await readJsonFile(paths.graphPath);
|
|
18872
|
+
}
|
|
18873
|
+
const sourcePages = graph ? scopedSourcePages(graph, scope.sourceIds) : [];
|
|
18874
|
+
const analyses = await loadSourceAnalyses(rootDir, scope.sourceIds);
|
|
18875
|
+
const report = await readGraphReport(rootDir);
|
|
18876
|
+
const contradictions = findContradictionsForScope(scope, report);
|
|
18877
|
+
const relatedPageIds = uniqueStrings4([
|
|
18878
|
+
...sourcePages.slice(0, 18).map((page) => page.id),
|
|
18879
|
+
...session.targetedPagePaths.map((relativePath) => {
|
|
18880
|
+
const page = graph?.pages.find((candidate) => candidate.path === relativePath);
|
|
18881
|
+
return page?.id ?? "";
|
|
18882
|
+
})
|
|
18883
|
+
]);
|
|
18884
|
+
const relatedNodeIds = graph ? scopedNodeIds(graph, scope.sourceIds).slice(0, 28) : [];
|
|
18885
|
+
const projectIds = uniqueStrings4(sourcePages.flatMap((page) => page.projectIds));
|
|
18886
|
+
const relativeBriefPath = session.briefPath && path26.isAbsolute(session.briefPath) ? path26.relative(paths.wikiDir, session.briefPath) : session.briefPath;
|
|
18887
|
+
const sessionMarkdown = [
|
|
18888
|
+
`# Guided Session: ${scope.title}`,
|
|
18889
|
+
"",
|
|
18890
|
+
`Status: \`${session.status}\``,
|
|
18891
|
+
`Session ID: \`${session.sessionId}\``,
|
|
18892
|
+
...session.approvalId ? [`Approval Bundle: \`${session.approvalId}\``] : [],
|
|
18893
|
+
...relativeBriefPath ? [`Brief: \`${relativeBriefPath}\``] : [],
|
|
18894
|
+
"",
|
|
18895
|
+
"## What This Source Is",
|
|
18896
|
+
"",
|
|
18897
|
+
...analyses.length ? analyses.slice(0, 6).map((analysis) => `- ${analysis.title}: ${analysis.summary}`) : ["- Awaiting compile context."],
|
|
18898
|
+
"",
|
|
18899
|
+
"## Guided Questions",
|
|
18900
|
+
"",
|
|
18901
|
+
...session.questions.flatMap((question) => [`### ${question.prompt}`, "", question.answer ?? "_Awaiting input._", ""]),
|
|
18902
|
+
"## Proposed Wiki Targets",
|
|
18903
|
+
"",
|
|
18904
|
+
...session.targetedPagePaths.length ? session.targetedPagePaths.map((targetPath) => `- [[${targetPath.replace(/\.md$/, "")}]]`) : ["- No canonical update targets selected yet."],
|
|
18905
|
+
"",
|
|
18906
|
+
"## Conflicts And Judgment Calls",
|
|
18907
|
+
"",
|
|
18908
|
+
...contradictions.length ? contradictions.map((contradiction) => `- ${contradiction.claimA} / ${contradiction.claimB}`) : ["- No contradictions are currently flagged for this source scope."],
|
|
18909
|
+
"",
|
|
18910
|
+
"## Follow-up Questions",
|
|
18911
|
+
"",
|
|
18912
|
+
...(() => {
|
|
18913
|
+
const followups = questionAnswer(session.questions, "followups", "");
|
|
18914
|
+
if (followups) {
|
|
18915
|
+
return followups.split(/\n+/).map((line) => line.trim()).filter(Boolean).map((line) => `- ${line.replace(/^-+\s*/, "")}`);
|
|
18916
|
+
}
|
|
18917
|
+
const analysisQuestions = uniqueStrings4(analyses.flatMap((analysis) => analysis.questions)).slice(0, 6);
|
|
18918
|
+
return analysisQuestions.length ? analysisQuestions.map((question) => `- ${question}`) : ["- No follow-up questions recorded yet."];
|
|
18919
|
+
})(),
|
|
18920
|
+
"",
|
|
18921
|
+
"## Related Artifacts",
|
|
18922
|
+
"",
|
|
18923
|
+
`- [[outputs/source-briefs/${scope.id}|Source Brief]]`,
|
|
18924
|
+
`- [[outputs/source-reviews/${scope.id}|Source Review]]`,
|
|
18925
|
+
`- [[outputs/source-guides/${scope.id}|Source Guide]]`,
|
|
18926
|
+
""
|
|
18927
|
+
].join("\n");
|
|
18928
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18929
|
+
const output = buildOutputPage({
|
|
18930
|
+
title: `Guided Session: ${scope.title}`,
|
|
18931
|
+
question: `Guided Session ${scope.title}`,
|
|
18932
|
+
answer: sessionMarkdown,
|
|
18933
|
+
citations: scope.sourceIds,
|
|
18934
|
+
schemaHash: graph?.generatedAt ?? "",
|
|
18935
|
+
outputFormat: "report",
|
|
18936
|
+
relatedPageIds,
|
|
18937
|
+
relatedNodeIds,
|
|
18938
|
+
relatedSourceIds: scope.sourceIds,
|
|
18939
|
+
projectIds,
|
|
18940
|
+
extraTags: ["source-session", "guided-session"],
|
|
18941
|
+
origin: "query",
|
|
18942
|
+
slug: `source-sessions/${scope.id}`,
|
|
18943
|
+
metadata: {
|
|
18944
|
+
status: "active",
|
|
18945
|
+
createdAt: now,
|
|
18946
|
+
updatedAt: now,
|
|
18947
|
+
compiledFrom: scope.sourceIds,
|
|
18948
|
+
managedBy: "system",
|
|
18949
|
+
confidence: 0.81
|
|
18950
|
+
}
|
|
18951
|
+
});
|
|
18952
|
+
return { page: output.page, content: output.content };
|
|
18953
|
+
}
|
|
18954
|
+
async function persistSourceSessionPage(rootDir, scope, session) {
|
|
18955
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
18956
|
+
const output = await buildSourceSessionSavedPage(rootDir, scope, session);
|
|
18957
|
+
const absolutePath = path26.join(paths.wikiDir, output.page.path);
|
|
18958
|
+
await ensureDir(path26.dirname(absolutePath));
|
|
18959
|
+
await fs22.writeFile(absolutePath, output.content, "utf8");
|
|
18960
|
+
return { pageId: output.page.id, sessionPath: absolutePath };
|
|
18961
|
+
}
|
|
18962
|
+
async function buildGuidedInsightUpdatePages(rootDir, scope, session) {
|
|
18963
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
18964
|
+
let graph = await readJsonFile(paths.graphPath);
|
|
18965
|
+
if (!graph) {
|
|
18966
|
+
await compileVault(rootDir, {});
|
|
18967
|
+
graph = await readJsonFile(paths.graphPath);
|
|
18968
|
+
}
|
|
18969
|
+
if (!graph) {
|
|
18970
|
+
return [];
|
|
18971
|
+
}
|
|
18972
|
+
const sourcePages = scopedSourcePages(graph, scope.sourceIds);
|
|
18973
|
+
const analyses = await loadSourceAnalyses(rootDir, scope.sourceIds);
|
|
18974
|
+
const report = await readGraphReport(rootDir);
|
|
18975
|
+
const contradictions = findContradictionsForScope(scope, report);
|
|
18976
|
+
const selectedTargets = selectGuidedTargetPages(scope, sourcePages, session.questions);
|
|
18977
|
+
const targetPages = selectedTargets.length ? selectedTargets : [null];
|
|
18978
|
+
return await Promise.all(
|
|
18979
|
+
targetPages.map(async (targetPage, index) => {
|
|
18980
|
+
const relativePath = targetPage ? insightRelativePathForTarget(targetPage, scope) : `insights/topics/${slugify(scope.title)}.md`;
|
|
18981
|
+
const absolutePath = path26.join(paths.wikiDir, relativePath);
|
|
18982
|
+
const existingContent = await fileExists(absolutePath) ? await fs22.readFile(absolutePath, "utf8") : "";
|
|
18983
|
+
const parsed = existingContent ? matter10(existingContent) : { data: {}, content: "" };
|
|
18984
|
+
const existingData = parsed.data;
|
|
18985
|
+
const existingSourceIds = Array.isArray(existingData.source_ids) ? existingData.source_ids.filter((value) => typeof value === "string") : [];
|
|
18986
|
+
const existingProjectIds = Array.isArray(existingData.project_ids) ? existingData.project_ids.filter((value) => typeof value === "string") : [];
|
|
18987
|
+
const existingNodeIds = Array.isArray(existingData.node_ids) ? existingData.node_ids.filter((value) => typeof value === "string") : [];
|
|
18988
|
+
const existingBacklinks = Array.isArray(existingData.backlinks) ? existingData.backlinks.filter((value) => typeof value === "string") : [];
|
|
18989
|
+
const createdAt = typeof existingData.created_at === "string" && existingData.created_at.trim() ? existingData.created_at : (/* @__PURE__ */ new Date()).toISOString();
|
|
18990
|
+
const title = typeof existingData.title === "string" && existingData.title.trim() || (targetPage ? insightTitleForTarget(targetPage, scope) : `${scope.title} Notes`);
|
|
18991
|
+
const baseBody = parsed.content.trim() ? parsed.content.trim() : [`# ${title}`, "", "Human-curated insight page. Guided sessions stage replaceable update blocks here.", ""].join("\n");
|
|
18992
|
+
const importance = questionAnswer(
|
|
18993
|
+
session.questions,
|
|
18994
|
+
"importance",
|
|
18995
|
+
"Capture the most important new ideas from this source before treating them as canonical."
|
|
18996
|
+
);
|
|
18997
|
+
const exclude = questionAnswer(
|
|
18998
|
+
session.questions,
|
|
18999
|
+
"exclude",
|
|
19000
|
+
"Keep uncertain or incidental details provisional until they matter to the research thread."
|
|
19001
|
+
);
|
|
19002
|
+
const conflictNotes = questionAnswer(
|
|
19003
|
+
session.questions,
|
|
19004
|
+
"conflicts",
|
|
19005
|
+
contradictions.length ? "Review the conflicting evidence before accepting any canonical summary changes." : "No explicit conflicts were called out."
|
|
19006
|
+
);
|
|
19007
|
+
const followups = questionAnswer(session.questions, "followups", "Track follow-up questions on the source session page.");
|
|
19008
|
+
const updateBlock = [
|
|
19009
|
+
`## Guided Session Update: ${scope.title}`,
|
|
19010
|
+
"",
|
|
19011
|
+
`Session: [[outputs/source-sessions/${scope.id}|Guided Session]]`,
|
|
19012
|
+
`Source Guide: [[outputs/source-guides/${scope.id}|Source Guide]]`,
|
|
19013
|
+
"",
|
|
19014
|
+
"### What Matters Now",
|
|
19015
|
+
"",
|
|
19016
|
+
importance,
|
|
19017
|
+
"",
|
|
19018
|
+
"### Proposed Integration",
|
|
19019
|
+
"",
|
|
19020
|
+
targetPage ? `- Fold the strongest source-backed takeaways into [[${targetPage.path.replace(/\.md$/, "")}|${targetPage.title}]].` : `- Start a durable topic note for ${scope.title}.`,
|
|
19021
|
+
...analyses.slice(0, 5).map((analysis) => `- ${truncate(normalizeWhitespace(analysis.summary), 180)}`),
|
|
19022
|
+
"",
|
|
19023
|
+
"### Keep Provisional Or Out",
|
|
19024
|
+
"",
|
|
19025
|
+
exclude,
|
|
19026
|
+
"",
|
|
19027
|
+
"### Reinforcing Or Conflicting Notes",
|
|
19028
|
+
"",
|
|
19029
|
+
conflictNotes,
|
|
19030
|
+
...contradictions.length ? ["", ...contradictions.slice(0, 4).map((contradiction) => `- ${contradiction.claimA} / ${contradiction.claimB}`)] : [],
|
|
19031
|
+
"",
|
|
19032
|
+
"### Follow-up Questions",
|
|
19033
|
+
"",
|
|
19034
|
+
followups,
|
|
19035
|
+
""
|
|
19036
|
+
].join("\n");
|
|
19037
|
+
const nextBody = replaceMarkedSection(baseBody, scope.id, updateBlock);
|
|
19038
|
+
const content = matter10.stringify(`${nextBody.trimEnd()}
|
|
19039
|
+
`, {
|
|
19040
|
+
...existingData,
|
|
19041
|
+
page_id: typeof existingData.page_id === "string" && existingData.page_id.trim() || `insight:${slugify(relativePath.replace(/\.md$/, ""))}`,
|
|
19042
|
+
kind: "insight",
|
|
19043
|
+
title,
|
|
19044
|
+
tags: uniqueStrings4([
|
|
19045
|
+
...Array.isArray(existingData.tags) ? existingData.tags.filter((value) => typeof value === "string") : [],
|
|
19046
|
+
...insightTagsForTarget(targetPage)
|
|
19047
|
+
]),
|
|
19048
|
+
source_ids: uniqueStrings4([...existingSourceIds, ...scope.sourceIds]),
|
|
19049
|
+
project_ids: uniqueStrings4([...existingProjectIds, ...targetPage?.projectIds ?? []]),
|
|
19050
|
+
node_ids: uniqueStrings4([...existingNodeIds, ...targetPage?.nodeIds ?? []]),
|
|
19051
|
+
freshness: "fresh",
|
|
19052
|
+
status: existingData.status === "archived" ? "archived" : "active",
|
|
19053
|
+
confidence: 0.83,
|
|
19054
|
+
created_at: createdAt,
|
|
19055
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19056
|
+
compiled_from: uniqueStrings4([
|
|
19057
|
+
...Array.isArray(existingData.compiled_from) ? existingData.compiled_from.filter((value) => typeof value === "string") : [],
|
|
19058
|
+
...scope.sourceIds
|
|
19059
|
+
]),
|
|
19060
|
+
managed_by: "human",
|
|
19061
|
+
backlinks: uniqueStrings4([
|
|
19062
|
+
...existingBacklinks,
|
|
19063
|
+
...targetPage ? [targetPage.id] : [],
|
|
19064
|
+
`output:source-sessions/${scope.id}`,
|
|
19065
|
+
`output:source-guides/${scope.id}`
|
|
19066
|
+
]),
|
|
19067
|
+
schema_hash: typeof existingData.schema_hash === "string" ? existingData.schema_hash : "",
|
|
19068
|
+
source_hashes: existingData.source_hashes && typeof existingData.source_hashes === "object" ? existingData.source_hashes : {},
|
|
19069
|
+
source_semantic_hashes: existingData.source_semantic_hashes && typeof existingData.source_semantic_hashes === "object" ? existingData.source_semantic_hashes : {}
|
|
19070
|
+
});
|
|
19071
|
+
const page = parseStoredPage(relativePath, content, {
|
|
19072
|
+
createdAt,
|
|
19073
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
19074
|
+
});
|
|
19075
|
+
if (index === 0) {
|
|
19076
|
+
session.targetedPagePaths = uniqueStrings4([
|
|
19077
|
+
...session.targetedPagePaths,
|
|
19078
|
+
...selectedTargets.length ? selectedTargets.map((page2) => page2.path) : [relativePath]
|
|
19079
|
+
]);
|
|
19080
|
+
}
|
|
19081
|
+
return { page, content, label: "guided-update" };
|
|
19082
|
+
})
|
|
19083
|
+
);
|
|
19084
|
+
}
|
|
19085
|
+
async function stageSourceGuideForScope(rootDir, scope, options = {}) {
|
|
19086
|
+
const { session, statePath } = await prepareGuidedSourceSession(rootDir, scope, options.answers);
|
|
19087
|
+
const briefPath = scope.briefPath ?? session.briefPath ?? await writeSourceBriefForScope(rootDir, scope) ?? void 0;
|
|
19088
|
+
session.briefPath = briefPath;
|
|
18574
19089
|
if (briefPath) {
|
|
18575
19090
|
await refreshVaultAfterOutputSave(rootDir);
|
|
18576
19091
|
}
|
|
19092
|
+
if (answeredGuidedSessionQuestions(session.questions).length === 0) {
|
|
19093
|
+
session.status = "awaiting_input";
|
|
19094
|
+
const persisted2 = await persistSourceSessionPage(rootDir, scope, session);
|
|
19095
|
+
session.sessionPath = persisted2.sessionPath;
|
|
19096
|
+
await writeGuidedSourceSession(rootDir, session);
|
|
19097
|
+
await refreshVaultAfterOutputSave(rootDir);
|
|
19098
|
+
return {
|
|
19099
|
+
sourceId: scope.id,
|
|
19100
|
+
sessionId: session.sessionId,
|
|
19101
|
+
sessionPath: persisted2.sessionPath,
|
|
19102
|
+
sessionStatePath: statePath,
|
|
19103
|
+
status: session.status,
|
|
19104
|
+
questions: session.questions,
|
|
19105
|
+
awaitingInput: true,
|
|
19106
|
+
targetedPagePaths: session.targetedPagePaths,
|
|
19107
|
+
stagedUpdatePaths: session.stagedUpdatePaths,
|
|
19108
|
+
briefPath,
|
|
19109
|
+
staged: false
|
|
19110
|
+
};
|
|
19111
|
+
}
|
|
19112
|
+
session.status = "ready_to_stage";
|
|
19113
|
+
await writeGuidedSourceSession(rootDir, session);
|
|
18577
19114
|
const reviewOutput = await buildSourceReviewStagedPage(rootDir, scope);
|
|
18578
19115
|
const guideOutput = await buildSourceGuideStagedPage(rootDir, {
|
|
18579
19116
|
...scope,
|
|
18580
19117
|
briefPath
|
|
18581
19118
|
});
|
|
19119
|
+
const guidedUpdates = await buildGuidedInsightUpdatePages(rootDir, scope, session);
|
|
19120
|
+
session.stagedUpdatePaths = guidedUpdates.map((item) => item.page.path);
|
|
18582
19121
|
const approval = await stageGeneratedOutputPages(
|
|
18583
19122
|
rootDir,
|
|
18584
19123
|
[
|
|
18585
19124
|
{ page: reviewOutput.page, content: reviewOutput.content, label: "source-review" },
|
|
18586
|
-
{ page: guideOutput.page, content: guideOutput.content, label: "source-guide" }
|
|
19125
|
+
{ page: guideOutput.page, content: guideOutput.content, label: "source-guide" },
|
|
19126
|
+
...guidedUpdates
|
|
18587
19127
|
],
|
|
18588
19128
|
{
|
|
18589
|
-
bundleType: "
|
|
18590
|
-
title: `Guided
|
|
19129
|
+
bundleType: "guided_session",
|
|
19130
|
+
title: `Guided Session: ${scope.title}`,
|
|
19131
|
+
sourceSessionId: session.sessionId
|
|
18591
19132
|
}
|
|
18592
19133
|
);
|
|
19134
|
+
session.status = "staged";
|
|
19135
|
+
session.reviewPath = path26.join(approval.approvalDir, "wiki", reviewOutput.page.path);
|
|
19136
|
+
session.guidePath = path26.join(approval.approvalDir, "wiki", guideOutput.page.path);
|
|
19137
|
+
session.approvalId = approval.approvalId;
|
|
19138
|
+
session.approvalDir = approval.approvalDir;
|
|
19139
|
+
const persisted = await persistSourceSessionPage(rootDir, scope, session);
|
|
19140
|
+
session.sessionPath = persisted.sessionPath;
|
|
19141
|
+
await writeGuidedSourceSession(rootDir, session);
|
|
18593
19142
|
await refreshVaultAfterOutputSave(rootDir);
|
|
18594
19143
|
return {
|
|
18595
19144
|
sourceId: scope.id,
|
|
18596
19145
|
pageId: guideOutput.page.id,
|
|
18597
|
-
guidePath:
|
|
19146
|
+
guidePath: session.guidePath,
|
|
18598
19147
|
reviewPageId: reviewOutput.page.id,
|
|
18599
|
-
reviewPath:
|
|
19148
|
+
reviewPath: session.reviewPath,
|
|
19149
|
+
sessionId: session.sessionId,
|
|
19150
|
+
sessionPath: persisted.sessionPath,
|
|
19151
|
+
sessionStatePath: statePath,
|
|
19152
|
+
status: session.status,
|
|
19153
|
+
questions: session.questions,
|
|
19154
|
+
targetedPagePaths: session.targetedPagePaths,
|
|
19155
|
+
stagedUpdatePaths: session.stagedUpdatePaths,
|
|
18600
19156
|
briefPath,
|
|
18601
19157
|
staged: true,
|
|
18602
19158
|
approvalId: approval.approvalId,
|
|
@@ -18612,53 +19168,82 @@ function scopeFromManagedSource(source) {
|
|
|
18612
19168
|
briefPath: source.briefPath
|
|
18613
19169
|
};
|
|
18614
19170
|
}
|
|
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,
|
|
19171
|
+
function scopeFromManifest(manifest, manifests) {
|
|
19172
|
+
const groupId = manifest.sourceGroupId ?? manifest.sourceId;
|
|
19173
|
+
return {
|
|
19174
|
+
id: groupId,
|
|
18637
19175
|
title: manifest.sourceGroupTitle ?? manifest.title,
|
|
18638
19176
|
sourceIds: manifest.sourceGroupId ? manifests.filter((candidate) => candidate.sourceGroupId === manifest.sourceGroupId).map((candidate) => candidate.sourceId) : [manifest.sourceId],
|
|
18639
19177
|
kind: manifest.sourceKind
|
|
18640
|
-
}
|
|
19178
|
+
};
|
|
18641
19179
|
}
|
|
18642
|
-
async function
|
|
19180
|
+
async function resolveSourceScope(rootDir, id) {
|
|
18643
19181
|
const managedSources = await loadManagedSources(rootDir);
|
|
18644
19182
|
const managedSource = managedSources.find((source) => source.id === id);
|
|
18645
19183
|
if (managedSource) {
|
|
18646
|
-
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
|
|
19184
|
+
return scopeFromManagedSource(managedSource);
|
|
19185
|
+
}
|
|
19186
|
+
const latestSession = await findLatestGuidedSourceSessionByScope(rootDir, id);
|
|
19187
|
+
if (latestSession) {
|
|
19188
|
+
return {
|
|
19189
|
+
id: latestSession.scopeId,
|
|
19190
|
+
title: latestSession.scopeTitle,
|
|
19191
|
+
sourceIds: latestSession.sourceIds
|
|
19192
|
+
};
|
|
18650
19193
|
}
|
|
18651
19194
|
const manifests = await listManifests(rootDir);
|
|
18652
|
-
const manifest = manifests.find((candidate) => candidate.sourceId === id);
|
|
19195
|
+
const manifest = manifests.find((candidate) => candidate.sourceId === id) ?? manifests.find((candidate) => candidate.sourceGroupId === id);
|
|
18653
19196
|
if (!manifest) {
|
|
19197
|
+
return null;
|
|
19198
|
+
}
|
|
19199
|
+
return scopeFromManifest(manifest, manifests);
|
|
19200
|
+
}
|
|
19201
|
+
async function reviewSourceScope(rootDir, scope) {
|
|
19202
|
+
return await stageSourceReviewForScope(rootDir, scope);
|
|
19203
|
+
}
|
|
19204
|
+
async function guideSourceScope(rootDir, scope, options = {}) {
|
|
19205
|
+
return await stageSourceGuideForScope(rootDir, scope, options);
|
|
19206
|
+
}
|
|
19207
|
+
async function reviewManagedSource(rootDir, id) {
|
|
19208
|
+
const scope = await resolveSourceScope(rootDir, id);
|
|
19209
|
+
if (!scope) {
|
|
18654
19210
|
throw new Error(`Managed source or source id not found: ${id}`);
|
|
18655
19211
|
}
|
|
18656
|
-
|
|
18657
|
-
|
|
18658
|
-
|
|
18659
|
-
|
|
18660
|
-
|
|
18661
|
-
|
|
19212
|
+
if (!await loadVaultConfig(rootDir).then(({ paths }) => fileExists(paths.graphPath))) {
|
|
19213
|
+
await compileVault(rootDir, {});
|
|
19214
|
+
}
|
|
19215
|
+
return await stageSourceReviewForScope(rootDir, scope);
|
|
19216
|
+
}
|
|
19217
|
+
async function guideManagedSource(rootDir, id, options = {}) {
|
|
19218
|
+
const scope = await resolveSourceScope(rootDir, id);
|
|
19219
|
+
if (!scope) {
|
|
19220
|
+
throw new Error(`Managed source or source id not found: ${id}`);
|
|
19221
|
+
}
|
|
19222
|
+
if (!await loadVaultConfig(rootDir).then(({ paths }) => fileExists(paths.graphPath))) {
|
|
19223
|
+
await compileVault(rootDir, {});
|
|
19224
|
+
}
|
|
19225
|
+
return await stageSourceGuideForScope(rootDir, scope, options);
|
|
19226
|
+
}
|
|
19227
|
+
async function resumeSourceSession(rootDir, id, options = {}) {
|
|
19228
|
+
const existingSession = await readGuidedSourceSession(rootDir, id);
|
|
19229
|
+
if (existingSession) {
|
|
19230
|
+
return await stageSourceGuideForScope(
|
|
19231
|
+
rootDir,
|
|
19232
|
+
{
|
|
19233
|
+
id: existingSession.scopeId,
|
|
19234
|
+
title: existingSession.scopeTitle,
|
|
19235
|
+
sourceIds: existingSession.sourceIds,
|
|
19236
|
+
kind: existingSession.kind,
|
|
19237
|
+
briefPath: existingSession.briefPath
|
|
19238
|
+
},
|
|
19239
|
+
options
|
|
19240
|
+
);
|
|
19241
|
+
}
|
|
19242
|
+
const scope = await resolveSourceScope(rootDir, id);
|
|
19243
|
+
if (!scope) {
|
|
19244
|
+
throw new Error(`Managed source, source scope, or guided session not found: ${id}`);
|
|
19245
|
+
}
|
|
19246
|
+
return await stageSourceGuideForScope(rootDir, scope, options);
|
|
18662
19247
|
}
|
|
18663
19248
|
function shouldCompile(changedSources, graphExists, compileRequested) {
|
|
18664
19249
|
return compileRequested && (!graphExists || changedSources.length > 0);
|
|
@@ -18677,7 +19262,7 @@ async function addManagedSource(rootDir, input, options = {}) {
|
|
|
18677
19262
|
const existing = sources.find((candidate) => matchesManagedSourceSpec(candidate, resolved));
|
|
18678
19263
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18679
19264
|
const source = existing ?? {
|
|
18680
|
-
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind,
|
|
19265
|
+
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind, path26.resolve(resolved.path), resolved.title) : stableManagedSourceId(resolved.kind, resolved.url, resolved.title),
|
|
18681
19266
|
kind: resolved.kind,
|
|
18682
19267
|
title: resolved.title,
|
|
18683
19268
|
path: resolved.kind === "directory" || resolved.kind === "file" ? resolved.path : void 0,
|
|
@@ -18712,10 +19297,14 @@ async function addManagedSource(rootDir, input, options = {}) {
|
|
|
18712
19297
|
const nextSources = existing ? sources.map((candidate) => candidate.id === nextSource.id ? nextSource : candidate) : [...sources, nextSource];
|
|
18713
19298
|
await saveManagedSources(rootDir, nextSources);
|
|
18714
19299
|
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
|
-
|
|
19300
|
+
const guide = guideRequested && nextSource.status === "ready" ? await stageSourceGuideForScope(
|
|
19301
|
+
rootDir,
|
|
19302
|
+
{
|
|
19303
|
+
...scopeFromManagedSource(nextSource),
|
|
19304
|
+
briefPath: nextSource.briefPath
|
|
19305
|
+
},
|
|
19306
|
+
{ answers: options.guideAnswers }
|
|
19307
|
+
) : void 0;
|
|
18719
19308
|
return {
|
|
18720
19309
|
source: nextSource,
|
|
18721
19310
|
compile,
|
|
@@ -18769,10 +19358,14 @@ async function reloadManagedSources(rootDir, options = {}) {
|
|
|
18769
19358
|
) : [];
|
|
18770
19359
|
const guides = guideRequested ? await Promise.all(
|
|
18771
19360
|
nextSources.filter((source) => selected.some((candidate) => candidate.id === source.id)).filter((source) => source.status === "ready").map(
|
|
18772
|
-
async (source) => await stageSourceGuideForScope(
|
|
18773
|
-
|
|
18774
|
-
|
|
18775
|
-
|
|
19361
|
+
async (source) => await stageSourceGuideForScope(
|
|
19362
|
+
rootDir,
|
|
19363
|
+
{
|
|
19364
|
+
...scopeFromManagedSource(source),
|
|
19365
|
+
briefPath: source.briefPath
|
|
19366
|
+
},
|
|
19367
|
+
{ answers: options.guideAnswers }
|
|
19368
|
+
)
|
|
18776
19369
|
)
|
|
18777
19370
|
) : [];
|
|
18778
19371
|
return {
|
|
@@ -18794,17 +19387,17 @@ async function deleteManagedSource(rootDir, id) {
|
|
|
18794
19387
|
sources.filter((source) => source.id !== id)
|
|
18795
19388
|
);
|
|
18796
19389
|
const workingDir = await managedSourceWorkingDir(rootDir, id);
|
|
18797
|
-
await
|
|
19390
|
+
await fs22.rm(workingDir, { recursive: true, force: true });
|
|
18798
19391
|
return { removed: target };
|
|
18799
19392
|
}
|
|
18800
19393
|
|
|
18801
19394
|
// src/viewer.ts
|
|
18802
19395
|
import { execFile } from "child_process";
|
|
18803
|
-
import
|
|
19396
|
+
import fs23 from "fs/promises";
|
|
18804
19397
|
import http from "http";
|
|
18805
|
-
import
|
|
19398
|
+
import path28 from "path";
|
|
18806
19399
|
import { promisify } from "util";
|
|
18807
|
-
import
|
|
19400
|
+
import matter11 from "gray-matter";
|
|
18808
19401
|
import mime2 from "mime-types";
|
|
18809
19402
|
|
|
18810
19403
|
// src/graph-presentation.ts
|
|
@@ -18926,7 +19519,7 @@ function buildViewerGraphArtifact(graph, options = {}) {
|
|
|
18926
19519
|
}
|
|
18927
19520
|
|
|
18928
19521
|
// src/watch.ts
|
|
18929
|
-
import
|
|
19522
|
+
import path27 from "path";
|
|
18930
19523
|
import process3 from "process";
|
|
18931
19524
|
import chokidar from "chokidar";
|
|
18932
19525
|
var MAX_BACKOFF_MS = 3e4;
|
|
@@ -18934,15 +19527,15 @@ var BACKOFF_THRESHOLD = 3;
|
|
|
18934
19527
|
var CRITICAL_THRESHOLD = 10;
|
|
18935
19528
|
var REPO_WATCH_IGNORES = /* @__PURE__ */ new Set([".git", ".venv"]);
|
|
18936
19529
|
function withinRoot3(rootPath, targetPath) {
|
|
18937
|
-
const relative =
|
|
18938
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
19530
|
+
const relative = path27.relative(rootPath, targetPath);
|
|
19531
|
+
return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
|
|
18939
19532
|
}
|
|
18940
19533
|
function hasIgnoredRepoSegment(baseDir, targetPath) {
|
|
18941
|
-
const relativePath =
|
|
19534
|
+
const relativePath = path27.relative(baseDir, targetPath);
|
|
18942
19535
|
if (!relativePath || relativePath.startsWith("..")) {
|
|
18943
19536
|
return false;
|
|
18944
19537
|
}
|
|
18945
|
-
return relativePath.split(
|
|
19538
|
+
return relativePath.split(path27.sep).some((segment) => REPO_WATCH_IGNORES.has(segment));
|
|
18946
19539
|
}
|
|
18947
19540
|
function workspaceIgnoreRoots(rootDir, paths) {
|
|
18948
19541
|
return [
|
|
@@ -18951,16 +19544,16 @@ function workspaceIgnoreRoots(rootDir, paths) {
|
|
|
18951
19544
|
paths.stateDir,
|
|
18952
19545
|
paths.agentDir,
|
|
18953
19546
|
paths.inboxDir,
|
|
18954
|
-
|
|
18955
|
-
|
|
18956
|
-
|
|
18957
|
-
].map((candidate) =>
|
|
19547
|
+
path27.join(rootDir, ".claude"),
|
|
19548
|
+
path27.join(rootDir, ".cursor"),
|
|
19549
|
+
path27.join(rootDir, ".obsidian")
|
|
19550
|
+
].map((candidate) => path27.resolve(candidate));
|
|
18958
19551
|
}
|
|
18959
19552
|
async function resolveWatchTargets(rootDir, paths, options) {
|
|
18960
|
-
const targets = /* @__PURE__ */ new Set([
|
|
19553
|
+
const targets = /* @__PURE__ */ new Set([path27.resolve(paths.inboxDir)]);
|
|
18961
19554
|
if (options.repo) {
|
|
18962
19555
|
for (const repoRoot of await listTrackedRepoRoots(rootDir)) {
|
|
18963
|
-
targets.add(
|
|
19556
|
+
targets.add(path27.resolve(repoRoot));
|
|
18964
19557
|
}
|
|
18965
19558
|
}
|
|
18966
19559
|
return [...targets].sort((left, right) => left.localeCompare(right));
|
|
@@ -19090,7 +19683,7 @@ async function watchVault(rootDir, options = {}) {
|
|
|
19090
19683
|
const { paths } = await initWorkspace(rootDir);
|
|
19091
19684
|
const baseDebounceMs = options.debounceMs ?? 900;
|
|
19092
19685
|
const ignoredRoots = workspaceIgnoreRoots(rootDir, paths);
|
|
19093
|
-
const inboxWatchRoot =
|
|
19686
|
+
const inboxWatchRoot = path27.resolve(paths.inboxDir);
|
|
19094
19687
|
let watchTargets = await resolveWatchTargets(rootDir, paths, options);
|
|
19095
19688
|
let timer;
|
|
19096
19689
|
let running = false;
|
|
@@ -19105,7 +19698,7 @@ async function watchVault(rootDir, options = {}) {
|
|
|
19105
19698
|
usePolling: true,
|
|
19106
19699
|
interval: 100,
|
|
19107
19700
|
ignored: (targetPath) => {
|
|
19108
|
-
const absolutePath =
|
|
19701
|
+
const absolutePath = path27.resolve(targetPath);
|
|
19109
19702
|
const primaryTarget = watchTargets.filter((watchTarget) => withinRoot3(watchTarget, absolutePath)).sort((left, right) => right.length - left.length)[0] ?? null;
|
|
19110
19703
|
if (!primaryTarget) {
|
|
19111
19704
|
return false;
|
|
@@ -19294,8 +19887,8 @@ async function watchVault(rootDir, options = {}) {
|
|
|
19294
19887
|
}
|
|
19295
19888
|
};
|
|
19296
19889
|
const reasonForPath = (targetPath) => {
|
|
19297
|
-
const baseDir = watchTargets.filter((watchTarget) => withinRoot3(watchTarget,
|
|
19298
|
-
return
|
|
19890
|
+
const baseDir = watchTargets.filter((watchTarget) => withinRoot3(watchTarget, path27.resolve(targetPath))).sort((left, right) => right.length - left.length)[0] ?? paths.inboxDir;
|
|
19891
|
+
return path27.relative(baseDir, targetPath) || ".";
|
|
19299
19892
|
};
|
|
19300
19893
|
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
19894
|
await new Promise((resolve, reject) => {
|
|
@@ -19337,15 +19930,15 @@ async function getWatchStatus(rootDir) {
|
|
|
19337
19930
|
var execFileAsync = promisify(execFile);
|
|
19338
19931
|
async function readViewerPage(rootDir, relativePath) {
|
|
19339
19932
|
const { paths } = await loadVaultConfig(rootDir);
|
|
19340
|
-
const absolutePath =
|
|
19933
|
+
const absolutePath = path28.resolve(paths.wikiDir, relativePath);
|
|
19341
19934
|
if (!absolutePath.startsWith(paths.wikiDir) || !await fileExists(absolutePath)) {
|
|
19342
19935
|
return null;
|
|
19343
19936
|
}
|
|
19344
|
-
const raw = await
|
|
19345
|
-
const parsed =
|
|
19937
|
+
const raw = await fs23.readFile(absolutePath, "utf8");
|
|
19938
|
+
const parsed = matter11(raw);
|
|
19346
19939
|
return {
|
|
19347
19940
|
path: relativePath,
|
|
19348
|
-
title: typeof parsed.data.title === "string" ? parsed.data.title :
|
|
19941
|
+
title: typeof parsed.data.title === "string" ? parsed.data.title : path28.basename(relativePath, path28.extname(relativePath)),
|
|
19349
19942
|
frontmatter: parsed.data,
|
|
19350
19943
|
content: parsed.content,
|
|
19351
19944
|
assets: normalizeOutputAssets(parsed.data.output_assets)
|
|
@@ -19353,12 +19946,12 @@ async function readViewerPage(rootDir, relativePath) {
|
|
|
19353
19946
|
}
|
|
19354
19947
|
async function readViewerAsset(rootDir, relativePath) {
|
|
19355
19948
|
const { paths } = await loadVaultConfig(rootDir);
|
|
19356
|
-
const absolutePath =
|
|
19949
|
+
const absolutePath = path28.resolve(paths.wikiDir, relativePath);
|
|
19357
19950
|
if (!absolutePath.startsWith(paths.wikiDir) || !await fileExists(absolutePath)) {
|
|
19358
19951
|
return null;
|
|
19359
19952
|
}
|
|
19360
19953
|
return {
|
|
19361
|
-
buffer: await
|
|
19954
|
+
buffer: await fs23.readFile(absolutePath),
|
|
19362
19955
|
mimeType: mime2.lookup(absolutePath) || "application/octet-stream"
|
|
19363
19956
|
};
|
|
19364
19957
|
}
|
|
@@ -19381,12 +19974,12 @@ async function readJsonBody(request) {
|
|
|
19381
19974
|
return JSON.parse(raw);
|
|
19382
19975
|
}
|
|
19383
19976
|
async function ensureViewerDist(viewerDistDir) {
|
|
19384
|
-
const indexPath =
|
|
19977
|
+
const indexPath = path28.join(viewerDistDir, "index.html");
|
|
19385
19978
|
if (await fileExists(indexPath)) {
|
|
19386
19979
|
return;
|
|
19387
19980
|
}
|
|
19388
|
-
const viewerProjectDir =
|
|
19389
|
-
if (await fileExists(
|
|
19981
|
+
const viewerProjectDir = path28.dirname(viewerDistDir);
|
|
19982
|
+
if (await fileExists(path28.join(viewerProjectDir, "package.json"))) {
|
|
19390
19983
|
await execFileAsync("pnpm", ["build"], { cwd: viewerProjectDir });
|
|
19391
19984
|
}
|
|
19392
19985
|
}
|
|
@@ -19408,7 +20001,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19408
20001
|
response.end(JSON.stringify({ error: "Graph artifact not found. Run `swarmvault compile` first." }));
|
|
19409
20002
|
return;
|
|
19410
20003
|
}
|
|
19411
|
-
const reportPath =
|
|
20004
|
+
const reportPath = path28.join(paths.wikiDir, "graph", "report.json");
|
|
19412
20005
|
const report = await readJsonFile(reportPath) ?? null;
|
|
19413
20006
|
response.writeHead(200, { "content-type": "application/json" });
|
|
19414
20007
|
response.end(JSON.stringify(buildViewerGraphArtifact(graph, { report, full: options.full ?? false })));
|
|
@@ -19468,14 +20061,14 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19468
20061
|
return;
|
|
19469
20062
|
}
|
|
19470
20063
|
if (url.pathname === "/api/graph-report") {
|
|
19471
|
-
const reportPath =
|
|
20064
|
+
const reportPath = path28.join(paths.wikiDir, "graph", "report.json");
|
|
19472
20065
|
if (!await fileExists(reportPath)) {
|
|
19473
20066
|
response.writeHead(404, { "content-type": "application/json" });
|
|
19474
20067
|
response.end(JSON.stringify({ error: "Graph report artifact not found. Run `swarmvault compile` first." }));
|
|
19475
20068
|
return;
|
|
19476
20069
|
}
|
|
19477
20070
|
response.writeHead(200, { "content-type": "application/json" });
|
|
19478
|
-
response.end(await
|
|
20071
|
+
response.end(await fs23.readFile(reportPath, "utf8"));
|
|
19479
20072
|
return;
|
|
19480
20073
|
}
|
|
19481
20074
|
if (url.pathname === "/api/watch-status") {
|
|
@@ -19558,8 +20151,8 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19558
20151
|
return;
|
|
19559
20152
|
}
|
|
19560
20153
|
const relativePath = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
|
|
19561
|
-
const target =
|
|
19562
|
-
const fallback =
|
|
20154
|
+
const target = path28.join(paths.viewerDistDir, relativePath);
|
|
20155
|
+
const fallback = path28.join(paths.viewerDistDir, "index.html");
|
|
19563
20156
|
const filePath = await fileExists(target) ? target : fallback;
|
|
19564
20157
|
if (!await fileExists(filePath)) {
|
|
19565
20158
|
response.writeHead(503, { "content-type": "text/plain" });
|
|
@@ -19567,7 +20160,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
19567
20160
|
return;
|
|
19568
20161
|
}
|
|
19569
20162
|
response.writeHead(200, { "content-type": mime2.lookup(filePath) || "text/plain" });
|
|
19570
|
-
response.end(await
|
|
20163
|
+
response.end(await fs23.readFile(filePath));
|
|
19571
20164
|
});
|
|
19572
20165
|
await new Promise((resolve) => {
|
|
19573
20166
|
server.listen(effectivePort, resolve);
|
|
@@ -19594,7 +20187,7 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
19594
20187
|
throw new Error("Graph artifact not found. Run `swarmvault compile` first.");
|
|
19595
20188
|
}
|
|
19596
20189
|
await ensureViewerDist(paths.viewerDistDir);
|
|
19597
|
-
const indexPath =
|
|
20190
|
+
const indexPath = path28.join(paths.viewerDistDir, "index.html");
|
|
19598
20191
|
if (!await fileExists(indexPath)) {
|
|
19599
20192
|
throw new Error("Viewer build not found. Run `pnpm build` first.");
|
|
19600
20193
|
}
|
|
@@ -19620,17 +20213,17 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
19620
20213
|
} : null;
|
|
19621
20214
|
})
|
|
19622
20215
|
);
|
|
19623
|
-
const rawHtml = await
|
|
20216
|
+
const rawHtml = await fs23.readFile(indexPath, "utf8");
|
|
19624
20217
|
const scriptMatch = rawHtml.match(/<script type="module" crossorigin src="([^"]+)"><\/script>/);
|
|
19625
20218
|
const styleMatch = rawHtml.match(/<link rel="stylesheet" crossorigin href="([^"]+)">/);
|
|
19626
|
-
const scriptPath = scriptMatch?.[1] ?
|
|
19627
|
-
const stylePath = styleMatch?.[1] ?
|
|
20219
|
+
const scriptPath = scriptMatch?.[1] ? path28.join(paths.viewerDistDir, scriptMatch[1].replace(/^\//, "")) : null;
|
|
20220
|
+
const stylePath = styleMatch?.[1] ? path28.join(paths.viewerDistDir, styleMatch[1].replace(/^\//, "")) : null;
|
|
19628
20221
|
if (!scriptPath || !await fileExists(scriptPath)) {
|
|
19629
20222
|
throw new Error("Viewer script bundle not found. Run `pnpm build` first.");
|
|
19630
20223
|
}
|
|
19631
|
-
const script = await
|
|
19632
|
-
const style = stylePath && await fileExists(stylePath) ? await
|
|
19633
|
-
const report = await readJsonFile(
|
|
20224
|
+
const script = await fs23.readFile(scriptPath, "utf8");
|
|
20225
|
+
const style = stylePath && await fileExists(stylePath) ? await fs23.readFile(stylePath, "utf8") : "";
|
|
20226
|
+
const report = await readJsonFile(path28.join(paths.wikiDir, "graph", "report.json"));
|
|
19634
20227
|
const embeddedData = JSON.stringify(
|
|
19635
20228
|
{ graph: buildViewerGraphArtifact(graph, { report, full: options.full ?? false }), pages: pages.filter(Boolean), report },
|
|
19636
20229
|
null,
|
|
@@ -19653,9 +20246,9 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
19653
20246
|
"</html>",
|
|
19654
20247
|
""
|
|
19655
20248
|
].filter(Boolean).join("\n");
|
|
19656
|
-
await
|
|
19657
|
-
await
|
|
19658
|
-
return
|
|
20249
|
+
await fs23.mkdir(path28.dirname(outputPath), { recursive: true });
|
|
20250
|
+
await fs23.writeFile(outputPath, html, "utf8");
|
|
20251
|
+
return path28.resolve(outputPath);
|
|
19659
20252
|
}
|
|
19660
20253
|
export {
|
|
19661
20254
|
acceptApproval,
|
|
@@ -19717,6 +20310,7 @@ export {
|
|
|
19717
20310
|
rejectApproval,
|
|
19718
20311
|
reloadManagedSources,
|
|
19719
20312
|
resolvePaths,
|
|
20313
|
+
resumeSourceSession,
|
|
19720
20314
|
reviewManagedSource,
|
|
19721
20315
|
reviewSourceScope,
|
|
19722
20316
|
runSchedule,
|