@swarmvaultai/engine 0.6.4 → 0.6.6
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/LICENSE +21 -0
- package/dist/chunk-HRRPWXRZ.js +1335 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +554 -184
- package/dist/registry-NBLIJHZT.js +12 -0
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
firstSentences,
|
|
10
10
|
getProviderForTask,
|
|
11
11
|
initWorkspace,
|
|
12
|
+
isPathWithin,
|
|
12
13
|
listFilesRecursive,
|
|
13
14
|
loadVaultConfig,
|
|
14
15
|
normalizeWhitespace,
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
uniqueBy,
|
|
22
23
|
writeFileIfChanged,
|
|
23
24
|
writeJsonFile
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-HRRPWXRZ.js";
|
|
25
26
|
|
|
26
27
|
// src/agents.ts
|
|
27
28
|
import crypto from "crypto";
|
|
@@ -3869,8 +3870,31 @@ function interpreterFromShebang(content) {
|
|
|
3869
3870
|
}
|
|
3870
3871
|
return basename(parts[0] ?? "");
|
|
3871
3872
|
}
|
|
3872
|
-
function
|
|
3873
|
-
|
|
3873
|
+
function languageFromInterpreter(interpreter) {
|
|
3874
|
+
switch (interpreter) {
|
|
3875
|
+
case "sh":
|
|
3876
|
+
case "bash":
|
|
3877
|
+
case "zsh":
|
|
3878
|
+
case "dash":
|
|
3879
|
+
case "ksh":
|
|
3880
|
+
case "ash":
|
|
3881
|
+
return "bash";
|
|
3882
|
+
case "node":
|
|
3883
|
+
case "nodejs":
|
|
3884
|
+
return "javascript";
|
|
3885
|
+
case "python":
|
|
3886
|
+
case "python2":
|
|
3887
|
+
case "python3":
|
|
3888
|
+
return "python";
|
|
3889
|
+
case "ruby":
|
|
3890
|
+
return "ruby";
|
|
3891
|
+
case "php":
|
|
3892
|
+
return "php";
|
|
3893
|
+
case "lua":
|
|
3894
|
+
return "lua";
|
|
3895
|
+
default:
|
|
3896
|
+
return void 0;
|
|
3897
|
+
}
|
|
3874
3898
|
}
|
|
3875
3899
|
function formatDiagnosticCategory(category) {
|
|
3876
3900
|
switch (category) {
|
|
@@ -4472,8 +4496,11 @@ function inferCodeLanguage(filePath, mimeType = "", options = {}) {
|
|
|
4472
4496
|
if ([".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".hxx"].includes(extension)) {
|
|
4473
4497
|
return "cpp";
|
|
4474
4498
|
}
|
|
4475
|
-
if (!extension && options.executable
|
|
4476
|
-
|
|
4499
|
+
if (!extension && options.executable) {
|
|
4500
|
+
const fromShebang = languageFromInterpreter(interpreterFromShebang(options.content));
|
|
4501
|
+
if (fromShebang) {
|
|
4502
|
+
return fromShebang;
|
|
4503
|
+
}
|
|
4477
4504
|
}
|
|
4478
4505
|
return void 0;
|
|
4479
4506
|
}
|
|
@@ -6583,7 +6610,7 @@ function inferKind(mimeType, filePath, detectionOptions = {}) {
|
|
|
6583
6610
|
if (mimeType === "text/csv" || mimeType === "text/tab-separated-values" || filePath.toLowerCase().endsWith(".csv") || filePath.toLowerCase().endsWith(".tsv")) {
|
|
6584
6611
|
return "csv";
|
|
6585
6612
|
}
|
|
6586
|
-
if (mimeType.startsWith("text/")) {
|
|
6613
|
+
if (mimeType.startsWith("text/") || isStructuredTextMime(mimeType) || isKnownTextPath(filePath)) {
|
|
6587
6614
|
return "text";
|
|
6588
6615
|
}
|
|
6589
6616
|
if (mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || filePath.toLowerCase().endsWith(".xlsx")) {
|
|
@@ -6597,6 +6624,26 @@ function inferKind(mimeType, filePath, detectionOptions = {}) {
|
|
|
6597
6624
|
}
|
|
6598
6625
|
return "binary";
|
|
6599
6626
|
}
|
|
6627
|
+
function isStructuredTextMime(mimeType) {
|
|
6628
|
+
switch (mimeType) {
|
|
6629
|
+
case "application/json":
|
|
6630
|
+
case "application/json5":
|
|
6631
|
+
case "application/ld+json":
|
|
6632
|
+
case "application/manifest+json":
|
|
6633
|
+
case "application/xml":
|
|
6634
|
+
case "application/toml":
|
|
6635
|
+
case "application/yaml":
|
|
6636
|
+
case "application/x-yaml":
|
|
6637
|
+
case "application/javascript":
|
|
6638
|
+
case "application/ecmascript":
|
|
6639
|
+
case "application/typescript":
|
|
6640
|
+
case "application/x-sh":
|
|
6641
|
+
case "application/x-shellscript":
|
|
6642
|
+
return true;
|
|
6643
|
+
default:
|
|
6644
|
+
return false;
|
|
6645
|
+
}
|
|
6646
|
+
}
|
|
6600
6647
|
async function localCodeDetectionOptions(absolutePath, payloadBytes) {
|
|
6601
6648
|
if (path12.extname(absolutePath)) {
|
|
6602
6649
|
return {};
|
|
@@ -6645,7 +6692,129 @@ function guessMimeType(target) {
|
|
|
6645
6692
|
if (isRstFilePath(target)) {
|
|
6646
6693
|
return "text/x-rst";
|
|
6647
6694
|
}
|
|
6648
|
-
|
|
6695
|
+
const extension = path12.extname(target).toLowerCase();
|
|
6696
|
+
if (extension === ".ts" || extension === ".tsx" || extension === ".mts" || extension === ".cts") {
|
|
6697
|
+
return "text/typescript";
|
|
6698
|
+
}
|
|
6699
|
+
const looked = mime.lookup(target);
|
|
6700
|
+
if (looked) {
|
|
6701
|
+
return looked;
|
|
6702
|
+
}
|
|
6703
|
+
if (isKnownTextPath(target)) {
|
|
6704
|
+
return "text/plain";
|
|
6705
|
+
}
|
|
6706
|
+
return "application/octet-stream";
|
|
6707
|
+
}
|
|
6708
|
+
var KNOWN_TEXT_DOTFILE_NAMES = /* @__PURE__ */ new Set([
|
|
6709
|
+
".gitignore",
|
|
6710
|
+
".gitattributes",
|
|
6711
|
+
".gitkeep",
|
|
6712
|
+
".gitmodules",
|
|
6713
|
+
".editorconfig",
|
|
6714
|
+
".npmrc",
|
|
6715
|
+
".yarnrc",
|
|
6716
|
+
".prettierignore",
|
|
6717
|
+
".prettierrc",
|
|
6718
|
+
".dockerignore",
|
|
6719
|
+
".eslintignore",
|
|
6720
|
+
".eslintrc",
|
|
6721
|
+
".nvmrc",
|
|
6722
|
+
".node-version",
|
|
6723
|
+
".python-version",
|
|
6724
|
+
".ruby-version",
|
|
6725
|
+
".tool-versions"
|
|
6726
|
+
]);
|
|
6727
|
+
var KNOWN_TEXT_BASENAMES = /* @__PURE__ */ new Set([
|
|
6728
|
+
"readme",
|
|
6729
|
+
"license",
|
|
6730
|
+
"licence",
|
|
6731
|
+
"copying",
|
|
6732
|
+
"unlicense",
|
|
6733
|
+
"notice",
|
|
6734
|
+
"authors",
|
|
6735
|
+
"contributors",
|
|
6736
|
+
"patents",
|
|
6737
|
+
"maintainers",
|
|
6738
|
+
"owners",
|
|
6739
|
+
"codeowners",
|
|
6740
|
+
"changelog",
|
|
6741
|
+
"changes",
|
|
6742
|
+
"history",
|
|
6743
|
+
"news",
|
|
6744
|
+
"todo",
|
|
6745
|
+
"install",
|
|
6746
|
+
"dockerfile",
|
|
6747
|
+
"containerfile",
|
|
6748
|
+
"makefile",
|
|
6749
|
+
"gnumakefile",
|
|
6750
|
+
"rakefile",
|
|
6751
|
+
"gemfile",
|
|
6752
|
+
"procfile",
|
|
6753
|
+
"jenkinsfile",
|
|
6754
|
+
"vagrantfile",
|
|
6755
|
+
"brewfile",
|
|
6756
|
+
"go.mod",
|
|
6757
|
+
"go.sum",
|
|
6758
|
+
"go.work",
|
|
6759
|
+
"go.work.sum",
|
|
6760
|
+
"cargo.lock",
|
|
6761
|
+
"pipfile",
|
|
6762
|
+
"pipfile.lock",
|
|
6763
|
+
"poetry.lock",
|
|
6764
|
+
"uv.lock",
|
|
6765
|
+
"py.typed",
|
|
6766
|
+
"package-lock.json",
|
|
6767
|
+
"yarn.lock",
|
|
6768
|
+
"pnpm-lock.yaml",
|
|
6769
|
+
"composer.lock",
|
|
6770
|
+
"requirements.txt"
|
|
6771
|
+
]);
|
|
6772
|
+
var KNOWN_TEXT_BASENAME_PREFIXES = ["license", "licence", "copying", "unlicense", "readme", "changelog", "dockerfile", "containerfile"];
|
|
6773
|
+
var KNOWN_TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6774
|
+
".toml",
|
|
6775
|
+
".lock",
|
|
6776
|
+
".tmpl",
|
|
6777
|
+
".template",
|
|
6778
|
+
".mustache",
|
|
6779
|
+
".hbs",
|
|
6780
|
+
".handlebars",
|
|
6781
|
+
".ejs",
|
|
6782
|
+
".njk",
|
|
6783
|
+
".liquid",
|
|
6784
|
+
".vim",
|
|
6785
|
+
".typed",
|
|
6786
|
+
".env",
|
|
6787
|
+
".properties",
|
|
6788
|
+
".ini",
|
|
6789
|
+
".cfg",
|
|
6790
|
+
".conf",
|
|
6791
|
+
".config",
|
|
6792
|
+
".bazel",
|
|
6793
|
+
".bzl",
|
|
6794
|
+
".bat",
|
|
6795
|
+
".cmd"
|
|
6796
|
+
]);
|
|
6797
|
+
function isKnownTextPath(target) {
|
|
6798
|
+
const basename = path12.basename(target).toLowerCase();
|
|
6799
|
+
if (KNOWN_TEXT_DOTFILE_NAMES.has(basename)) {
|
|
6800
|
+
return true;
|
|
6801
|
+
}
|
|
6802
|
+
if (basename === ".env" || basename.startsWith(".env.")) {
|
|
6803
|
+
return true;
|
|
6804
|
+
}
|
|
6805
|
+
if (KNOWN_TEXT_BASENAMES.has(basename)) {
|
|
6806
|
+
return true;
|
|
6807
|
+
}
|
|
6808
|
+
for (const prefix of KNOWN_TEXT_BASENAME_PREFIXES) {
|
|
6809
|
+
if (basename === prefix || basename.startsWith(`${prefix}-`) || basename.startsWith(`${prefix}.`)) {
|
|
6810
|
+
return true;
|
|
6811
|
+
}
|
|
6812
|
+
}
|
|
6813
|
+
const extension = path12.extname(target).toLowerCase();
|
|
6814
|
+
if (extension && KNOWN_TEXT_EXTENSIONS.has(extension)) {
|
|
6815
|
+
return true;
|
|
6816
|
+
}
|
|
6817
|
+
return false;
|
|
6649
6818
|
}
|
|
6650
6819
|
function sourceGroupIdFor(prepared) {
|
|
6651
6820
|
const originKey = prepared.originType === "url" ? prepared.url ?? prepared.title : prepared.originalPath ?? prepared.title;
|
|
@@ -8564,7 +8733,7 @@ async function collectInboxAttachmentRefs(inputDir, files) {
|
|
|
8564
8733
|
const sourceRefs = [];
|
|
8565
8734
|
for (const ref of refs) {
|
|
8566
8735
|
const resolved = path12.resolve(path12.dirname(absolutePath), ref);
|
|
8567
|
-
if (!
|
|
8736
|
+
if (!isPathWithin(inputDir, resolved) || !await fileExists(resolved)) {
|
|
8568
8737
|
continue;
|
|
8569
8738
|
}
|
|
8570
8739
|
sourceRefs.push({
|
|
@@ -9099,6 +9268,7 @@ import { z as z7 } from "zod";
|
|
|
9099
9268
|
|
|
9100
9269
|
// src/analysis.ts
|
|
9101
9270
|
import path14 from "path";
|
|
9271
|
+
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
9102
9272
|
import { z as z2 } from "zod";
|
|
9103
9273
|
var ANALYSIS_FORMAT_VERSION = 7;
|
|
9104
9274
|
var sourceAnalysisSchema = z2.object({
|
|
@@ -9158,6 +9328,12 @@ var STOPWORDS = /* @__PURE__ */ new Set([
|
|
|
9158
9328
|
"would",
|
|
9159
9329
|
"your"
|
|
9160
9330
|
]);
|
|
9331
|
+
var HEURISTIC_SECTION_SOURCE_KINDS = /* @__PURE__ */ new Map([
|
|
9332
|
+
["transcript", "Transcript"],
|
|
9333
|
+
["chat_export", "Messages"],
|
|
9334
|
+
["email", "Message"],
|
|
9335
|
+
["calendar", "Description"]
|
|
9336
|
+
]);
|
|
9161
9337
|
function extractTopTerms(text, count) {
|
|
9162
9338
|
const frequency = /* @__PURE__ */ new Map();
|
|
9163
9339
|
for (const token of text.toLowerCase().match(/[a-z][a-z0-9-]{3,}/g) ?? []) {
|
|
@@ -9184,18 +9360,112 @@ function detectPolarity(text) {
|
|
|
9184
9360
|
}
|
|
9185
9361
|
return "neutral";
|
|
9186
9362
|
}
|
|
9187
|
-
function
|
|
9188
|
-
|
|
9189
|
-
|
|
9363
|
+
function parseMarkdownNodes(text) {
|
|
9364
|
+
try {
|
|
9365
|
+
const root = fromMarkdown(text);
|
|
9366
|
+
return Array.isArray(root.children) ? root.children : [];
|
|
9367
|
+
} catch {
|
|
9368
|
+
return [];
|
|
9369
|
+
}
|
|
9370
|
+
}
|
|
9371
|
+
function markdownNodeText(node) {
|
|
9372
|
+
if (node.type === "text" || node.type === "inlineCode" || node.type === "code") {
|
|
9373
|
+
return normalizeWhitespace(node.value ?? "");
|
|
9374
|
+
}
|
|
9375
|
+
if (node.type === "image") {
|
|
9376
|
+
return normalizeWhitespace(node.alt ?? "");
|
|
9377
|
+
}
|
|
9378
|
+
if (node.type === "break" || node.type === "thematicBreak") {
|
|
9379
|
+
return " ";
|
|
9380
|
+
}
|
|
9381
|
+
return normalizeWhitespace((node.children ?? []).map((child) => markdownNodeText(child)).join(" "));
|
|
9382
|
+
}
|
|
9383
|
+
function markdownNodesText(nodes) {
|
|
9384
|
+
return normalizeWhitespace(nodes.map((node) => markdownNodeText(node)).join("\n"));
|
|
9385
|
+
}
|
|
9386
|
+
function stripLeadingTitleNodes(nodes, title) {
|
|
9387
|
+
const normalizedTitle = normalizeWhitespace(title);
|
|
9388
|
+
if (!normalizedTitle || !nodes.length) {
|
|
9389
|
+
return nodes;
|
|
9390
|
+
}
|
|
9391
|
+
for (let index = 0; index < nodes.length; index += 1) {
|
|
9392
|
+
const node = nodes[index];
|
|
9393
|
+
if (!node) {
|
|
9394
|
+
continue;
|
|
9395
|
+
}
|
|
9396
|
+
const nodeText2 = markdownNodeText(node);
|
|
9397
|
+
if (node.type === "heading" && node.depth === 1 && nodeText2 === normalizedTitle) {
|
|
9398
|
+
return nodes.slice(index + 1);
|
|
9399
|
+
}
|
|
9400
|
+
if (node.type === "paragraph" && nodeText2 === normalizedTitle) {
|
|
9401
|
+
return nodes.slice(index + 1);
|
|
9402
|
+
}
|
|
9403
|
+
return nodes;
|
|
9404
|
+
}
|
|
9405
|
+
return nodes;
|
|
9406
|
+
}
|
|
9407
|
+
function markdownSectionNodes(nodes, heading) {
|
|
9408
|
+
const normalizedHeading = normalizeWhitespace(heading);
|
|
9409
|
+
for (let index = 0; index < nodes.length; index += 1) {
|
|
9410
|
+
const node = nodes[index];
|
|
9411
|
+
if (node?.type !== "heading" || node.depth !== 2) {
|
|
9412
|
+
continue;
|
|
9413
|
+
}
|
|
9414
|
+
if (markdownNodeText(node) !== normalizedHeading) {
|
|
9415
|
+
continue;
|
|
9416
|
+
}
|
|
9417
|
+
const sectionNodes = [];
|
|
9418
|
+
for (let cursor = index + 1; cursor < nodes.length; cursor += 1) {
|
|
9419
|
+
const candidate = nodes[cursor];
|
|
9420
|
+
if (candidate?.type === "heading" && typeof candidate.depth === "number" && candidate.depth <= 2) {
|
|
9421
|
+
break;
|
|
9422
|
+
}
|
|
9423
|
+
if (candidate) {
|
|
9424
|
+
sectionNodes.push(candidate);
|
|
9425
|
+
}
|
|
9426
|
+
}
|
|
9427
|
+
return sectionNodes;
|
|
9428
|
+
}
|
|
9429
|
+
return [];
|
|
9430
|
+
}
|
|
9431
|
+
function textForHeuristicAnalysis(manifest, text) {
|
|
9432
|
+
const nodes = parseMarkdownNodes(text);
|
|
9433
|
+
if (!nodes.length) {
|
|
9434
|
+
return normalizeWhitespace(text);
|
|
9435
|
+
}
|
|
9436
|
+
const sectionHeading = HEURISTIC_SECTION_SOURCE_KINDS.get(manifest.sourceKind);
|
|
9437
|
+
const scopedNodes = sectionHeading ? markdownSectionNodes(nodes, sectionHeading) : nodes;
|
|
9438
|
+
const relevantNodes = scopedNodes.length ? scopedNodes : nodes;
|
|
9439
|
+
const contentNodes = stripLeadingTitleNodes(relevantNodes, manifest.title);
|
|
9440
|
+
const normalized = markdownNodesText(contentNodes.length ? contentNodes : relevantNodes);
|
|
9441
|
+
return normalized || normalizeWhitespace(text);
|
|
9442
|
+
}
|
|
9443
|
+
function normalizeAnalysisTitle(manifest, candidate) {
|
|
9444
|
+
if (manifest.sourceKind !== "code") {
|
|
9445
|
+
return manifest.title;
|
|
9446
|
+
}
|
|
9447
|
+
const normalized = normalizeWhitespace(candidate.replace(/^#+\s+/, ""));
|
|
9448
|
+
if (!normalized) {
|
|
9449
|
+
return manifest.title;
|
|
9450
|
+
}
|
|
9451
|
+
if (normalized.length > 140 || normalized.includes(" ## ")) {
|
|
9452
|
+
return manifest.title;
|
|
9453
|
+
}
|
|
9454
|
+
return normalized;
|
|
9455
|
+
}
|
|
9456
|
+
function normalizeSourceAnalysis(manifest, analysis) {
|
|
9457
|
+
const title = normalizeAnalysisTitle(manifest, analysis.title);
|
|
9458
|
+
return title === analysis.title ? analysis : { ...analysis, title };
|
|
9190
9459
|
}
|
|
9191
9460
|
function heuristicAnalysis(manifest, text, schemaHash) {
|
|
9192
|
-
const
|
|
9461
|
+
const analysisText = textForHeuristicAnalysis(manifest, text);
|
|
9462
|
+
const normalized = normalizeWhitespace(analysisText);
|
|
9193
9463
|
const concepts = extractTopTerms(normalized, 6).map((term) => ({
|
|
9194
9464
|
id: `concept:${slugify(term)}`,
|
|
9195
9465
|
name: term,
|
|
9196
9466
|
description: `Frequently referenced concept in ${manifest.title}.`
|
|
9197
9467
|
}));
|
|
9198
|
-
const entities = extractEntities(
|
|
9468
|
+
const entities = extractEntities(analysisText, 6).map((term) => ({
|
|
9199
9469
|
id: `entity:${slugify(term)}`,
|
|
9200
9470
|
name: term,
|
|
9201
9471
|
description: `Named entity mentioned in ${manifest.title}.`
|
|
@@ -9208,7 +9478,7 @@ function heuristicAnalysis(manifest, text, schemaHash) {
|
|
|
9208
9478
|
semanticHash: manifest.semanticHash,
|
|
9209
9479
|
extractionHash: manifest.extractionHash,
|
|
9210
9480
|
schemaHash,
|
|
9211
|
-
title:
|
|
9481
|
+
title: manifest.title,
|
|
9212
9482
|
summary: firstSentences(normalized, 3) || truncate(normalized, 280) || `Imported ${manifest.sourceKind} source.`,
|
|
9213
9483
|
concepts,
|
|
9214
9484
|
entities,
|
|
@@ -9333,7 +9603,11 @@ async function analyzeSource(manifest, extractedText, provider, paths, schema) {
|
|
|
9333
9603
|
const cachePath = path14.join(paths.analysesDir, `${manifest.sourceId}.json`);
|
|
9334
9604
|
const cached = await readJsonFile(cachePath);
|
|
9335
9605
|
if (cached && cached.analysisVersion === ANALYSIS_FORMAT_VERSION && (cached.semanticHash ?? cached.sourceHash) === manifest.semanticHash && cached.extractionHash === manifest.extractionHash && cached.schemaHash === schema.hash) {
|
|
9336
|
-
|
|
9606
|
+
const normalizedCached = normalizeSourceAnalysis(manifest, cached);
|
|
9607
|
+
if (normalizedCached !== cached) {
|
|
9608
|
+
await writeJsonFile(cachePath, normalizedCached);
|
|
9609
|
+
}
|
|
9610
|
+
return normalizedCached;
|
|
9337
9611
|
}
|
|
9338
9612
|
const extraction = await readExtractionArtifact(paths.rootDir, manifest);
|
|
9339
9613
|
const content = normalizeWhitespace(extractedText ?? "");
|
|
@@ -9398,8 +9672,9 @@ async function analyzeSource(manifest, extractedText, provider, paths, schema) {
|
|
|
9398
9672
|
analysis = heuristicAnalysis(manifest, content, schema.hash);
|
|
9399
9673
|
}
|
|
9400
9674
|
}
|
|
9401
|
-
|
|
9402
|
-
|
|
9675
|
+
const normalized = normalizeSourceAnalysis(manifest, analysis);
|
|
9676
|
+
await writeJsonFile(cachePath, normalized);
|
|
9677
|
+
return normalized;
|
|
9403
9678
|
}
|
|
9404
9679
|
function analysisSignature(analysis) {
|
|
9405
9680
|
return sha256(JSON.stringify(analysis));
|
|
@@ -13486,7 +13761,7 @@ async function resolveImageGenerationProvider(rootDir) {
|
|
|
13486
13761
|
if (!providerConfig) {
|
|
13487
13762
|
throw new Error(`No provider configured with id "${preferredProviderId}" for task "imageProvider".`);
|
|
13488
13763
|
}
|
|
13489
|
-
const { createProvider: createProvider2 } = await import("./registry-
|
|
13764
|
+
const { createProvider: createProvider2 } = await import("./registry-NBLIJHZT.js");
|
|
13490
13765
|
return createProvider2(preferredProviderId, providerConfig, rootDir);
|
|
13491
13766
|
}
|
|
13492
13767
|
async function generateOutputArtifacts(rootDir, input) {
|
|
@@ -17525,9 +17800,16 @@ async function listPages(rootDir) {
|
|
|
17525
17800
|
return graph?.pages ?? [];
|
|
17526
17801
|
}
|
|
17527
17802
|
async function readPage(rootDir, relativePath) {
|
|
17803
|
+
if (!relativePath) {
|
|
17804
|
+
return null;
|
|
17805
|
+
}
|
|
17528
17806
|
const { paths } = await loadVaultConfig(rootDir);
|
|
17529
17807
|
const absolutePath = path23.resolve(paths.wikiDir, relativePath);
|
|
17530
|
-
if (!
|
|
17808
|
+
if (!isPathWithin(paths.wikiDir, absolutePath)) {
|
|
17809
|
+
return null;
|
|
17810
|
+
}
|
|
17811
|
+
const stats = await fs19.stat(absolutePath).catch(() => null);
|
|
17812
|
+
if (!stats?.isFile()) {
|
|
17531
17813
|
return null;
|
|
17532
17814
|
}
|
|
17533
17815
|
const raw = await fs19.readFile(absolutePath, "utf8");
|
|
@@ -17556,6 +17838,28 @@ async function getWorkspaceInfo(rootDir) {
|
|
|
17556
17838
|
pageCount: pages.length
|
|
17557
17839
|
};
|
|
17558
17840
|
}
|
|
17841
|
+
function extractClaimSectionLines(content) {
|
|
17842
|
+
const lines = content.split("\n");
|
|
17843
|
+
let inClaims = false;
|
|
17844
|
+
let found = false;
|
|
17845
|
+
const claimLines = [];
|
|
17846
|
+
for (const line of lines) {
|
|
17847
|
+
const trimmed = line.trimEnd();
|
|
17848
|
+
if (trimmed === "## Claims") {
|
|
17849
|
+
inClaims = true;
|
|
17850
|
+
found = true;
|
|
17851
|
+
continue;
|
|
17852
|
+
}
|
|
17853
|
+
if (inClaims) {
|
|
17854
|
+
if (/^#{1,2}\s/.test(trimmed)) {
|
|
17855
|
+
inClaims = false;
|
|
17856
|
+
continue;
|
|
17857
|
+
}
|
|
17858
|
+
claimLines.push(line);
|
|
17859
|
+
}
|
|
17860
|
+
}
|
|
17861
|
+
return found ? claimLines : null;
|
|
17862
|
+
}
|
|
17559
17863
|
function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sourceProjects) {
|
|
17560
17864
|
const manifestMap = new Map(manifests.map((manifest) => [manifest.sourceId, manifest]));
|
|
17561
17865
|
const pageMap2 = new Map(graph.pages.map((page) => [page.id, page]));
|
|
@@ -17601,8 +17905,9 @@ function structuralLintFindings(_rootDir, paths, graph, schemas, manifests, sour
|
|
|
17601
17905
|
const absolutePath = path23.join(paths.wikiDir, page.path);
|
|
17602
17906
|
if (await fileExists(absolutePath)) {
|
|
17603
17907
|
const content = await fs19.readFile(absolutePath, "utf8");
|
|
17604
|
-
|
|
17605
|
-
|
|
17908
|
+
const claimLines = extractClaimSectionLines(content);
|
|
17909
|
+
if (claimLines !== null) {
|
|
17910
|
+
const uncited = claimLines.filter((line) => line.startsWith("- ") && !line.includes("[source:"));
|
|
17606
17911
|
if (uncited.length) {
|
|
17607
17912
|
findings.push({
|
|
17608
17913
|
severity: "warning",
|
|
@@ -17717,7 +18022,7 @@ async function bootstrapDemo(rootDir, input) {
|
|
|
17717
18022
|
}
|
|
17718
18023
|
|
|
17719
18024
|
// src/mcp.ts
|
|
17720
|
-
var SERVER_VERSION = "0.6.
|
|
18025
|
+
var SERVER_VERSION = "0.6.6";
|
|
17721
18026
|
async function createMcpServer(rootDir) {
|
|
17722
18027
|
const server = new McpServer({
|
|
17723
18028
|
name: "swarmvault",
|
|
@@ -18052,7 +18357,7 @@ async function createMcpServer(rootDir) {
|
|
|
18052
18357
|
const encodedPath = typeof variables.path === "string" ? variables.path : "";
|
|
18053
18358
|
const relativePath = decodeURIComponent(encodedPath);
|
|
18054
18359
|
const absolutePath = path24.resolve(paths.sessionsDir, relativePath);
|
|
18055
|
-
if (!
|
|
18360
|
+
if (!isPathWithin(paths.sessionsDir, absolutePath) || !await fileExists(absolutePath)) {
|
|
18056
18361
|
return asTextResource(`swarmvault://sessions/${encodedPath}`, `Session not found: ${relativePath}`);
|
|
18057
18362
|
}
|
|
18058
18363
|
return asTextResource(`swarmvault://sessions/${encodedPath}`, await fs20.readFile(absolutePath, "utf8"));
|
|
@@ -18391,6 +18696,15 @@ var DOCS_HINT_SEGMENTS = /* @__PURE__ */ new Set([
|
|
|
18391
18696
|
function uniqueStrings4(values) {
|
|
18392
18697
|
return uniqueBy(values.filter(Boolean), (value) => value);
|
|
18393
18698
|
}
|
|
18699
|
+
function sourceOutputSchemaHash(schemas, projectIds) {
|
|
18700
|
+
if (!projectIds.length) {
|
|
18701
|
+
return schemas.effective.global.hash;
|
|
18702
|
+
}
|
|
18703
|
+
return composeVaultSchema(
|
|
18704
|
+
schemas.root,
|
|
18705
|
+
uniqueStrings4([...projectIds].sort((left, right) => left.localeCompare(right))).map((projectId) => schemas.projects[projectId]).filter((schema) => Boolean(schema?.hash))
|
|
18706
|
+
).hash;
|
|
18707
|
+
}
|
|
18394
18708
|
function normalizeManagedStatus(value) {
|
|
18395
18709
|
return value === "missing" || value === "error" ? value : "ready";
|
|
18396
18710
|
}
|
|
@@ -18974,6 +19288,7 @@ async function writeSourceBriefForScope(rootDir, source) {
|
|
|
18974
19288
|
return null;
|
|
18975
19289
|
}
|
|
18976
19290
|
const graph = await readJsonFile(paths.graphPath);
|
|
19291
|
+
const schemas = await loadVaultSchemas(rootDir);
|
|
18977
19292
|
const relatedPages = graph ? scopedSourcePages(graph, source.sourceIds) : [];
|
|
18978
19293
|
const relatedPageIds = relatedPages.slice(0, 12).map((page) => page.id);
|
|
18979
19294
|
const relatedNodeIds = graph ? scopedNodeIds(graph, source.sourceIds).slice(0, 20) : [];
|
|
@@ -18984,7 +19299,7 @@ async function writeSourceBriefForScope(rootDir, source) {
|
|
|
18984
19299
|
question: `Brief ${source.title}`,
|
|
18985
19300
|
answer: markdown,
|
|
18986
19301
|
citations: source.sourceIds,
|
|
18987
|
-
schemaHash:
|
|
19302
|
+
schemaHash: sourceOutputSchemaHash(schemas, projectIds),
|
|
18988
19303
|
outputFormat: "report",
|
|
18989
19304
|
relatedPageIds,
|
|
18990
19305
|
relatedNodeIds,
|
|
@@ -19219,6 +19534,7 @@ async function buildSourceReviewStagedPage(rootDir, scope) {
|
|
|
19219
19534
|
throw new Error(`Could not generate a source review for ${scope.id}.`);
|
|
19220
19535
|
}
|
|
19221
19536
|
const graph = await readJsonFile(paths.graphPath);
|
|
19537
|
+
const schemas = await loadVaultSchemas(rootDir);
|
|
19222
19538
|
const scopeManifests = manifestsForScope(graph, scope);
|
|
19223
19539
|
const relatedPages = graph ? scopedSourcePages(graph, scope.sourceIds) : [];
|
|
19224
19540
|
const relatedPageIds = relatedPages.slice(0, 16).map((page) => page.id);
|
|
@@ -19230,7 +19546,7 @@ async function buildSourceReviewStagedPage(rootDir, scope) {
|
|
|
19230
19546
|
question: `Review ${scope.title}`,
|
|
19231
19547
|
answer: markdown,
|
|
19232
19548
|
citations: scope.sourceIds,
|
|
19233
|
-
schemaHash:
|
|
19549
|
+
schemaHash: sourceOutputSchemaHash(schemas, projectIds),
|
|
19234
19550
|
outputFormat: "report",
|
|
19235
19551
|
relatedPageIds,
|
|
19236
19552
|
relatedNodeIds,
|
|
@@ -19464,6 +19780,7 @@ async function buildSourceGuideStagedPage(rootDir, scope) {
|
|
|
19464
19780
|
throw new Error(`Could not generate a source guide for ${scope.id}.`);
|
|
19465
19781
|
}
|
|
19466
19782
|
const graph = await readJsonFile(paths.graphPath);
|
|
19783
|
+
const schemas = await loadVaultSchemas(rootDir);
|
|
19467
19784
|
const scopeManifests = manifestsForScope(graph, scope);
|
|
19468
19785
|
const relatedPages = graph ? scopedSourcePages(graph, scope.sourceIds) : [];
|
|
19469
19786
|
const contradictions = findContradictionsForScope(scope, await readGraphReport(rootDir));
|
|
@@ -19477,7 +19794,7 @@ async function buildSourceGuideStagedPage(rootDir, scope) {
|
|
|
19477
19794
|
question: `Guide ${scope.title}`,
|
|
19478
19795
|
answer: markdown,
|
|
19479
19796
|
citations: scope.sourceIds,
|
|
19480
|
-
schemaHash:
|
|
19797
|
+
schemaHash: sourceOutputSchemaHash(schemas, projectIds),
|
|
19481
19798
|
outputFormat: "report",
|
|
19482
19799
|
relatedPageIds,
|
|
19483
19800
|
relatedNodeIds,
|
|
@@ -19566,6 +19883,7 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
|
19566
19883
|
await compileVault(rootDir, {});
|
|
19567
19884
|
graph = await readJsonFile(paths.graphPath);
|
|
19568
19885
|
}
|
|
19886
|
+
const schemas = await loadVaultSchemas(rootDir);
|
|
19569
19887
|
const scopeManifests = manifestsForScope(graph, scope);
|
|
19570
19888
|
const sourcePages = graph ? scopedSourcePages(graph, scope.sourceIds) : [];
|
|
19571
19889
|
const analyses = await loadSourceAnalyses(rootDir, scope.sourceIds);
|
|
@@ -19631,7 +19949,7 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
|
19631
19949
|
question: `Guided Session ${scope.title}`,
|
|
19632
19950
|
answer: sessionMarkdown,
|
|
19633
19951
|
citations: scope.sourceIds,
|
|
19634
|
-
schemaHash:
|
|
19952
|
+
schemaHash: sourceOutputSchemaHash(schemas, projectIds),
|
|
19635
19953
|
outputFormat: "report",
|
|
19636
19954
|
relatedPageIds,
|
|
19637
19955
|
relatedNodeIds,
|
|
@@ -19984,6 +20302,15 @@ async function resumeSourceSession(rootDir, id, options = {}) {
|
|
|
19984
20302
|
function shouldCompile(changedSources, graphExists, compileRequested) {
|
|
19985
20303
|
return compileRequested && (!graphExists || changedSources.length > 0);
|
|
19986
20304
|
}
|
|
20305
|
+
async function shouldRefreshBriefForManagedSource(source, options) {
|
|
20306
|
+
if (options.compilePerformed || options.changed) {
|
|
20307
|
+
return true;
|
|
20308
|
+
}
|
|
20309
|
+
if (!source.briefPath) {
|
|
20310
|
+
return true;
|
|
20311
|
+
}
|
|
20312
|
+
return !await fileExists(source.briefPath);
|
|
20313
|
+
}
|
|
19987
20314
|
async function listManagedSourceRecords(rootDir) {
|
|
19988
20315
|
await ensureManagedSourcesArtifact(rootDir);
|
|
19989
20316
|
return await loadManagedSources(rootDir);
|
|
@@ -20015,12 +20342,15 @@ async function addManagedSource(rootDir, input, options = {}) {
|
|
|
20015
20342
|
}
|
|
20016
20343
|
const graphExists = await loadVaultConfig(rootDir).then(({ paths }) => fileExists(paths.graphPath));
|
|
20017
20344
|
let compile;
|
|
20018
|
-
if (shouldCompile([synced], graphExists, compileRequested)) {
|
|
20345
|
+
if (shouldCompile(synced.changed ? [synced] : [], graphExists, compileRequested)) {
|
|
20019
20346
|
compile = await compileVault(rootDir, {});
|
|
20020
20347
|
}
|
|
20021
20348
|
let briefGenerated = false;
|
|
20022
20349
|
let briefPath;
|
|
20023
|
-
if (compileRequested && briefRequested && synced.status === "ready"
|
|
20350
|
+
if (compileRequested && briefRequested && synced.status === "ready" && await shouldRefreshBriefForManagedSource(synced, {
|
|
20351
|
+
compilePerformed: Boolean(compile),
|
|
20352
|
+
changed: synced.changed
|
|
20353
|
+
})) {
|
|
20024
20354
|
const briefs = await generateBriefsForSources(rootDir, [synced]);
|
|
20025
20355
|
briefPath = briefs.get(synced.id);
|
|
20026
20356
|
briefGenerated = Boolean(briefPath);
|
|
@@ -20664,10 +20994,21 @@ async function getWatchStatus(rootDir) {
|
|
|
20664
20994
|
|
|
20665
20995
|
// src/viewer.ts
|
|
20666
20996
|
var execFileAsync = promisify(execFile);
|
|
20997
|
+
async function isReadableFile(absolutePath) {
|
|
20998
|
+
try {
|
|
20999
|
+
const stats = await fs23.stat(absolutePath);
|
|
21000
|
+
return stats.isFile();
|
|
21001
|
+
} catch {
|
|
21002
|
+
return false;
|
|
21003
|
+
}
|
|
21004
|
+
}
|
|
20667
21005
|
async function readViewerPage(rootDir, relativePath) {
|
|
21006
|
+
if (!relativePath) {
|
|
21007
|
+
return null;
|
|
21008
|
+
}
|
|
20668
21009
|
const { paths } = await loadVaultConfig(rootDir);
|
|
20669
21010
|
const absolutePath = path28.resolve(paths.wikiDir, relativePath);
|
|
20670
|
-
if (!
|
|
21011
|
+
if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
|
|
20671
21012
|
return null;
|
|
20672
21013
|
}
|
|
20673
21014
|
const raw = await fs23.readFile(absolutePath, "utf8");
|
|
@@ -20681,9 +21022,12 @@ async function readViewerPage(rootDir, relativePath) {
|
|
|
20681
21022
|
};
|
|
20682
21023
|
}
|
|
20683
21024
|
async function readViewerAsset(rootDir, relativePath) {
|
|
21025
|
+
if (!relativePath) {
|
|
21026
|
+
return null;
|
|
21027
|
+
}
|
|
20684
21028
|
const { paths } = await loadVaultConfig(rootDir);
|
|
20685
21029
|
const absolutePath = path28.resolve(paths.wikiDir, relativePath);
|
|
20686
|
-
if (!
|
|
21030
|
+
if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
|
|
20687
21031
|
return null;
|
|
20688
21032
|
}
|
|
20689
21033
|
return {
|
|
@@ -20725,178 +21069,204 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
20725
21069
|
await ensureViewerDist(paths.viewerDistDir);
|
|
20726
21070
|
const server = http.createServer(async (request, response) => {
|
|
20727
21071
|
const url = new URL(request.url ?? "/", `http://${request.headers.host ?? `localhost:${effectivePort}`}`);
|
|
20728
|
-
|
|
20729
|
-
if (
|
|
20730
|
-
|
|
20731
|
-
|
|
21072
|
+
try {
|
|
21073
|
+
if (url.pathname === "/api/graph") {
|
|
21074
|
+
if (!await fileExists(paths.graphPath)) {
|
|
21075
|
+
response.writeHead(404, { "content-type": "application/json" });
|
|
21076
|
+
response.end(JSON.stringify({ error: "Graph artifact not found. Run `swarmvault compile` first." }));
|
|
21077
|
+
return;
|
|
21078
|
+
}
|
|
21079
|
+
const graph = await readJsonFile(paths.graphPath);
|
|
21080
|
+
if (!graph) {
|
|
21081
|
+
response.writeHead(404, { "content-type": "application/json" });
|
|
21082
|
+
response.end(JSON.stringify({ error: "Graph artifact not found. Run `swarmvault compile` first." }));
|
|
21083
|
+
return;
|
|
21084
|
+
}
|
|
21085
|
+
const reportPath = path28.join(paths.wikiDir, "graph", "report.json");
|
|
21086
|
+
const report = await readJsonFile(reportPath) ?? null;
|
|
21087
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21088
|
+
response.end(JSON.stringify(buildViewerGraphArtifact(graph, { report, full: options.full ?? false })));
|
|
20732
21089
|
return;
|
|
20733
21090
|
}
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
|
|
20737
|
-
|
|
21091
|
+
if (url.pathname === "/api/graph/query") {
|
|
21092
|
+
const question = url.searchParams.get("q") ?? "";
|
|
21093
|
+
const traversal = url.searchParams.get("traversal");
|
|
21094
|
+
const budget = Number.parseInt(url.searchParams.get("budget") ?? "12", 10);
|
|
21095
|
+
const result = await queryGraphVault(rootDir, question, {
|
|
21096
|
+
traversal: traversal === "dfs" ? "dfs" : "bfs",
|
|
21097
|
+
budget: Number.isFinite(budget) ? budget : 12
|
|
21098
|
+
});
|
|
21099
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21100
|
+
response.end(JSON.stringify(result));
|
|
20738
21101
|
return;
|
|
20739
21102
|
}
|
|
20740
|
-
|
|
20741
|
-
|
|
20742
|
-
|
|
20743
|
-
|
|
20744
|
-
|
|
20745
|
-
|
|
20746
|
-
if (url.pathname === "/api/graph/query") {
|
|
20747
|
-
const question = url.searchParams.get("q") ?? "";
|
|
20748
|
-
const traversal = url.searchParams.get("traversal");
|
|
20749
|
-
const budget = Number.parseInt(url.searchParams.get("budget") ?? "12", 10);
|
|
20750
|
-
response.writeHead(200, { "content-type": "application/json" });
|
|
20751
|
-
response.end(
|
|
20752
|
-
JSON.stringify(
|
|
20753
|
-
await queryGraphVault(rootDir, question, {
|
|
20754
|
-
traversal: traversal === "dfs" ? "dfs" : "bfs",
|
|
20755
|
-
budget: Number.isFinite(budget) ? budget : 12
|
|
20756
|
-
})
|
|
20757
|
-
)
|
|
20758
|
-
);
|
|
20759
|
-
return;
|
|
20760
|
-
}
|
|
20761
|
-
if (url.pathname === "/api/graph/path") {
|
|
20762
|
-
const from = url.searchParams.get("from") ?? "";
|
|
20763
|
-
const to = url.searchParams.get("to") ?? "";
|
|
20764
|
-
response.writeHead(200, { "content-type": "application/json" });
|
|
20765
|
-
response.end(JSON.stringify(await pathGraphVault(rootDir, from, to)));
|
|
20766
|
-
return;
|
|
20767
|
-
}
|
|
20768
|
-
if (url.pathname === "/api/graph/explain") {
|
|
20769
|
-
const target2 = url.searchParams.get("target") ?? "";
|
|
20770
|
-
response.writeHead(200, { "content-type": "application/json" });
|
|
20771
|
-
response.end(JSON.stringify(await explainGraphVault(rootDir, target2)));
|
|
20772
|
-
return;
|
|
20773
|
-
}
|
|
20774
|
-
if (url.pathname === "/api/search") {
|
|
20775
|
-
if (!await fileExists(paths.searchDbPath)) {
|
|
20776
|
-
response.writeHead(404, { "content-type": "application/json" });
|
|
20777
|
-
response.end(JSON.stringify({ error: "Search index not found. Run `swarmvault compile` first." }));
|
|
21103
|
+
if (url.pathname === "/api/graph/path") {
|
|
21104
|
+
const from = url.searchParams.get("from") ?? "";
|
|
21105
|
+
const to = url.searchParams.get("to") ?? "";
|
|
21106
|
+
const result = await pathGraphVault(rootDir, from, to);
|
|
21107
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21108
|
+
response.end(JSON.stringify(result));
|
|
20778
21109
|
return;
|
|
20779
21110
|
}
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
|
|
20794
|
-
|
|
20795
|
-
response.writeHead(200, { "content-type": "application/json" });
|
|
20796
|
-
response.end(JSON.stringify(results));
|
|
20797
|
-
return;
|
|
20798
|
-
}
|
|
20799
|
-
if (url.pathname === "/api/graph-report") {
|
|
20800
|
-
const reportPath = path28.join(paths.wikiDir, "graph", "report.json");
|
|
20801
|
-
if (!await fileExists(reportPath)) {
|
|
20802
|
-
response.writeHead(404, { "content-type": "application/json" });
|
|
20803
|
-
response.end(JSON.stringify({ error: "Graph report artifact not found. Run `swarmvault compile` first." }));
|
|
21111
|
+
if (url.pathname === "/api/graph/explain") {
|
|
21112
|
+
const target2 = url.searchParams.get("target") ?? "";
|
|
21113
|
+
if (!target2) {
|
|
21114
|
+
response.writeHead(400, { "content-type": "application/json" });
|
|
21115
|
+
response.end(JSON.stringify({ error: "Missing explain target." }));
|
|
21116
|
+
return;
|
|
21117
|
+
}
|
|
21118
|
+
try {
|
|
21119
|
+
const result = await explainGraphVault(rootDir, target2);
|
|
21120
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21121
|
+
response.end(JSON.stringify(result));
|
|
21122
|
+
} catch (error) {
|
|
21123
|
+
response.writeHead(404, { "content-type": "application/json" });
|
|
21124
|
+
response.end(JSON.stringify({ error: error instanceof Error ? error.message : `Could not resolve graph target: ${target2}` }));
|
|
21125
|
+
}
|
|
20804
21126
|
return;
|
|
20805
21127
|
}
|
|
20806
|
-
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
20811
|
-
|
|
20812
|
-
|
|
20813
|
-
|
|
20814
|
-
|
|
20815
|
-
|
|
20816
|
-
|
|
20817
|
-
|
|
20818
|
-
|
|
20819
|
-
|
|
20820
|
-
|
|
21128
|
+
if (url.pathname === "/api/search") {
|
|
21129
|
+
if (!await fileExists(paths.searchDbPath)) {
|
|
21130
|
+
response.writeHead(404, { "content-type": "application/json" });
|
|
21131
|
+
response.end(JSON.stringify({ error: "Search index not found. Run `swarmvault compile` first." }));
|
|
21132
|
+
return;
|
|
21133
|
+
}
|
|
21134
|
+
const query = url.searchParams.get("q") ?? "";
|
|
21135
|
+
const limit = Number.parseInt(url.searchParams.get("limit") ?? "10", 10);
|
|
21136
|
+
const kind = url.searchParams.get("kind") ?? "all";
|
|
21137
|
+
const status = url.searchParams.get("status") ?? "all";
|
|
21138
|
+
const project = url.searchParams.get("project") ?? "all";
|
|
21139
|
+
const sourceType = url.searchParams.get("sourceType") ?? "all";
|
|
21140
|
+
const sourceClass = url.searchParams.get("sourceClass") ?? "all";
|
|
21141
|
+
const results = searchPages(paths.searchDbPath, query, {
|
|
21142
|
+
limit: Number.isFinite(limit) ? limit : 10,
|
|
21143
|
+
kind,
|
|
21144
|
+
status,
|
|
21145
|
+
project,
|
|
21146
|
+
sourceType,
|
|
21147
|
+
sourceClass
|
|
21148
|
+
});
|
|
21149
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21150
|
+
response.end(JSON.stringify(results));
|
|
20821
21151
|
return;
|
|
20822
21152
|
}
|
|
20823
|
-
|
|
20824
|
-
|
|
20825
|
-
|
|
20826
|
-
|
|
20827
|
-
|
|
20828
|
-
|
|
20829
|
-
|
|
20830
|
-
|
|
20831
|
-
response.writeHead(
|
|
20832
|
-
response.end(
|
|
21153
|
+
if (url.pathname === "/api/graph-report") {
|
|
21154
|
+
const reportPath = path28.join(paths.wikiDir, "graph", "report.json");
|
|
21155
|
+
if (!await fileExists(reportPath)) {
|
|
21156
|
+
response.writeHead(404, { "content-type": "application/json" });
|
|
21157
|
+
response.end(JSON.stringify({ error: "Graph report artifact not found. Run `swarmvault compile` first." }));
|
|
21158
|
+
return;
|
|
21159
|
+
}
|
|
21160
|
+
const body = await fs23.readFile(reportPath, "utf8");
|
|
21161
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21162
|
+
response.end(body);
|
|
20833
21163
|
return;
|
|
20834
21164
|
}
|
|
20835
|
-
|
|
20836
|
-
|
|
20837
|
-
|
|
20838
|
-
|
|
20839
|
-
if (url.pathname === "/api/reviews" && request.method === "GET") {
|
|
20840
|
-
response.writeHead(200, { "content-type": "application/json" });
|
|
20841
|
-
response.end(JSON.stringify(await listApprovals(rootDir)));
|
|
20842
|
-
return;
|
|
20843
|
-
}
|
|
20844
|
-
if (url.pathname === "/api/review" && request.method === "GET") {
|
|
20845
|
-
const approvalId = url.searchParams.get("id") ?? "";
|
|
20846
|
-
if (!approvalId) {
|
|
20847
|
-
response.writeHead(400, { "content-type": "application/json" });
|
|
20848
|
-
response.end(JSON.stringify({ error: "Missing approval id." }));
|
|
21165
|
+
if (url.pathname === "/api/watch-status") {
|
|
21166
|
+
const watchStatus = await getWatchStatus(rootDir);
|
|
21167
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21168
|
+
response.end(JSON.stringify(watchStatus));
|
|
20849
21169
|
return;
|
|
20850
21170
|
}
|
|
20851
|
-
|
|
20852
|
-
|
|
20853
|
-
|
|
20854
|
-
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20860
|
-
|
|
20861
|
-
response.writeHead(400, { "content-type": "application/json" });
|
|
20862
|
-
response.end(JSON.stringify({ error: "Missing approval id or invalid review action." }));
|
|
21171
|
+
if (url.pathname === "/api/page") {
|
|
21172
|
+
const relativePath2 = url.searchParams.get("path") ?? "";
|
|
21173
|
+
const page = await readViewerPage(rootDir, relativePath2);
|
|
21174
|
+
if (!page) {
|
|
21175
|
+
response.writeHead(404, { "content-type": "application/json" });
|
|
21176
|
+
response.end(JSON.stringify({ error: `Page not found: ${relativePath2}` }));
|
|
21177
|
+
return;
|
|
21178
|
+
}
|
|
21179
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21180
|
+
response.end(JSON.stringify(page));
|
|
20863
21181
|
return;
|
|
20864
21182
|
}
|
|
20865
|
-
|
|
20866
|
-
|
|
20867
|
-
|
|
20868
|
-
|
|
20869
|
-
|
|
20870
|
-
|
|
20871
|
-
|
|
20872
|
-
|
|
20873
|
-
|
|
20874
|
-
|
|
20875
|
-
if (url.pathname === "/api/candidate" && request.method === "POST") {
|
|
20876
|
-
const body = await readJsonBody(request);
|
|
20877
|
-
const target2 = typeof body.target === "string" ? body.target : "";
|
|
20878
|
-
const action = url.searchParams.get("action") ?? "";
|
|
20879
|
-
if (!target2 || action !== "promote" && action !== "archive") {
|
|
20880
|
-
response.writeHead(400, { "content-type": "application/json" });
|
|
20881
|
-
response.end(JSON.stringify({ error: "Missing candidate target or invalid candidate action." }));
|
|
21183
|
+
if (url.pathname === "/api/asset") {
|
|
21184
|
+
const relativePath2 = url.searchParams.get("path") ?? "";
|
|
21185
|
+
const asset = await readViewerAsset(rootDir, relativePath2);
|
|
21186
|
+
if (!asset) {
|
|
21187
|
+
response.writeHead(404, { "content-type": "application/json" });
|
|
21188
|
+
response.end(JSON.stringify({ error: `Asset not found: ${relativePath2}` }));
|
|
21189
|
+
return;
|
|
21190
|
+
}
|
|
21191
|
+
response.writeHead(200, { "content-type": asset.mimeType });
|
|
21192
|
+
response.end(asset.buffer);
|
|
20882
21193
|
return;
|
|
20883
21194
|
}
|
|
20884
|
-
|
|
20885
|
-
|
|
20886
|
-
|
|
20887
|
-
|
|
20888
|
-
|
|
20889
|
-
|
|
20890
|
-
|
|
20891
|
-
|
|
20892
|
-
|
|
20893
|
-
|
|
20894
|
-
|
|
20895
|
-
|
|
20896
|
-
|
|
21195
|
+
if (url.pathname === "/api/reviews" && request.method === "GET") {
|
|
21196
|
+
const approvals = await listApprovals(rootDir);
|
|
21197
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21198
|
+
response.end(JSON.stringify(approvals));
|
|
21199
|
+
return;
|
|
21200
|
+
}
|
|
21201
|
+
if (url.pathname === "/api/review" && request.method === "GET") {
|
|
21202
|
+
const approvalId = url.searchParams.get("id") ?? "";
|
|
21203
|
+
if (!approvalId) {
|
|
21204
|
+
response.writeHead(400, { "content-type": "application/json" });
|
|
21205
|
+
response.end(JSON.stringify({ error: "Missing approval id." }));
|
|
21206
|
+
return;
|
|
21207
|
+
}
|
|
21208
|
+
const approval = await readApproval(rootDir, approvalId);
|
|
21209
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21210
|
+
response.end(JSON.stringify(approval));
|
|
21211
|
+
return;
|
|
21212
|
+
}
|
|
21213
|
+
if (url.pathname === "/api/review" && request.method === "POST") {
|
|
21214
|
+
const body = await readJsonBody(request);
|
|
21215
|
+
const approvalId = typeof body.approvalId === "string" ? body.approvalId : "";
|
|
21216
|
+
const targets = Array.isArray(body.targets) ? body.targets.filter((item) => typeof item === "string") : [];
|
|
21217
|
+
const action = url.searchParams.get("action") ?? "";
|
|
21218
|
+
if (!approvalId || action !== "accept" && action !== "reject") {
|
|
21219
|
+
response.writeHead(400, { "content-type": "application/json" });
|
|
21220
|
+
response.end(JSON.stringify({ error: "Missing approval id or invalid review action." }));
|
|
21221
|
+
return;
|
|
21222
|
+
}
|
|
21223
|
+
const result = action === "accept" ? await acceptApproval(rootDir, approvalId, targets) : await rejectApproval(rootDir, approvalId, targets);
|
|
21224
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21225
|
+
response.end(JSON.stringify(result));
|
|
21226
|
+
return;
|
|
21227
|
+
}
|
|
21228
|
+
if (url.pathname === "/api/candidates" && request.method === "GET") {
|
|
21229
|
+
const candidates = await listCandidates(rootDir);
|
|
21230
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21231
|
+
response.end(JSON.stringify(candidates));
|
|
21232
|
+
return;
|
|
21233
|
+
}
|
|
21234
|
+
if (url.pathname === "/api/candidate" && request.method === "POST") {
|
|
21235
|
+
const body = await readJsonBody(request);
|
|
21236
|
+
const target2 = typeof body.target === "string" ? body.target : "";
|
|
21237
|
+
const action = url.searchParams.get("action") ?? "";
|
|
21238
|
+
if (!target2 || action !== "promote" && action !== "archive") {
|
|
21239
|
+
response.writeHead(400, { "content-type": "application/json" });
|
|
21240
|
+
response.end(JSON.stringify({ error: "Missing candidate target or invalid candidate action." }));
|
|
21241
|
+
return;
|
|
21242
|
+
}
|
|
21243
|
+
const result = action === "promote" ? await promoteCandidate(rootDir, target2) : await archiveCandidate(rootDir, target2);
|
|
21244
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
21245
|
+
response.end(JSON.stringify(result));
|
|
21246
|
+
return;
|
|
21247
|
+
}
|
|
21248
|
+
const relativePath = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
|
|
21249
|
+
const target = path28.join(paths.viewerDistDir, relativePath);
|
|
21250
|
+
const fallback = path28.join(paths.viewerDistDir, "index.html");
|
|
21251
|
+
const filePath = await fileExists(target) ? target : fallback;
|
|
21252
|
+
if (!await fileExists(filePath)) {
|
|
21253
|
+
response.writeHead(503, { "content-type": "text/plain" });
|
|
21254
|
+
response.end("Viewer build not found. Run `pnpm build` first.");
|
|
21255
|
+
return;
|
|
21256
|
+
}
|
|
21257
|
+
const staticBody = await fs23.readFile(filePath);
|
|
21258
|
+
response.writeHead(200, { "content-type": mime2.lookup(filePath) || "text/plain" });
|
|
21259
|
+
response.end(staticBody);
|
|
21260
|
+
} catch (error) {
|
|
21261
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21262
|
+
console.error(`[viewer] ${request.method ?? "GET"} ${url.pathname} failed: ${message}`);
|
|
21263
|
+
if (!response.headersSent) {
|
|
21264
|
+
response.writeHead(500, { "content-type": "application/json" });
|
|
21265
|
+
response.end(JSON.stringify({ error: message }));
|
|
21266
|
+
} else {
|
|
21267
|
+
response.end();
|
|
21268
|
+
}
|
|
20897
21269
|
}
|
|
20898
|
-
response.writeHead(200, { "content-type": mime2.lookup(filePath) || "text/plain" });
|
|
20899
|
-
response.end(await fs23.readFile(filePath));
|
|
20900
21270
|
});
|
|
20901
21271
|
await new Promise((resolve) => {
|
|
20902
21272
|
server.listen(effectivePort, resolve);
|