@swarmvaultai/engine 3.5.0 → 3.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/README.md +3 -0
- package/dist/chunk-5GEPTIZE.js +26010 -0
- package/dist/chunk-7O2HJSWQ.js +1686 -0
- package/dist/chunk-V7KX3AQD.js +26010 -0
- package/dist/hooks/claude.js +53 -5
- package/dist/hooks/codex.js +13 -3
- package/dist/hooks/copilot.js +13 -3
- package/dist/hooks/gemini.js +13 -3
- package/dist/index.d.ts +55 -5
- package/dist/index.js +152 -80
- package/dist/memory-FVIBFROA.js +32 -0
- package/dist/memory-HE6VWUPV.js +32 -0
- package/dist/registry-NMXDBYIZ.js +12 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
buildOutputPage,
|
|
24
24
|
buildRedactor,
|
|
25
25
|
buildSchemaPrompt,
|
|
26
|
+
checkTrackedRepoChanges,
|
|
26
27
|
compileVault,
|
|
27
28
|
composeVaultSchema,
|
|
28
29
|
computeDecayScore,
|
|
@@ -91,6 +92,7 @@ import {
|
|
|
91
92
|
readWatchStatusArtifact,
|
|
92
93
|
rebuildRetrievalIndex,
|
|
93
94
|
recordSession,
|
|
95
|
+
refreshGraphClusters,
|
|
94
96
|
refreshVaultAfterOutputSave,
|
|
95
97
|
rejectApproval,
|
|
96
98
|
removeManifestBySourceId,
|
|
@@ -123,9 +125,10 @@ import {
|
|
|
123
125
|
writeGuidedSourceSession,
|
|
124
126
|
writeRetrievalManifest,
|
|
125
127
|
writeWatchStatusArtifact
|
|
126
|
-
} from "./chunk-
|
|
128
|
+
} from "./chunk-5GEPTIZE.js";
|
|
127
129
|
import {
|
|
128
130
|
LocalWhisperProviderAdapter,
|
|
131
|
+
SWARMVAULT_OUT_ENV,
|
|
129
132
|
appendJsonLine,
|
|
130
133
|
assertProviderCapability,
|
|
131
134
|
createProvider,
|
|
@@ -140,6 +143,7 @@ import {
|
|
|
140
143
|
loadVaultConfig,
|
|
141
144
|
normalizeWhitespace,
|
|
142
145
|
readJsonFile,
|
|
146
|
+
resolveArtifactRootDir,
|
|
143
147
|
resolvePaths,
|
|
144
148
|
sha256,
|
|
145
149
|
slugify,
|
|
@@ -147,7 +151,7 @@ import {
|
|
|
147
151
|
truncate,
|
|
148
152
|
uniqueBy,
|
|
149
153
|
writeJsonFile
|
|
150
|
-
} from "./chunk-
|
|
154
|
+
} from "./chunk-7O2HJSWQ.js";
|
|
151
155
|
import {
|
|
152
156
|
estimatePageTokens,
|
|
153
157
|
estimateTokens,
|
|
@@ -3920,27 +3924,78 @@ async function pushGraphNeo4j(rootDir, options = {}) {
|
|
|
3920
3924
|
}
|
|
3921
3925
|
}
|
|
3922
3926
|
|
|
3927
|
+
// src/graph-status.ts
|
|
3928
|
+
import path6 from "path";
|
|
3929
|
+
function recommendedCommand(input) {
|
|
3930
|
+
if (!input.graphExists || !input.reportExists) {
|
|
3931
|
+
return "swarmvault compile";
|
|
3932
|
+
}
|
|
3933
|
+
if (input.semanticChangeCount > 0 || input.pendingSemanticRefreshCount > 0) {
|
|
3934
|
+
return "swarmvault compile";
|
|
3935
|
+
}
|
|
3936
|
+
if (input.codeChangeCount > 0) {
|
|
3937
|
+
return "swarmvault graph update";
|
|
3938
|
+
}
|
|
3939
|
+
return null;
|
|
3940
|
+
}
|
|
3941
|
+
async function getGraphStatus(rootDir, options = {}) {
|
|
3942
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
3943
|
+
const graphPath = paths.graphPath;
|
|
3944
|
+
const reportPath = path6.join(paths.wikiDir, "graph", "report.md");
|
|
3945
|
+
const resolvedOverrideRoots = options.repoRoots?.map((repoRoot) => path6.resolve(rootDir, repoRoot));
|
|
3946
|
+
const [graphExists, reportExists, trackedRepoRoots, changes, pendingSemanticRefresh] = await Promise.all([
|
|
3947
|
+
fileExists(graphPath),
|
|
3948
|
+
fileExists(reportPath),
|
|
3949
|
+
resolvedOverrideRoots ? Promise.resolve([...new Set(resolvedOverrideRoots)].sort((left, right) => left.localeCompare(right))) : listTrackedRepoRoots(rootDir),
|
|
3950
|
+
checkTrackedRepoChanges(rootDir, resolvedOverrideRoots),
|
|
3951
|
+
readJsonFile(paths.pendingSemanticRefreshPath).then((entries) => Array.isArray(entries) ? entries : [])
|
|
3952
|
+
]);
|
|
3953
|
+
const codeChangeCount = changes.filter((change) => change.refreshType === "code").length;
|
|
3954
|
+
const semanticChangeCount = changes.filter((change) => change.refreshType === "semantic").length;
|
|
3955
|
+
const command = recommendedCommand({
|
|
3956
|
+
graphExists,
|
|
3957
|
+
reportExists,
|
|
3958
|
+
codeChangeCount,
|
|
3959
|
+
semanticChangeCount,
|
|
3960
|
+
pendingSemanticRefreshCount: pendingSemanticRefresh.length
|
|
3961
|
+
});
|
|
3962
|
+
return {
|
|
3963
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3964
|
+
graphExists,
|
|
3965
|
+
graphPath,
|
|
3966
|
+
reportExists,
|
|
3967
|
+
reportPath,
|
|
3968
|
+
trackedRepoRoots,
|
|
3969
|
+
codeChangeCount,
|
|
3970
|
+
semanticChangeCount,
|
|
3971
|
+
pendingSemanticRefresh,
|
|
3972
|
+
stale: Boolean(command),
|
|
3973
|
+
recommendedCommand: command,
|
|
3974
|
+
changes
|
|
3975
|
+
};
|
|
3976
|
+
}
|
|
3977
|
+
|
|
3923
3978
|
// src/hooks.ts
|
|
3924
3979
|
import fs6 from "fs/promises";
|
|
3925
|
-
import
|
|
3980
|
+
import path7 from "path";
|
|
3926
3981
|
import process3 from "process";
|
|
3927
3982
|
var hookStart = "# >>> swarmvault hook >>>";
|
|
3928
3983
|
var hookEnd = "# <<< swarmvault hook <<<";
|
|
3929
3984
|
async function findNearestGitRoot(startPath) {
|
|
3930
|
-
let current =
|
|
3985
|
+
let current = path7.resolve(startPath);
|
|
3931
3986
|
try {
|
|
3932
3987
|
const stat = await fs6.stat(current);
|
|
3933
3988
|
if (!stat.isDirectory()) {
|
|
3934
|
-
current =
|
|
3989
|
+
current = path7.dirname(current);
|
|
3935
3990
|
}
|
|
3936
3991
|
} catch {
|
|
3937
|
-
current =
|
|
3992
|
+
current = path7.dirname(current);
|
|
3938
3993
|
}
|
|
3939
3994
|
while (true) {
|
|
3940
|
-
if (await fileExists(
|
|
3995
|
+
if (await fileExists(path7.join(current, ".git"))) {
|
|
3941
3996
|
return current;
|
|
3942
3997
|
}
|
|
3943
|
-
const parent =
|
|
3998
|
+
const parent = path7.dirname(current);
|
|
3944
3999
|
if (parent === current) {
|
|
3945
4000
|
return null;
|
|
3946
4001
|
}
|
|
@@ -3952,8 +4007,8 @@ function shellQuote(value) {
|
|
|
3952
4007
|
}
|
|
3953
4008
|
function resolveSwarmvaultExecutableCandidate() {
|
|
3954
4009
|
const argvPath = process3.argv[1];
|
|
3955
|
-
if (typeof argvPath === "string" && argvPath.trim() && (argvPath.includes(`${
|
|
3956
|
-
return
|
|
4010
|
+
if (typeof argvPath === "string" && argvPath.trim() && (argvPath.includes(`${path7.sep}@swarmvaultai${path7.sep}cli${path7.sep}`) || argvPath.includes(`${path7.sep}packages${path7.sep}cli${path7.sep}`))) {
|
|
4011
|
+
return path7.resolve(argvPath);
|
|
3957
4012
|
}
|
|
3958
4013
|
return "swarmvault";
|
|
3959
4014
|
}
|
|
@@ -3972,7 +4027,7 @@ function managedHookBlock(vaultRoot) {
|
|
|
3972
4027
|
].join("\n");
|
|
3973
4028
|
}
|
|
3974
4029
|
function hookPath(repoRoot, hookName) {
|
|
3975
|
-
return
|
|
4030
|
+
return path7.join(repoRoot, ".git", "hooks", hookName);
|
|
3976
4031
|
}
|
|
3977
4032
|
async function readHookStatus(filePath) {
|
|
3978
4033
|
if (!await fileExists(filePath)) {
|
|
@@ -3996,7 +4051,7 @@ ${block}`.trimEnd();
|
|
|
3996
4051
|
next = `#!/bin/sh
|
|
3997
4052
|
${block}`.trimEnd();
|
|
3998
4053
|
}
|
|
3999
|
-
await ensureDir(
|
|
4054
|
+
await ensureDir(path7.dirname(filePath));
|
|
4000
4055
|
await fs6.writeFile(filePath, `${next}
|
|
4001
4056
|
`, { mode: 493, encoding: "utf8" });
|
|
4002
4057
|
await fs6.chmod(filePath, 493);
|
|
@@ -4039,7 +4094,7 @@ async function installGitHooks(rootDir) {
|
|
|
4039
4094
|
if (!repoRoot) {
|
|
4040
4095
|
throw new Error("No git repository found above the current vault.");
|
|
4041
4096
|
}
|
|
4042
|
-
const block = managedHookBlock(
|
|
4097
|
+
const block = managedHookBlock(path7.resolve(rootDir));
|
|
4043
4098
|
await upsertHookFile(hookPath(repoRoot, "post-commit"), block);
|
|
4044
4099
|
await upsertHookFile(hookPath(repoRoot, "post-checkout"), block);
|
|
4045
4100
|
return getGitHookStatus(rootDir);
|
|
@@ -4060,11 +4115,11 @@ async function uninstallGitHooks(rootDir) {
|
|
|
4060
4115
|
|
|
4061
4116
|
// src/mcp.ts
|
|
4062
4117
|
import fs7 from "fs/promises";
|
|
4063
|
-
import
|
|
4118
|
+
import path8 from "path";
|
|
4064
4119
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4065
4120
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4066
4121
|
import { z } from "zod";
|
|
4067
|
-
var SERVER_VERSION = "3.
|
|
4122
|
+
var SERVER_VERSION = "3.6.0";
|
|
4068
4123
|
async function createMcpServer(rootDir) {
|
|
4069
4124
|
const server = new McpServer({
|
|
4070
4125
|
name: "swarmvault",
|
|
@@ -4202,6 +4257,18 @@ async function createMcpServer(rootDir) {
|
|
|
4202
4257
|
return asToolText(await graphStatsVault(rootDir));
|
|
4203
4258
|
})
|
|
4204
4259
|
);
|
|
4260
|
+
server.registerTool(
|
|
4261
|
+
"cluster_graph",
|
|
4262
|
+
{
|
|
4263
|
+
description: "Recompute graph communities, node degrees, god-node flags, and graph report artifacts from the existing compiled graph.",
|
|
4264
|
+
inputSchema: {
|
|
4265
|
+
resolution: z.number().positive().optional().describe("Optional Louvain community resolution override")
|
|
4266
|
+
}
|
|
4267
|
+
},
|
|
4268
|
+
safeHandler(async ({ resolution }) => {
|
|
4269
|
+
return asToolText(await refreshGraphClusters(rootDir, { resolution }));
|
|
4270
|
+
})
|
|
4271
|
+
);
|
|
4205
4272
|
server.registerTool(
|
|
4206
4273
|
"get_node",
|
|
4207
4274
|
{
|
|
@@ -4760,7 +4827,7 @@ async function createMcpServer(rootDir) {
|
|
|
4760
4827
|
},
|
|
4761
4828
|
async () => {
|
|
4762
4829
|
const { paths } = await loadVaultConfig(rootDir);
|
|
4763
|
-
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(
|
|
4830
|
+
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path8.relative(paths.sessionsDir, filePath))).sort();
|
|
4764
4831
|
return asTextResource("swarmvault://sessions", JSON.stringify(files, null, 2));
|
|
4765
4832
|
}
|
|
4766
4833
|
);
|
|
@@ -4829,7 +4896,7 @@ async function createMcpServer(rootDir) {
|
|
|
4829
4896
|
return asTextResource(`swarmvault://pages/${encodedPath}`, `Page not found: ${relativePath}`);
|
|
4830
4897
|
}
|
|
4831
4898
|
const { paths } = await loadVaultConfig(rootDir);
|
|
4832
|
-
const absolutePath =
|
|
4899
|
+
const absolutePath = path8.resolve(paths.wikiDir, relativePath);
|
|
4833
4900
|
return asTextResource(`swarmvault://pages/${encodedPath}`, await fs7.readFile(absolutePath, "utf8"));
|
|
4834
4901
|
}
|
|
4835
4902
|
);
|
|
@@ -4838,11 +4905,11 @@ async function createMcpServer(rootDir) {
|
|
|
4838
4905
|
new ResourceTemplate("swarmvault://sessions/{path}", {
|
|
4839
4906
|
list: async () => {
|
|
4840
4907
|
const { paths } = await loadVaultConfig(rootDir);
|
|
4841
|
-
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(
|
|
4908
|
+
const files = (await listFilesRecursive(paths.sessionsDir)).filter((filePath) => filePath.endsWith(".md")).map((filePath) => toPosix(path8.relative(paths.sessionsDir, filePath))).sort();
|
|
4842
4909
|
return {
|
|
4843
4910
|
resources: files.map((relativePath) => ({
|
|
4844
4911
|
uri: `swarmvault://sessions/${encodeURIComponent(relativePath)}`,
|
|
4845
|
-
name:
|
|
4912
|
+
name: path8.basename(relativePath, ".md"),
|
|
4846
4913
|
title: relativePath,
|
|
4847
4914
|
description: "SwarmVault session artifact",
|
|
4848
4915
|
mimeType: "text/markdown"
|
|
@@ -4859,7 +4926,7 @@ async function createMcpServer(rootDir) {
|
|
|
4859
4926
|
const { paths } = await loadVaultConfig(rootDir);
|
|
4860
4927
|
const encodedPath = typeof variables.path === "string" ? variables.path : "";
|
|
4861
4928
|
const relativePath = decodeURIComponent(encodedPath);
|
|
4862
|
-
const absolutePath =
|
|
4929
|
+
const absolutePath = path8.resolve(paths.sessionsDir, relativePath);
|
|
4863
4930
|
if (!isPathWithin(paths.sessionsDir, absolutePath) || !await fileExists(absolutePath)) {
|
|
4864
4931
|
return asTextResource(`swarmvault://sessions/${encodedPath}`, `Session not found: ${relativePath}`);
|
|
4865
4932
|
}
|
|
@@ -4925,7 +4992,7 @@ function asTextResource(uri, text) {
|
|
|
4925
4992
|
import { createWriteStream, constants as fsConstants } from "fs";
|
|
4926
4993
|
import fs8 from "fs/promises";
|
|
4927
4994
|
import os from "os";
|
|
4928
|
-
import
|
|
4995
|
+
import path9 from "path";
|
|
4929
4996
|
import { Readable } from "stream";
|
|
4930
4997
|
import { pipeline } from "stream/promises";
|
|
4931
4998
|
var BINARY_CANDIDATES = ["whisper-cli", "whisper-cpp", "whisper"];
|
|
@@ -4953,10 +5020,10 @@ async function discoverLocalWhisperBinary(options = {}) {
|
|
|
4953
5020
|
}
|
|
4954
5021
|
const pathValue = env.PATH ?? "";
|
|
4955
5022
|
const candidates = [];
|
|
4956
|
-
for (const dir of pathValue.split(
|
|
5023
|
+
for (const dir of pathValue.split(path9.delimiter)) {
|
|
4957
5024
|
if (!dir) continue;
|
|
4958
5025
|
for (const name of BINARY_CANDIDATES) {
|
|
4959
|
-
const full =
|
|
5026
|
+
const full = path9.join(dir, name);
|
|
4960
5027
|
candidates.push(full);
|
|
4961
5028
|
if (await isExecutable(full)) {
|
|
4962
5029
|
return { binaryPath: full, candidates, source: "path" };
|
|
@@ -4967,14 +5034,14 @@ async function discoverLocalWhisperBinary(options = {}) {
|
|
|
4967
5034
|
}
|
|
4968
5035
|
function expectedModelPath(modelName, homeDir) {
|
|
4969
5036
|
const home = homeDir ?? os.homedir();
|
|
4970
|
-
return
|
|
5037
|
+
return path9.join(home, ".swarmvault", "models", `ggml-${modelName}.bin`);
|
|
4971
5038
|
}
|
|
4972
5039
|
function modelDownloadUrl(modelName) {
|
|
4973
5040
|
return `${HUGGINGFACE_BASE}/ggml-${modelName}.bin`;
|
|
4974
5041
|
}
|
|
4975
5042
|
async function downloadWhisperModel(options) {
|
|
4976
5043
|
const destPath = expectedModelPath(options.modelName, options.homeDir);
|
|
4977
|
-
await ensureDir(
|
|
5044
|
+
await ensureDir(path9.dirname(destPath));
|
|
4978
5045
|
const doFetch = options.fetchImpl ?? fetch;
|
|
4979
5046
|
const url = modelDownloadUrl(options.modelName);
|
|
4980
5047
|
const response = await doFetch(url);
|
|
@@ -5134,12 +5201,12 @@ async function withCapabilityFallback(provider, capability, run, fallback) {
|
|
|
5134
5201
|
|
|
5135
5202
|
// src/schedule.ts
|
|
5136
5203
|
import fs9 from "fs/promises";
|
|
5137
|
-
import
|
|
5204
|
+
import path10 from "path";
|
|
5138
5205
|
function scheduleStatePath(schedulesDir, jobId) {
|
|
5139
|
-
return
|
|
5206
|
+
return path10.join(schedulesDir, `${encodeURIComponent(jobId)}.json`);
|
|
5140
5207
|
}
|
|
5141
5208
|
function scheduleLockPath(schedulesDir, jobId) {
|
|
5142
|
-
return
|
|
5209
|
+
return path10.join(schedulesDir, `${encodeURIComponent(jobId)}.lock`);
|
|
5143
5210
|
}
|
|
5144
5211
|
function parseEveryDuration(value) {
|
|
5145
5212
|
const match = value.trim().match(/^(\d+)(m|h|d)$/i);
|
|
@@ -5408,7 +5475,7 @@ async function serveSchedules(rootDir, pollMs = 3e4) {
|
|
|
5408
5475
|
// src/sources.ts
|
|
5409
5476
|
import { spawn } from "child_process";
|
|
5410
5477
|
import fs10 from "fs/promises";
|
|
5411
|
-
import
|
|
5478
|
+
import path11 from "path";
|
|
5412
5479
|
import matter3 from "gray-matter";
|
|
5413
5480
|
import { JSDOM } from "jsdom";
|
|
5414
5481
|
var DEFAULT_CRAWL_MAX_PAGES = 12;
|
|
@@ -5454,24 +5521,24 @@ function emptyManagedSourceSyncCounts() {
|
|
|
5454
5521
|
};
|
|
5455
5522
|
}
|
|
5456
5523
|
function withinRoot(rootPath, targetPath) {
|
|
5457
|
-
const relative =
|
|
5458
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
5524
|
+
const relative = path11.relative(rootPath, targetPath);
|
|
5525
|
+
return relative === "" || !relative.startsWith("..") && !path11.isAbsolute(relative);
|
|
5459
5526
|
}
|
|
5460
5527
|
async function findNearestGitRoot2(startPath) {
|
|
5461
|
-
let current =
|
|
5528
|
+
let current = path11.resolve(startPath);
|
|
5462
5529
|
try {
|
|
5463
5530
|
const stat = await fs10.stat(current);
|
|
5464
5531
|
if (!stat.isDirectory()) {
|
|
5465
|
-
current =
|
|
5532
|
+
current = path11.dirname(current);
|
|
5466
5533
|
}
|
|
5467
5534
|
} catch {
|
|
5468
|
-
current =
|
|
5535
|
+
current = path11.dirname(current);
|
|
5469
5536
|
}
|
|
5470
5537
|
while (true) {
|
|
5471
|
-
if (await fileExists(
|
|
5538
|
+
if (await fileExists(path11.join(current, ".git"))) {
|
|
5472
5539
|
return current;
|
|
5473
5540
|
}
|
|
5474
|
-
const parent =
|
|
5541
|
+
const parent = path11.dirname(current);
|
|
5475
5542
|
if (parent === current) {
|
|
5476
5543
|
return null;
|
|
5477
5544
|
}
|
|
@@ -5545,7 +5612,7 @@ function isAllowedDocsCandidate(candidate, startUrl) {
|
|
|
5545
5612
|
if (candidate.origin !== startUrl.origin) {
|
|
5546
5613
|
return false;
|
|
5547
5614
|
}
|
|
5548
|
-
const extension =
|
|
5615
|
+
const extension = path11.extname(candidate.pathname).toLowerCase();
|
|
5549
5616
|
if (extension && extension !== ".html" && extension !== ".htm" && extension !== ".md") {
|
|
5550
5617
|
return false;
|
|
5551
5618
|
}
|
|
@@ -5634,12 +5701,12 @@ function matchesManagedSourceSpec(existing, input) {
|
|
|
5634
5701
|
return false;
|
|
5635
5702
|
}
|
|
5636
5703
|
if (input.kind === "directory" || input.kind === "file") {
|
|
5637
|
-
return
|
|
5704
|
+
return path11.resolve(existing.path ?? "") === path11.resolve(input.path);
|
|
5638
5705
|
}
|
|
5639
5706
|
return (existing.url ?? "") === input.url;
|
|
5640
5707
|
}
|
|
5641
5708
|
async function resolveManagedSourceInput(rootDir, input) {
|
|
5642
|
-
const absoluteInput =
|
|
5709
|
+
const absoluteInput = path11.resolve(rootDir, input);
|
|
5643
5710
|
if (!(input.startsWith("http://") || input.startsWith("https://"))) {
|
|
5644
5711
|
const stat = await fs10.stat(absoluteInput).catch(() => null);
|
|
5645
5712
|
if (!stat) {
|
|
@@ -5649,7 +5716,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
5649
5716
|
return {
|
|
5650
5717
|
kind: "file",
|
|
5651
5718
|
path: absoluteInput,
|
|
5652
|
-
title:
|
|
5719
|
+
title: path11.basename(absoluteInput, path11.extname(absoluteInput)) || absoluteInput
|
|
5653
5720
|
};
|
|
5654
5721
|
}
|
|
5655
5722
|
if (!stat.isDirectory()) {
|
|
@@ -5661,7 +5728,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
5661
5728
|
kind: "directory",
|
|
5662
5729
|
path: absoluteInput,
|
|
5663
5730
|
repoRoot,
|
|
5664
|
-
title:
|
|
5731
|
+
title: path11.basename(absoluteInput) || absoluteInput
|
|
5665
5732
|
};
|
|
5666
5733
|
}
|
|
5667
5734
|
const github = normalizeGitHubRepoRootUrl(input);
|
|
@@ -5684,16 +5751,16 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
5684
5751
|
};
|
|
5685
5752
|
}
|
|
5686
5753
|
function directorySourceIdsFor(manifests, inputPath) {
|
|
5687
|
-
return manifests.filter((manifest) => manifest.originalPath && withinRoot(
|
|
5754
|
+
return manifests.filter((manifest) => manifest.originalPath && withinRoot(path11.resolve(inputPath), path11.resolve(manifest.originalPath))).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
|
|
5688
5755
|
}
|
|
5689
5756
|
function fileSourceIdsFor(manifests, inputPath) {
|
|
5690
|
-
const absoluteInput =
|
|
5691
|
-
return manifests.filter((manifest) => manifest.originalPath &&
|
|
5757
|
+
const absoluteInput = path11.resolve(inputPath);
|
|
5758
|
+
return manifests.filter((manifest) => manifest.originalPath && path11.resolve(manifest.originalPath) === absoluteInput).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
|
|
5692
5759
|
}
|
|
5693
5760
|
async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
5694
5761
|
const manifestsBefore = await listManifests(rootDir);
|
|
5695
5762
|
const previousInScope = manifestsBefore.filter(
|
|
5696
|
-
(manifest) => manifest.originalPath && withinRoot(
|
|
5763
|
+
(manifest) => manifest.originalPath && withinRoot(path11.resolve(inputPath), path11.resolve(manifest.originalPath))
|
|
5697
5764
|
);
|
|
5698
5765
|
const result = await ingestDirectory(rootDir, inputPath, { repoRoot });
|
|
5699
5766
|
const removed = [];
|
|
@@ -5701,7 +5768,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
5701
5768
|
if (!manifest.originalPath) {
|
|
5702
5769
|
continue;
|
|
5703
5770
|
}
|
|
5704
|
-
if (await fileExists(
|
|
5771
|
+
if (await fileExists(path11.resolve(manifest.originalPath))) {
|
|
5705
5772
|
continue;
|
|
5706
5773
|
}
|
|
5707
5774
|
const removedManifest = await removeManifestBySourceId(rootDir, manifest.sourceId);
|
|
@@ -5711,7 +5778,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
5711
5778
|
}
|
|
5712
5779
|
const manifestsAfter = await listManifests(rootDir);
|
|
5713
5780
|
return {
|
|
5714
|
-
title:
|
|
5781
|
+
title: path11.basename(inputPath) || inputPath,
|
|
5715
5782
|
sourceIds: directorySourceIdsFor(manifestsAfter, inputPath),
|
|
5716
5783
|
counts: {
|
|
5717
5784
|
scannedCount: result.scannedCount,
|
|
@@ -5727,7 +5794,7 @@ async function syncFileSource(rootDir, inputPath) {
|
|
|
5727
5794
|
const result = await ingestInputDetailed(rootDir, inputPath);
|
|
5728
5795
|
const manifestsAfter = await listManifests(rootDir);
|
|
5729
5796
|
return {
|
|
5730
|
-
title:
|
|
5797
|
+
title: path11.basename(inputPath, path11.extname(inputPath)) || inputPath,
|
|
5731
5798
|
sourceIds: fileSourceIdsFor(manifestsAfter, inputPath),
|
|
5732
5799
|
counts: {
|
|
5733
5800
|
scannedCount: result.scannedCount,
|
|
@@ -5761,7 +5828,7 @@ async function runGitCommand(cwd, args) {
|
|
|
5761
5828
|
}
|
|
5762
5829
|
async function syncGitHubRepoSource(rootDir, entry) {
|
|
5763
5830
|
const workingDir = await managedSourceWorkingDir(rootDir, entry.id);
|
|
5764
|
-
const checkoutDir =
|
|
5831
|
+
const checkoutDir = path11.join(workingDir, "checkout");
|
|
5765
5832
|
await fs10.rm(checkoutDir, { recursive: true, force: true });
|
|
5766
5833
|
await ensureDir(workingDir);
|
|
5767
5834
|
if (!entry.url) {
|
|
@@ -5892,7 +5959,7 @@ function scopedNodeIds(graph, sourceIds) {
|
|
|
5892
5959
|
async function loadSourceAnalyses(rootDir, sourceIds) {
|
|
5893
5960
|
const { paths } = await loadVaultConfig(rootDir);
|
|
5894
5961
|
const analyses = await Promise.all(
|
|
5895
|
-
sourceIds.map(async (sourceId) => await readJsonFile(
|
|
5962
|
+
sourceIds.map(async (sourceId) => await readJsonFile(path11.join(paths.analysesDir, `${sourceId}.json`)))
|
|
5896
5963
|
);
|
|
5897
5964
|
return analyses.filter((analysis) => Boolean(analysis?.sourceId));
|
|
5898
5965
|
}
|
|
@@ -6053,8 +6120,8 @@ async function writeSourceBriefForScope(rootDir, source) {
|
|
|
6053
6120
|
confidence: 0.82
|
|
6054
6121
|
}
|
|
6055
6122
|
});
|
|
6056
|
-
const absolutePath =
|
|
6057
|
-
await ensureDir(
|
|
6123
|
+
const absolutePath = path11.join(paths.wikiDir, output.page.path);
|
|
6124
|
+
await ensureDir(path11.dirname(absolutePath));
|
|
6058
6125
|
await fs10.writeFile(absolutePath, output.content, "utf8");
|
|
6059
6126
|
return absolutePath;
|
|
6060
6127
|
}
|
|
@@ -6343,7 +6410,7 @@ function selectGuidedTargetPages(scope, sourcePages, questions) {
|
|
|
6343
6410
|
return (matchedTargets.length ? matchedTargets : canonicalPages).slice(0, 6);
|
|
6344
6411
|
}
|
|
6345
6412
|
function insightRelativePathForTarget(page, scope) {
|
|
6346
|
-
const basename =
|
|
6413
|
+
const basename = path11.basename(page.path);
|
|
6347
6414
|
if (page.kind === "concept") {
|
|
6348
6415
|
return `insights/concepts/${basename}`;
|
|
6349
6416
|
}
|
|
@@ -6570,7 +6637,7 @@ async function stageSourceReviewForScope(rootDir, scope) {
|
|
|
6570
6637
|
return {
|
|
6571
6638
|
sourceId: scope.id,
|
|
6572
6639
|
pageId: output.page.id,
|
|
6573
|
-
reviewPath:
|
|
6640
|
+
reviewPath: path11.join(approval.approvalDir, "wiki", output.page.path),
|
|
6574
6641
|
staged: true,
|
|
6575
6642
|
approvalId: approval.approvalId,
|
|
6576
6643
|
approvalDir: approval.approvalDir
|
|
@@ -6637,7 +6704,7 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
|
6637
6704
|
const evidenceState = contradictions.length > 0 ? "conflicting" : session.targetedPagePaths.some(
|
|
6638
6705
|
(targetPath) => sourcePages.some((page) => page.path === targetPath && page.sourceIds.some((sourceId) => !scope.sourceIds.includes(sourceId)))
|
|
6639
6706
|
) ? "reinforcing" : session.targetedPagePaths.length ? "new" : "needs_judgment";
|
|
6640
|
-
const relativeBriefPath = session.briefPath &&
|
|
6707
|
+
const relativeBriefPath = session.briefPath && path11.isAbsolute(session.briefPath) ? path11.relative(paths.wikiDir, session.briefPath) : session.briefPath;
|
|
6641
6708
|
const sessionMarkdown = [
|
|
6642
6709
|
`# Guided Session: ${scope.title}`,
|
|
6643
6710
|
"",
|
|
@@ -6720,8 +6787,8 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
|
6720
6787
|
async function persistSourceSessionPage(rootDir, scope, session) {
|
|
6721
6788
|
const { paths } = await loadVaultConfig(rootDir);
|
|
6722
6789
|
const output = await buildSourceSessionSavedPage(rootDir, scope, session);
|
|
6723
|
-
const absolutePath =
|
|
6724
|
-
await ensureDir(
|
|
6790
|
+
const absolutePath = path11.join(paths.wikiDir, output.page.path);
|
|
6791
|
+
await ensureDir(path11.dirname(absolutePath));
|
|
6725
6792
|
await fs10.writeFile(absolutePath, output.content, "utf8");
|
|
6726
6793
|
return { pageId: output.page.id, sessionPath: absolutePath };
|
|
6727
6794
|
}
|
|
@@ -6750,7 +6817,7 @@ async function buildGuidedUpdatePages(rootDir, scope, session) {
|
|
|
6750
6817
|
targetPages.map(async (targetPage) => {
|
|
6751
6818
|
const evidenceState = classifyGuidedEvidenceState(scope, targetPage, contradictions);
|
|
6752
6819
|
const relativePath = useCanonicalTargets && targetPage ? targetPage.path : targetPage ? insightRelativePathForTarget(targetPage, scope) : `insights/topics/${slugify(scope.title)}.md`;
|
|
6753
|
-
const absolutePath =
|
|
6820
|
+
const absolutePath = path11.join(paths.wikiDir, relativePath);
|
|
6754
6821
|
const existingContent = await fileExists(absolutePath) ? await fs10.readFile(absolutePath, "utf8") : "";
|
|
6755
6822
|
const parsed = existingContent ? matter3(existingContent) : { data: {}, content: "" };
|
|
6756
6823
|
const existingData = parsed.data;
|
|
@@ -6922,8 +6989,8 @@ async function stageSourceGuideForScope(rootDir, scope, options = {}) {
|
|
|
6922
6989
|
}
|
|
6923
6990
|
);
|
|
6924
6991
|
session.status = "staged";
|
|
6925
|
-
session.reviewPath =
|
|
6926
|
-
session.guidePath =
|
|
6992
|
+
session.reviewPath = path11.join(approval.approvalDir, "wiki", reviewOutput.page.path);
|
|
6993
|
+
session.guidePath = path11.join(approval.approvalDir, "wiki", guideOutput.page.path);
|
|
6927
6994
|
session.approvalId = approval.approvalId;
|
|
6928
6995
|
session.approvalDir = approval.approvalDir;
|
|
6929
6996
|
const persisted = await persistSourceSessionPage(rootDir, scope, session);
|
|
@@ -7061,7 +7128,7 @@ async function addManagedSource(rootDir, input, options = {}) {
|
|
|
7061
7128
|
const existing = sources.find((candidate) => matchesManagedSourceSpec(candidate, resolved));
|
|
7062
7129
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7063
7130
|
const source = existing ?? {
|
|
7064
|
-
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind,
|
|
7131
|
+
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind, path11.resolve(resolved.path), resolved.title) : stableManagedSourceId(resolved.kind, resolved.url, resolved.title),
|
|
7065
7132
|
kind: resolved.kind,
|
|
7066
7133
|
title: resolved.title,
|
|
7067
7134
|
path: resolved.kind === "directory" || resolved.kind === "file" ? resolved.path : void 0,
|
|
@@ -7199,7 +7266,7 @@ import { randomUUID } from "crypto";
|
|
|
7199
7266
|
import { EventEmitter } from "events";
|
|
7200
7267
|
import fs11 from "fs/promises";
|
|
7201
7268
|
import http from "http";
|
|
7202
|
-
import
|
|
7269
|
+
import path12 from "path";
|
|
7203
7270
|
import { promisify as promisify2 } from "util";
|
|
7204
7271
|
import matter4 from "gray-matter";
|
|
7205
7272
|
import mime from "mime-types";
|
|
@@ -7364,7 +7431,7 @@ async function readViewerPage(rootDir, relativePath) {
|
|
|
7364
7431
|
return null;
|
|
7365
7432
|
}
|
|
7366
7433
|
const { paths } = await loadVaultConfig(rootDir);
|
|
7367
|
-
const absolutePath =
|
|
7434
|
+
const absolutePath = path12.resolve(paths.wikiDir, relativePath);
|
|
7368
7435
|
if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
|
|
7369
7436
|
return null;
|
|
7370
7437
|
}
|
|
@@ -7372,7 +7439,7 @@ async function readViewerPage(rootDir, relativePath) {
|
|
|
7372
7439
|
const parsed = matter4(raw);
|
|
7373
7440
|
return {
|
|
7374
7441
|
path: relativePath,
|
|
7375
|
-
title: typeof parsed.data.title === "string" ? parsed.data.title :
|
|
7442
|
+
title: typeof parsed.data.title === "string" ? parsed.data.title : path12.basename(relativePath, path12.extname(relativePath)),
|
|
7376
7443
|
frontmatter: parsed.data,
|
|
7377
7444
|
content: parsed.content,
|
|
7378
7445
|
assets: normalizeOutputAssets(parsed.data.output_assets)
|
|
@@ -7383,7 +7450,7 @@ async function readViewerAsset(rootDir, relativePath) {
|
|
|
7383
7450
|
return null;
|
|
7384
7451
|
}
|
|
7385
7452
|
const { paths } = await loadVaultConfig(rootDir);
|
|
7386
|
-
const absolutePath =
|
|
7453
|
+
const absolutePath = path12.resolve(paths.wikiDir, relativePath);
|
|
7387
7454
|
if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
|
|
7388
7455
|
return null;
|
|
7389
7456
|
}
|
|
@@ -7424,7 +7491,7 @@ async function writeInboxClip(rootDir, body) {
|
|
|
7424
7491
|
const tags = Array.isArray(body.tags) ? body.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0) : [];
|
|
7425
7492
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7426
7493
|
const fileName = `${now.replace(/[:.]/g, "-")}-${slugForClip(title)}.md`;
|
|
7427
|
-
const inboxPath =
|
|
7494
|
+
const inboxPath = path12.join(paths.inboxDir, fileName);
|
|
7428
7495
|
await fs11.mkdir(paths.inboxDir, { recursive: true });
|
|
7429
7496
|
const lines = [
|
|
7430
7497
|
"---",
|
|
@@ -7447,12 +7514,12 @@ async function writeInboxClip(rootDir, body) {
|
|
|
7447
7514
|
return { mode: "inbox", inboxPath, result };
|
|
7448
7515
|
}
|
|
7449
7516
|
async function ensureViewerDist(viewerDistDir) {
|
|
7450
|
-
const indexPath =
|
|
7517
|
+
const indexPath = path12.join(viewerDistDir, "index.html");
|
|
7451
7518
|
if (await fileExists(indexPath)) {
|
|
7452
7519
|
return;
|
|
7453
7520
|
}
|
|
7454
|
-
const viewerProjectDir =
|
|
7455
|
-
if (await fileExists(
|
|
7521
|
+
const viewerProjectDir = path12.dirname(viewerDistDir);
|
|
7522
|
+
if (await fileExists(path12.join(viewerProjectDir, "package.json"))) {
|
|
7456
7523
|
await execFileAsync2("pnpm", ["build"], { cwd: viewerProjectDir });
|
|
7457
7524
|
}
|
|
7458
7525
|
}
|
|
@@ -7475,7 +7542,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
7475
7542
|
response.end(JSON.stringify({ error: "Graph artifact not found. Run `swarmvault compile` first." }));
|
|
7476
7543
|
return;
|
|
7477
7544
|
}
|
|
7478
|
-
const reportPath =
|
|
7545
|
+
const reportPath = path12.join(paths.wikiDir, "graph", "report.json");
|
|
7479
7546
|
const report = await readJsonFile(reportPath) ?? null;
|
|
7480
7547
|
response.writeHead(200, { "content-type": "application/json" });
|
|
7481
7548
|
response.end(JSON.stringify(buildViewerGraphArtifact(graph, { report, full: options.full ?? false })));
|
|
@@ -7539,7 +7606,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
7539
7606
|
return;
|
|
7540
7607
|
}
|
|
7541
7608
|
if (url.pathname === "/api/graph-report") {
|
|
7542
|
-
const reportPath =
|
|
7609
|
+
const reportPath = path12.join(paths.wikiDir, "graph", "report.json");
|
|
7543
7610
|
if (!await fileExists(reportPath)) {
|
|
7544
7611
|
response.writeHead(404, { "content-type": "application/json" });
|
|
7545
7612
|
response.end(JSON.stringify({ error: "Graph report artifact not found. Run `swarmvault compile` first." }));
|
|
@@ -7783,7 +7850,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
7783
7850
|
return;
|
|
7784
7851
|
}
|
|
7785
7852
|
if (url.pathname === "/api/workspace") {
|
|
7786
|
-
const reportPath =
|
|
7853
|
+
const reportPath = path12.join(paths.wikiDir, "graph", "report.json");
|
|
7787
7854
|
const [graphRaw, reportRaw, approvalsRaw, candidatesRaw, memoryTasksRaw, watchStatusRaw, lintRaw, doctorRaw] = await Promise.all([
|
|
7788
7855
|
readJsonFile(paths.graphPath).catch(() => null),
|
|
7789
7856
|
readJsonFile(reportPath).catch(() => null),
|
|
@@ -7908,8 +7975,8 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
7908
7975
|
return;
|
|
7909
7976
|
}
|
|
7910
7977
|
const relativePath = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
|
|
7911
|
-
const target =
|
|
7912
|
-
const fallback =
|
|
7978
|
+
const target = path12.join(paths.viewerDistDir, relativePath);
|
|
7979
|
+
const fallback = path12.join(paths.viewerDistDir, "index.html");
|
|
7913
7980
|
const filePath = await fileExists(target) ? target : fallback;
|
|
7914
7981
|
if (!await fileExists(filePath)) {
|
|
7915
7982
|
response.writeHead(503, { "content-type": "text/plain" });
|
|
@@ -7956,7 +8023,7 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
7956
8023
|
throw new Error("Graph artifact not found. Run `swarmvault compile` first.");
|
|
7957
8024
|
}
|
|
7958
8025
|
await ensureViewerDist(paths.viewerDistDir);
|
|
7959
|
-
const indexPath =
|
|
8026
|
+
const indexPath = path12.join(paths.viewerDistDir, "index.html");
|
|
7960
8027
|
if (!await fileExists(indexPath)) {
|
|
7961
8028
|
throw new Error("Viewer build not found. Run `pnpm build` first.");
|
|
7962
8029
|
}
|
|
@@ -7985,14 +8052,14 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
7985
8052
|
const rawHtml = await fs11.readFile(indexPath, "utf8");
|
|
7986
8053
|
const scriptMatch = rawHtml.match(/<script type="module" crossorigin src="([^"]+)"><\/script>/);
|
|
7987
8054
|
const styleMatch = rawHtml.match(/<link rel="stylesheet" crossorigin href="([^"]+)">/);
|
|
7988
|
-
const scriptPath = scriptMatch?.[1] ?
|
|
7989
|
-
const stylePath = styleMatch?.[1] ?
|
|
8055
|
+
const scriptPath = scriptMatch?.[1] ? path12.join(paths.viewerDistDir, scriptMatch[1].replace(/^\//, "")) : null;
|
|
8056
|
+
const stylePath = styleMatch?.[1] ? path12.join(paths.viewerDistDir, styleMatch[1].replace(/^\//, "")) : null;
|
|
7990
8057
|
if (!scriptPath || !await fileExists(scriptPath)) {
|
|
7991
8058
|
throw new Error("Viewer script bundle not found. Run `pnpm build` first.");
|
|
7992
8059
|
}
|
|
7993
8060
|
const script = await fs11.readFile(scriptPath, "utf8");
|
|
7994
8061
|
const style = stylePath && await fileExists(stylePath) ? await fs11.readFile(stylePath, "utf8") : "";
|
|
7995
|
-
const report = await readJsonFile(
|
|
8062
|
+
const report = await readJsonFile(path12.join(paths.wikiDir, "graph", "report.json"));
|
|
7996
8063
|
const embeddedData = JSON.stringify(
|
|
7997
8064
|
{ graph: buildViewerGraphArtifact(graph, { report, full: options.full ?? false }), pages: pages.filter(Boolean), report },
|
|
7998
8065
|
null,
|
|
@@ -8015,9 +8082,9 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
8015
8082
|
"</html>",
|
|
8016
8083
|
""
|
|
8017
8084
|
].filter(Boolean).join("\n");
|
|
8018
|
-
await fs11.mkdir(
|
|
8085
|
+
await fs11.mkdir(path12.dirname(outputPath), { recursive: true });
|
|
8019
8086
|
await fs11.writeFile(outputPath, html, "utf8");
|
|
8020
|
-
return
|
|
8087
|
+
return path12.resolve(outputPath);
|
|
8021
8088
|
}
|
|
8022
8089
|
export {
|
|
8023
8090
|
ALL_MIGRATIONS,
|
|
@@ -8031,6 +8098,7 @@ export {
|
|
|
8031
8098
|
LOCAL_WHISPER_MODEL_SIZES,
|
|
8032
8099
|
LocalWhisperProviderAdapter,
|
|
8033
8100
|
OPENAI_COMPATIBLE_CAPABILITY_MATRIX,
|
|
8101
|
+
SWARMVAULT_OUT_ENV,
|
|
8034
8102
|
acceptApproval,
|
|
8035
8103
|
addInput,
|
|
8036
8104
|
addManagedSource,
|
|
@@ -8048,6 +8116,7 @@ export {
|
|
|
8048
8116
|
buildGraphShareArtifact,
|
|
8049
8117
|
buildMemoryGraphElements,
|
|
8050
8118
|
buildRedactor,
|
|
8119
|
+
checkTrackedRepoChanges,
|
|
8051
8120
|
compileVault,
|
|
8052
8121
|
computeDecayScore,
|
|
8053
8122
|
consolidateVault,
|
|
@@ -8079,6 +8148,7 @@ export {
|
|
|
8079
8148
|
finishMemoryTask,
|
|
8080
8149
|
getGitHookStatus,
|
|
8081
8150
|
getGraphCommunityVault,
|
|
8151
|
+
getGraphStatus,
|
|
8082
8152
|
getProviderForTask,
|
|
8083
8153
|
getRetrievalStatus,
|
|
8084
8154
|
getWatchStatus,
|
|
@@ -8133,6 +8203,7 @@ export {
|
|
|
8133
8203
|
readMemoryTask,
|
|
8134
8204
|
readPage,
|
|
8135
8205
|
rebuildRetrievalIndex,
|
|
8206
|
+
refreshGraphClusters,
|
|
8136
8207
|
registerLocalWhisperProvider,
|
|
8137
8208
|
rejectApproval,
|
|
8138
8209
|
reloadManagedSources,
|
|
@@ -8145,6 +8216,7 @@ export {
|
|
|
8145
8216
|
renderGraphShareSvg,
|
|
8146
8217
|
renderMemoryTaskMarkdown,
|
|
8147
8218
|
resetDecay,
|
|
8219
|
+
resolveArtifactRootDir,
|
|
8148
8220
|
resolveConsolidationConfig,
|
|
8149
8221
|
resolveDecayConfig,
|
|
8150
8222
|
resolveLargeRepoDefaults,
|