@gmickel/gno 1.45.1 → 2.0.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 +1 -1
- package/THIRD_PARTY_NOTICES.md +46 -0
- package/assets/skill/SKILL.md +7 -6
- package/assets/skill/cli-reference.md +14 -6
- package/assets/skill/mcp-reference.md +4 -1
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +32 -33
- package/bunfig.toml +2 -0
- package/package.json +40 -26
- package/spec/cli.md +30 -11
- package/spec/db/schema.sql +146 -1
- package/spec/mcp.md +26 -0
- package/src/app/context-runtime-types.ts +3 -0
- package/src/app/context-runtime.ts +2 -0
- package/src/cli/commands/ask.ts +6 -1
- package/src/cli/commands/daemon.ts +21 -8
- package/src/cli/commands/embed.ts +77 -41
- package/src/cli/commands/mcp/install.ts +20 -0
- package/src/cli/commands/mcp/paths.ts +25 -0
- package/src/cli/commands/mcp/status.ts +6 -0
- package/src/cli/detach.ts +3 -2
- package/src/cli/program.ts +6 -0
- package/src/config/types.ts +3 -3
- package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
- package/src/converters/adapters/officeparser/adapter.ts +1 -2
- package/src/converters/versions.ts +6 -8
- package/src/core/context-evidence.ts +8 -4
- package/src/core/job-manager.ts +95 -13
- package/src/core/network-boundary-inventory.ts +10 -0
- package/src/core/shutdown-budget.ts +45 -0
- package/src/embed/backlog.ts +107 -4
- package/src/embed/batch.ts +42 -2
- package/src/embed/fingerprint.ts +16 -0
- package/src/embed/retry.ts +113 -5
- package/src/embed/variant-backlog.ts +105 -0
- package/src/embed/variant-plan.ts +62 -0
- package/src/embed/variant-retry.ts +113 -0
- package/src/ingestion/graph-reconciliation.ts +327 -0
- package/src/ingestion/sync.ts +9 -272
- package/src/llm/http-inference.ts +6 -0
- package/src/llm/httpEmbedding.ts +37 -6
- package/src/llm/httpGeneration.ts +18 -3
- package/src/llm/httpRerank.ts +23 -5
- package/src/llm/inference-cancellation.ts +168 -0
- package/src/llm/inference-scope.ts +202 -0
- package/src/llm/lazy-ports.ts +115 -0
- package/src/llm/native-worker/client.ts +541 -0
- package/src/llm/native-worker/dispatcher.ts +228 -0
- package/src/llm/native-worker/embedding-identity.ts +33 -0
- package/src/llm/native-worker/entry.ts +173 -0
- package/src/llm/native-worker/errors.ts +32 -0
- package/src/llm/native-worker/evaluation.ts +16 -0
- package/src/llm/native-worker/owned-exit.ts +108 -0
- package/src/llm/native-worker/owner.ts +141 -0
- package/src/llm/native-worker/ports.ts +317 -0
- package/src/llm/native-worker/protocol.ts +442 -0
- package/src/llm/native-worker/runtime-config.ts +92 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
- package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
- package/src/llm/nodeLlamaCpp/generation.ts +34 -5
- package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
- package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
- package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
- package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
- package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
- package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
- package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
- package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
- package/src/llm/types.ts +35 -5
- package/src/mcp/context.ts +27 -0
- package/src/mcp/http-transport.ts +12 -10
- package/src/mcp/server.ts +3 -0
- package/src/mcp/tool-profile.ts +30 -8
- package/src/mcp/tools/context.ts +8 -11
- package/src/mcp/tools/embed.ts +1 -1
- package/src/mcp/tools/index-cmd.ts +1 -1
- package/src/mcp/tools/index.ts +10 -8
- package/src/mcp/tools/query.ts +14 -30
- package/src/mcp/tools/vsearch.ts +1 -1
- package/src/pipeline/answer.ts +23 -3
- package/src/pipeline/claim-verifier.ts +6 -0
- package/src/pipeline/expansion.ts +43 -40
- package/src/pipeline/explain.ts +6 -2
- package/src/pipeline/filters.ts +63 -0
- package/src/pipeline/fusion.ts +29 -9
- package/src/pipeline/graph-retrieval.ts +29 -9
- package/src/pipeline/hybrid.ts +198 -55
- package/src/pipeline/hydration.ts +161 -0
- package/src/pipeline/owner-fusion.ts +87 -0
- package/src/pipeline/rerank.ts +35 -11
- package/src/pipeline/search.ts +13 -2
- package/src/pipeline/types.ts +5 -3
- package/src/pipeline/vsearch.ts +87 -7
- package/src/sdk/client.ts +47 -3
- package/src/sdk/embed.ts +63 -39
- package/src/serve/background-runtime.ts +1 -1
- package/src/serve/context.ts +41 -56
- package/src/serve/embed-scheduler.ts +58 -35
- package/src/serve/public/components/IndexingProgress.tsx +46 -60
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/shiki-language-ids.ts +14 -0
- package/src/serve/resident-admission.ts +36 -36
- package/src/serve/resident-background-work.ts +20 -2
- package/src/serve/resident-request.ts +11 -5
- package/src/serve/resident-runtime.ts +97 -61
- package/src/serve/resident-shutdown.ts +153 -0
- package/src/serve/routes/api.ts +3 -1
- package/src/serve/server.ts +47 -26
- package/src/store/migrations/028-vector-variants.ts +54 -0
- package/src/store/migrations/029-graph-reference-state.ts +77 -0
- package/src/store/migrations/index.ts +4 -0
- package/src/store/sqlite/adapter.ts +251 -183
- package/src/store/sqlite/eligibility.ts +174 -0
- package/src/store/sqlite/graph-edge-application.ts +66 -0
- package/src/store/sqlite/graph-reference-state.ts +194 -0
- package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
- package/src/store/types.ts +80 -12
- package/src/store/vector/eligibility.ts +36 -0
- package/src/store/vector/freshness.ts +33 -6
- package/src/store/vector/lazy.ts +81 -0
- package/src/store/vector/sqlite-vec.ts +106 -54
- package/src/store/vector/stats.ts +14 -3
- package/src/store/vector/types.ts +35 -2
- package/src/store/vector/variant-search.ts +192 -0
- package/src/store/vector/variants.ts +451 -0
- package/vendor/converters/markitdown-ts/LICENSE +21 -0
- package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
- package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
- package/vendor/converters/markitdown-ts/package.json +77 -0
- package/vendor/converters/officeparser/LICENSE +21 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
- package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
- package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
- package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
- package/vendor/converters/officeparser/dist/cli.js +381 -0
- package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
- package/vendor/converters/officeparser/dist/defaults.js +218 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
- package/vendor/converters/officeparser/dist/index.d.ts +60 -0
- package/vendor/converters/officeparser/dist/index.js +72 -0
- package/vendor/converters/officeparser/dist/index.mjs +18 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
- package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
- package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
- package/vendor/converters/officeparser/dist/types.js +107 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
- package/vendor/converters/officeparser/package.json +147 -0
- package/vendor/converters/upstream-manifest.json +124 -0
- package/vendor/dependency-fixes/README.md +77 -0
- package/vendor/dependency-fixes/vendor-converters.py +83 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-627emwpj.js +0 -75
- /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/** Incremental graph inventory closure; full projection remains the repair oracle. */
|
|
2
|
+
import type {
|
|
3
|
+
DocEdgeInput,
|
|
4
|
+
DocumentRow,
|
|
5
|
+
GraphReferenceDocument,
|
|
6
|
+
GraphReferenceInventory,
|
|
7
|
+
StorePort,
|
|
8
|
+
} from "../store/types";
|
|
9
|
+
import type { SyncOptions } from "./types";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
isRelationMap,
|
|
13
|
+
normalizeRelationEdgeType,
|
|
14
|
+
normalizeRelationTarget,
|
|
15
|
+
} from "../core/change-diff";
|
|
16
|
+
import {
|
|
17
|
+
normalizeMarkdownPath,
|
|
18
|
+
normalizeWikiName,
|
|
19
|
+
parseTargetParts,
|
|
20
|
+
} from "../core/links";
|
|
21
|
+
import { parseFrontmatter } from "./frontmatter";
|
|
22
|
+
|
|
23
|
+
const VERSION = 1;
|
|
24
|
+
const EDGE_TYPE = /^[a-z][a-z0-9_]*$/;
|
|
25
|
+
type ProjectionError = { relPath: string; code: string; message: string };
|
|
26
|
+
|
|
27
|
+
function identity(doc: DocumentRow): GraphReferenceDocument {
|
|
28
|
+
return {
|
|
29
|
+
documentId: doc.id,
|
|
30
|
+
collection: doc.collection,
|
|
31
|
+
relPath: doc.relPath,
|
|
32
|
+
docid: doc.docid,
|
|
33
|
+
uri: doc.uri,
|
|
34
|
+
title: doc.title,
|
|
35
|
+
mirrorHash: doc.mirrorHash,
|
|
36
|
+
sourceHash: doc.sourceHash,
|
|
37
|
+
contentType: doc.contentType ?? null,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Insert once in catalog order: preserves legacy Array.find ambiguity precedence. */
|
|
42
|
+
function relationResolver(docs: GraphReferenceDocument[]) {
|
|
43
|
+
const docids = new Map<string, GraphReferenceDocument>();
|
|
44
|
+
const uris = new Map<string, GraphReferenceDocument>();
|
|
45
|
+
const paths = new Map<string, GraphReferenceDocument>();
|
|
46
|
+
const wiki = new Map<string, GraphReferenceDocument>();
|
|
47
|
+
const localWiki = new Map<string, GraphReferenceDocument>();
|
|
48
|
+
const put = (
|
|
49
|
+
map: Map<string, GraphReferenceDocument>,
|
|
50
|
+
key: string,
|
|
51
|
+
doc: GraphReferenceDocument
|
|
52
|
+
) => {
|
|
53
|
+
if (!map.has(key)) map.set(key, doc);
|
|
54
|
+
};
|
|
55
|
+
for (const doc of docs) {
|
|
56
|
+
put(docids, doc.docid, doc);
|
|
57
|
+
put(uris, doc.uri, doc);
|
|
58
|
+
put(paths, `${doc.collection}/${doc.relPath}`, doc);
|
|
59
|
+
const title = doc.title ?? doc.relPath.split("/").pop() ?? doc.relPath;
|
|
60
|
+
for (const value of [
|
|
61
|
+
title,
|
|
62
|
+
doc.relPath,
|
|
63
|
+
doc.relPath.replace(/\.[^/.]+$/, ""),
|
|
64
|
+
]) {
|
|
65
|
+
const key = normalizeWikiName(value);
|
|
66
|
+
put(wiki, key, doc);
|
|
67
|
+
put(localWiki, `${doc.collection}\0${key}`, doc);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return (
|
|
71
|
+
source: GraphReferenceDocument,
|
|
72
|
+
raw: string
|
|
73
|
+
): GraphReferenceDocument | undefined => {
|
|
74
|
+
const target = normalizeRelationTarget(raw);
|
|
75
|
+
if (!target) return;
|
|
76
|
+
if (target.startsWith("#")) return docids.get(target);
|
|
77
|
+
if (target.startsWith("gno://")) return uris.get(target);
|
|
78
|
+
const parts = parseTargetParts(target);
|
|
79
|
+
if (!parts.ref) return;
|
|
80
|
+
const key = normalizeWikiName(parts.ref);
|
|
81
|
+
if (parts.collection)
|
|
82
|
+
return (
|
|
83
|
+
paths.get(`${parts.collection}/${parts.ref}`) ??
|
|
84
|
+
localWiki.get(`${parts.collection}\0${key}`)
|
|
85
|
+
);
|
|
86
|
+
const relativePath = normalizeMarkdownPath(parts.ref, source.relPath);
|
|
87
|
+
return (
|
|
88
|
+
(relativePath
|
|
89
|
+
? paths.get(`${source.collection}/${relativePath}`)
|
|
90
|
+
: undefined) ??
|
|
91
|
+
paths.get(parts.ref) ??
|
|
92
|
+
localWiki.get(`${source.collection}\0${key}`) ??
|
|
93
|
+
wiki.get(key)
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function projectGraph(
|
|
99
|
+
store: StorePort,
|
|
100
|
+
options: SyncOptions,
|
|
101
|
+
requestedSources?: Set<number>,
|
|
102
|
+
forceFull = false
|
|
103
|
+
): Promise<ProjectionError[]> {
|
|
104
|
+
const errors: ProjectionError[] = [];
|
|
105
|
+
try {
|
|
106
|
+
const graph = store.graphReferenceStore?.();
|
|
107
|
+
let fingerprint = "";
|
|
108
|
+
if (graph) {
|
|
109
|
+
const collections = await store.getCollections();
|
|
110
|
+
if (!collections.ok) throw new Error(collections.error.message);
|
|
111
|
+
fingerprint = new Bun.CryptoHasher("sha256")
|
|
112
|
+
.update(
|
|
113
|
+
JSON.stringify({
|
|
114
|
+
rules: options.contentTypeRules ?? [],
|
|
115
|
+
collections: collections.value
|
|
116
|
+
.map(({ syncedAt: _syncedAt, ...config }) => config)
|
|
117
|
+
.sort((a, b) => a.name.localeCompare(b.name)),
|
|
118
|
+
})
|
|
119
|
+
)
|
|
120
|
+
.digest("hex");
|
|
121
|
+
}
|
|
122
|
+
const state = graph?.state(VERSION, fingerprint);
|
|
123
|
+
if (!forceFull && state?.complete) return [];
|
|
124
|
+
const documents = await store.listDocuments();
|
|
125
|
+
if (!documents.ok) throw new Error(documents.error.message);
|
|
126
|
+
const activeDocs = documents.value.filter((doc) => doc.active);
|
|
127
|
+
const current = activeDocs.map(identity);
|
|
128
|
+
const currentById = new Map(current.map((doc) => [doc.documentId, doc]));
|
|
129
|
+
// Read before begin: a new version/config deliberately resets the old inventory.
|
|
130
|
+
const previous = graph?.readInventory() ?? [];
|
|
131
|
+
const previousById = new Map(
|
|
132
|
+
previous.map((row) => [row.document.documentId, row])
|
|
133
|
+
);
|
|
134
|
+
const full =
|
|
135
|
+
forceFull ||
|
|
136
|
+
!graph ||
|
|
137
|
+
!state ||
|
|
138
|
+
state.inProgress ||
|
|
139
|
+
state.version !== VERSION ||
|
|
140
|
+
state.configFingerprint !== fingerprint;
|
|
141
|
+
const resolve = relationResolver(current);
|
|
142
|
+
let selected: Set<number> | undefined;
|
|
143
|
+
if (!full && graph) {
|
|
144
|
+
selected = new Set(requestedSources);
|
|
145
|
+
const changed = new Map<number, GraphReferenceDocument[]>();
|
|
146
|
+
for (const doc of current) {
|
|
147
|
+
const old = previousById.get(doc.documentId)?.document;
|
|
148
|
+
if (!old || JSON.stringify(old) !== JSON.stringify(doc)) {
|
|
149
|
+
changed.set(doc.documentId, old ? [old, doc] : [doc]);
|
|
150
|
+
selected.add(doc.documentId);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const row of previous) {
|
|
154
|
+
if (!currentById.has(row.document.documentId)) {
|
|
155
|
+
changed.set(row.document.documentId, [row.document]);
|
|
156
|
+
selected.add(row.document.documentId);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Input mutation without a changed identity can be a direct parsed-link edit.
|
|
160
|
+
// No durable per-source link journal exists; conservatively rebuild in that case.
|
|
161
|
+
if (changed.size === 0 && state.dirty) selected = undefined;
|
|
162
|
+
else {
|
|
163
|
+
for (const id of graph.incomingLinkSources(
|
|
164
|
+
[...changed.values()].flat()
|
|
165
|
+
))
|
|
166
|
+
selected.add(id);
|
|
167
|
+
const resolveOld = relationResolver(
|
|
168
|
+
previous.map((row) => row.document)
|
|
169
|
+
);
|
|
170
|
+
for (const row of previous) {
|
|
171
|
+
const source = currentById.get(row.document.documentId);
|
|
172
|
+
if (!source || selected.has(source.documentId)) continue;
|
|
173
|
+
if (
|
|
174
|
+
row.references.some(
|
|
175
|
+
(ref) =>
|
|
176
|
+
resolveOld(row.document, ref.target)?.documentId !==
|
|
177
|
+
resolve(source, ref.target)?.documentId
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
selected.add(source.documentId);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Persist interruption authority before starting the projection transaction.
|
|
185
|
+
const epoch = graph?.begin(VERSION, fingerprint);
|
|
186
|
+
if (state && epoch !== state.epoch + 1)
|
|
187
|
+
throw new Error("Graph inputs changed while computing affected sources");
|
|
188
|
+
const work = async () => {
|
|
189
|
+
const targets = selected
|
|
190
|
+
? documents.value.filter((doc) => selected.has(doc.id))
|
|
191
|
+
: documents.value;
|
|
192
|
+
// Configured sources get their final sets below. Applying defaults first
|
|
193
|
+
// would delete/recreate an unchanged configured edge on every repair pass.
|
|
194
|
+
const defaults = targets.filter((doc) => {
|
|
195
|
+
const hint = options.contentTypeRules?.find(
|
|
196
|
+
(rule) => rule.id === doc.contentType
|
|
197
|
+
)?.graphHints?.[0];
|
|
198
|
+
return !doc.active || !hint || !EDGE_TYPE.test(hint);
|
|
199
|
+
});
|
|
200
|
+
const backfill = await store.backfillDocEdges(
|
|
201
|
+
defaults.map((doc) => doc.id)
|
|
202
|
+
);
|
|
203
|
+
if (!backfill.ok) throw new Error(backfill.error.message);
|
|
204
|
+
for (const [index, doc] of targets.entries()) {
|
|
205
|
+
if (index > 0 && index % 25 === 0) await Bun.sleep(0);
|
|
206
|
+
if (!doc.active) {
|
|
207
|
+
const cleared = await store.setDocEdges(
|
|
208
|
+
doc.id,
|
|
209
|
+
[],
|
|
210
|
+
"frontmatter-relation"
|
|
211
|
+
);
|
|
212
|
+
if (!cleared.ok)
|
|
213
|
+
errors.push({ relPath: doc.relPath, ...cleared.error });
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const snapshot = currentById.get(doc.id)!;
|
|
217
|
+
const cached = selected ? previousById.get(doc.id) : undefined;
|
|
218
|
+
let references: GraphReferenceInventory["references"];
|
|
219
|
+
if (
|
|
220
|
+
cached &&
|
|
221
|
+
cached.document.mirrorHash === doc.mirrorHash &&
|
|
222
|
+
cached.document.sourceHash === doc.sourceHash
|
|
223
|
+
)
|
|
224
|
+
references = cached.references;
|
|
225
|
+
else {
|
|
226
|
+
references = [];
|
|
227
|
+
if (doc.mirrorHash) {
|
|
228
|
+
const content = await store.getContent(doc.mirrorHash);
|
|
229
|
+
if (!content.ok || content.value === null) {
|
|
230
|
+
errors.push({
|
|
231
|
+
relPath: doc.relPath,
|
|
232
|
+
code: "QUERY_FAILED",
|
|
233
|
+
message: content.ok
|
|
234
|
+
? "Missing graph source content"
|
|
235
|
+
: content.error.message,
|
|
236
|
+
});
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const relations = parseFrontmatter(content.value).metadata
|
|
240
|
+
.relations;
|
|
241
|
+
if (isRelationMap(relations)) {
|
|
242
|
+
for (const [rawType, refs] of Object.entries(relations)) {
|
|
243
|
+
const edgeType = normalizeRelationEdgeType(rawType);
|
|
244
|
+
if (EDGE_TYPE.test(edgeType)) {
|
|
245
|
+
for (const target of refs)
|
|
246
|
+
references.push({ edgeType, target });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const relationEdges: DocEdgeInput[] = [];
|
|
253
|
+
for (const ref of references) {
|
|
254
|
+
const target = resolve(snapshot, ref.target);
|
|
255
|
+
if (target)
|
|
256
|
+
relationEdges.push({
|
|
257
|
+
targetDocId: target.documentId,
|
|
258
|
+
edgeType: ref.edgeType,
|
|
259
|
+
confidence: "manual",
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
const relationsResult = await store.setDocEdges(
|
|
263
|
+
doc.id,
|
|
264
|
+
relationEdges,
|
|
265
|
+
"frontmatter-relation"
|
|
266
|
+
);
|
|
267
|
+
if (!relationsResult.ok)
|
|
268
|
+
errors.push({ relPath: doc.relPath, ...relationsResult.error });
|
|
269
|
+
graph?.writeInventory({ document: snapshot, references });
|
|
270
|
+
const hint = options.contentTypeRules?.find(
|
|
271
|
+
(rule) => rule.id === doc.contentType
|
|
272
|
+
)?.graphHints?.[0];
|
|
273
|
+
if (!hint || !EDGE_TYPE.test(hint)) continue;
|
|
274
|
+
const links = await store.getLinksForDoc(doc.id);
|
|
275
|
+
if (!links.ok) {
|
|
276
|
+
errors.push({ relPath: doc.relPath, ...links.error });
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const relationIds = new Set(
|
|
280
|
+
relationEdges.map((edge) => edge.targetDocId)
|
|
281
|
+
);
|
|
282
|
+
const wikiEdges: DocEdgeInput[] = [];
|
|
283
|
+
const markdownEdges: DocEdgeInput[] = [];
|
|
284
|
+
for (const link of links.value) {
|
|
285
|
+
const ref =
|
|
286
|
+
link.linkType === "markdown"
|
|
287
|
+
? `${doc.collection}/${link.targetRefNorm}`
|
|
288
|
+
: link.targetCollection
|
|
289
|
+
? `${link.targetCollection}:${link.targetRef}`
|
|
290
|
+
: link.targetRefNorm;
|
|
291
|
+
const target = resolve(snapshot, ref);
|
|
292
|
+
if (!target || relationIds.has(target.documentId)) continue;
|
|
293
|
+
const edge: DocEdgeInput = {
|
|
294
|
+
targetDocId: target.documentId,
|
|
295
|
+
edgeType: hint,
|
|
296
|
+
confidence: "configured",
|
|
297
|
+
};
|
|
298
|
+
(link.linkType === "wiki" ? wikiEdges : markdownEdges).push(edge);
|
|
299
|
+
}
|
|
300
|
+
for (const [source, edges] of [
|
|
301
|
+
["wikilink", wikiEdges],
|
|
302
|
+
["markdown-link", markdownEdges],
|
|
303
|
+
] as const) {
|
|
304
|
+
const result = await store.setDocEdges(doc.id, edges, source);
|
|
305
|
+
if (!result.ok)
|
|
306
|
+
errors.push({ relPath: doc.relPath, ...result.error });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (errors.length) throw new Error("Graph projection incomplete");
|
|
310
|
+
if (graph && epoch !== undefined) graph.complete(epoch);
|
|
311
|
+
};
|
|
312
|
+
if (store.withTransaction) {
|
|
313
|
+
const result = await store.withTransaction(work);
|
|
314
|
+
if (!result.ok && errors.length === 0)
|
|
315
|
+
throw new Error(result.error.message);
|
|
316
|
+
} else await work();
|
|
317
|
+
} catch (cause) {
|
|
318
|
+
if (errors.length === 0)
|
|
319
|
+
errors.push({
|
|
320
|
+
relPath: "(typed edge projection)",
|
|
321
|
+
code: "QUERY_FAILED",
|
|
322
|
+
message:
|
|
323
|
+
cause instanceof Error ? cause.message : "Graph projection failed",
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
return errors;
|
|
327
|
+
}
|
package/src/ingestion/sync.ts
CHANGED
|
@@ -14,7 +14,6 @@ import type { NormalizedContentTypeRule } from "../config";
|
|
|
14
14
|
import type { Collection } from "../config/types";
|
|
15
15
|
import type {
|
|
16
16
|
ChunkInput,
|
|
17
|
-
DocEdgeInput,
|
|
18
17
|
DocLinkInput,
|
|
19
18
|
DocumentInput,
|
|
20
19
|
DocumentRow,
|
|
@@ -49,16 +48,12 @@ import { DEFAULT_LIMITS, type RecordAdapter } from "../converters/types";
|
|
|
49
48
|
import {
|
|
50
49
|
diffDocumentStructure,
|
|
51
50
|
extractDocumentStructure,
|
|
52
|
-
isRelationMap,
|
|
53
|
-
normalizeRelationEdgeType,
|
|
54
|
-
normalizeRelationTarget,
|
|
55
51
|
} from "../core/change-diff";
|
|
56
52
|
import { enforceCollectionEgress } from "../core/egress-enforcement";
|
|
57
53
|
import {
|
|
58
54
|
normalizeMarkdownPath,
|
|
59
55
|
normalizeWikiName,
|
|
60
56
|
parseLinks,
|
|
61
|
-
parseTargetParts,
|
|
62
57
|
} from "../core/links";
|
|
63
58
|
import { extractMemoryScopes } from "../core/memory-record";
|
|
64
59
|
import { normalizeTag, validateTag } from "../core/tags";
|
|
@@ -68,6 +63,7 @@ import {
|
|
|
68
63
|
parseFrontmatter,
|
|
69
64
|
stripFrontmatter,
|
|
70
65
|
} from "./frontmatter";
|
|
66
|
+
import { projectGraph } from "./graph-reconciliation";
|
|
71
67
|
import { buildLineOffsets } from "./position";
|
|
72
68
|
import { processRecordContainer } from "./record-container";
|
|
73
69
|
import {
|
|
@@ -104,8 +100,6 @@ const MAX_CONCURRENCY = 16;
|
|
|
104
100
|
export const INGEST_VERSION = 6;
|
|
105
101
|
const EMPTY_CONTENT_TYPE_RULES_FINGERPRINT =
|
|
106
102
|
fingerprintContentTypeMetadataRules([]);
|
|
107
|
-
const RELATION_EDGE_TYPE_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
108
|
-
const PROJECTION_YIELD_INTERVAL = 25;
|
|
109
103
|
const NON_RETRYABLE_CONVERSION_ERROR_CODES = new Set([
|
|
110
104
|
"CORRUPT",
|
|
111
105
|
"PERMISSION",
|
|
@@ -113,98 +107,6 @@ const NON_RETRYABLE_CONVERSION_ERROR_CODES = new Set([
|
|
|
113
107
|
"UNSUPPORTED",
|
|
114
108
|
]);
|
|
115
109
|
|
|
116
|
-
function findDocByWikiRef(
|
|
117
|
-
docs: DocumentRow[],
|
|
118
|
-
targetRef: string,
|
|
119
|
-
collection?: string
|
|
120
|
-
): DocumentRow | undefined {
|
|
121
|
-
const normalized = normalizeWikiName(targetRef);
|
|
122
|
-
const candidates = collection
|
|
123
|
-
? docs.filter((doc) => doc.collection === collection)
|
|
124
|
-
: docs;
|
|
125
|
-
|
|
126
|
-
return candidates.find((doc) => {
|
|
127
|
-
const title = doc.title ?? doc.relPath.split("/").pop() ?? doc.relPath;
|
|
128
|
-
const relStem = doc.relPath.replace(/\.[^/.]+$/, "");
|
|
129
|
-
return (
|
|
130
|
-
normalizeWikiName(title) === normalized ||
|
|
131
|
-
normalizeWikiName(doc.relPath) === normalized ||
|
|
132
|
-
normalizeWikiName(relStem) === normalized
|
|
133
|
-
);
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function resolveRelationTarget(
|
|
138
|
-
docs: DocumentRow[],
|
|
139
|
-
sourceDoc: DocumentRow,
|
|
140
|
-
rawTarget: string
|
|
141
|
-
): DocumentRow | undefined {
|
|
142
|
-
const target = normalizeRelationTarget(rawTarget);
|
|
143
|
-
if (!target) {
|
|
144
|
-
return undefined;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (target.startsWith("#")) {
|
|
148
|
-
return docs.find((doc) => doc.docid === target);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (target.startsWith("gno://")) {
|
|
152
|
-
return docs.find((doc) => doc.uri === target);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const parts = parseTargetParts(target);
|
|
156
|
-
const targetCollection = parts.collection;
|
|
157
|
-
const targetRef = parts.ref;
|
|
158
|
-
if (!targetRef) {
|
|
159
|
-
return undefined;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (targetCollection) {
|
|
163
|
-
const exact = docs.find(
|
|
164
|
-
(doc) => doc.collection === targetCollection && doc.relPath === targetRef
|
|
165
|
-
);
|
|
166
|
-
return exact ?? findDocByWikiRef(docs, targetRef, targetCollection);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const sameCollectionPath = normalizeMarkdownPath(
|
|
170
|
-
targetRef,
|
|
171
|
-
sourceDoc.relPath
|
|
172
|
-
);
|
|
173
|
-
if (sameCollectionPath) {
|
|
174
|
-
const exact = docs.find(
|
|
175
|
-
(doc) =>
|
|
176
|
-
doc.collection === sourceDoc.collection &&
|
|
177
|
-
doc.relPath === sameCollectionPath
|
|
178
|
-
);
|
|
179
|
-
if (exact) {
|
|
180
|
-
return exact;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const explicitCollPath = docs.find(
|
|
185
|
-
(doc) => `${doc.collection}/${doc.relPath}` === targetRef
|
|
186
|
-
);
|
|
187
|
-
if (explicitCollPath) {
|
|
188
|
-
return explicitCollPath;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return (
|
|
192
|
-
findDocByWikiRef(docs, targetRef, sourceDoc.collection) ??
|
|
193
|
-
findDocByWikiRef(docs, targetRef)
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function getPrimaryGraphHint(
|
|
198
|
-
contentType: string | null | undefined,
|
|
199
|
-
rules: NormalizedContentTypeRule[]
|
|
200
|
-
): string | undefined {
|
|
201
|
-
if (!contentType) {
|
|
202
|
-
return undefined;
|
|
203
|
-
}
|
|
204
|
-
const rule = rules.find((candidate) => candidate.id === contentType);
|
|
205
|
-
return rule?.graphHints?.[0];
|
|
206
|
-
}
|
|
207
|
-
|
|
208
110
|
/**
|
|
209
111
|
* Decide whether to process a file or skip it.
|
|
210
112
|
* Handles repair cases where sourceHash matches but content is incomplete.
|
|
@@ -219,6 +121,11 @@ function decideAction(
|
|
|
219
121
|
if (!existing) {
|
|
220
122
|
return { kind: "process", reason: "new file" };
|
|
221
123
|
}
|
|
124
|
+
// Identical bytes can reappear after deletion; restore through the normal
|
|
125
|
+
// conversion/upsert path so identity, derived data and journal agree.
|
|
126
|
+
if (!existing.active) {
|
|
127
|
+
return { kind: "repair", reason: "source restored" };
|
|
128
|
+
}
|
|
222
129
|
|
|
223
130
|
// Source hash changed - must process
|
|
224
131
|
if (existing.sourceHash !== sourceHash) {
|
|
@@ -1784,182 +1691,12 @@ export class SyncService {
|
|
|
1784
1691
|
return null;
|
|
1785
1692
|
}
|
|
1786
1693
|
|
|
1787
|
-
private
|
|
1694
|
+
private projectTypedEdges(
|
|
1788
1695
|
store: StorePort,
|
|
1789
1696
|
options: SyncOptions,
|
|
1790
1697
|
sourceDocumentIds?: Set<number>
|
|
1791
1698
|
): Promise<Array<{ relPath: string; code: string; message: string }>> {
|
|
1792
|
-
|
|
1793
|
-
[];
|
|
1794
|
-
|
|
1795
|
-
const selectedSourceIds = sourceDocumentIds
|
|
1796
|
-
? [...sourceDocumentIds]
|
|
1797
|
-
: undefined;
|
|
1798
|
-
const backfillResult = await store.backfillDocEdges(selectedSourceIds);
|
|
1799
|
-
if (!backfillResult.ok) {
|
|
1800
|
-
return [
|
|
1801
|
-
{
|
|
1802
|
-
relPath: "(typed edge backfill)",
|
|
1803
|
-
code: backfillResult.error.code,
|
|
1804
|
-
message: backfillResult.error.message,
|
|
1805
|
-
},
|
|
1806
|
-
];
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
const docsResult = await store.listDocuments();
|
|
1810
|
-
if (!docsResult.ok) {
|
|
1811
|
-
return [
|
|
1812
|
-
{
|
|
1813
|
-
relPath: "(typed edge projection)",
|
|
1814
|
-
code: docsResult.error.code,
|
|
1815
|
-
message: docsResult.error.message,
|
|
1816
|
-
},
|
|
1817
|
-
];
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
const activeDocs = docsResult.value.filter((doc) => doc.active);
|
|
1821
|
-
const activeIds = new Set(activeDocs.map((doc) => doc.id));
|
|
1822
|
-
if (selectedSourceIds) {
|
|
1823
|
-
for (const documentId of selectedSourceIds) {
|
|
1824
|
-
if (!activeIds.has(documentId)) {
|
|
1825
|
-
// Clear typed edges for inactivated projection sources.
|
|
1826
|
-
const clearResult = await store.setDocEdges(
|
|
1827
|
-
documentId,
|
|
1828
|
-
[],
|
|
1829
|
-
"frontmatter-relation"
|
|
1830
|
-
);
|
|
1831
|
-
if (!clearResult.ok) {
|
|
1832
|
-
errors.push({
|
|
1833
|
-
relPath: `(doc:${documentId})`,
|
|
1834
|
-
code: clearResult.error.code,
|
|
1835
|
-
message: clearResult.error.message,
|
|
1836
|
-
});
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
const projectedDocs = sourceDocumentIds
|
|
1842
|
-
? activeDocs.filter((doc) => sourceDocumentIds.has(doc.id))
|
|
1843
|
-
: activeDocs;
|
|
1844
|
-
|
|
1845
|
-
for (const [docIndex, doc] of projectedDocs.entries()) {
|
|
1846
|
-
if (docIndex > 0 && docIndex % PROJECTION_YIELD_INTERVAL === 0) {
|
|
1847
|
-
await Bun.sleep(0);
|
|
1848
|
-
}
|
|
1849
|
-
if (!doc.mirrorHash) {
|
|
1850
|
-
continue;
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
const contentResult = await store.getContent(doc.mirrorHash);
|
|
1854
|
-
if (!contentResult.ok || contentResult.value === null) {
|
|
1855
|
-
continue;
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
const relationsValue = parseFrontmatter(contentResult.value).metadata
|
|
1859
|
-
.relations;
|
|
1860
|
-
const relationEdges: DocEdgeInput[] = [];
|
|
1861
|
-
|
|
1862
|
-
if (isRelationMap(relationsValue)) {
|
|
1863
|
-
for (const [rawEdgeType, targets] of Object.entries(relationsValue)) {
|
|
1864
|
-
const edgeType = normalizeRelationEdgeType(rawEdgeType);
|
|
1865
|
-
if (!RELATION_EDGE_TYPE_PATTERN.test(edgeType)) {
|
|
1866
|
-
continue;
|
|
1867
|
-
}
|
|
1868
|
-
for (const target of targets) {
|
|
1869
|
-
const targetDoc = resolveRelationTarget(activeDocs, doc, target);
|
|
1870
|
-
if (targetDoc) {
|
|
1871
|
-
relationEdges.push({
|
|
1872
|
-
targetDocId: targetDoc.id,
|
|
1873
|
-
edgeType,
|
|
1874
|
-
confidence: "manual",
|
|
1875
|
-
});
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
const relationTargetIds = new Set(
|
|
1881
|
-
relationEdges.map((edge) => edge.targetDocId)
|
|
1882
|
-
);
|
|
1883
|
-
|
|
1884
|
-
const relationsResult = await store.setDocEdges(
|
|
1885
|
-
doc.id,
|
|
1886
|
-
relationEdges,
|
|
1887
|
-
"frontmatter-relation"
|
|
1888
|
-
);
|
|
1889
|
-
if (!relationsResult.ok) {
|
|
1890
|
-
errors.push({
|
|
1891
|
-
relPath: doc.relPath,
|
|
1892
|
-
code: relationsResult.error.code,
|
|
1893
|
-
message: relationsResult.error.message,
|
|
1894
|
-
});
|
|
1895
|
-
}
|
|
1896
|
-
|
|
1897
|
-
const primaryHint = getPrimaryGraphHint(
|
|
1898
|
-
doc.contentType,
|
|
1899
|
-
options.contentTypeRules ?? []
|
|
1900
|
-
);
|
|
1901
|
-
if (!primaryHint || !RELATION_EDGE_TYPE_PATTERN.test(primaryHint)) {
|
|
1902
|
-
continue;
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
|
-
const linksResult = await store.getLinksForDoc(doc.id);
|
|
1906
|
-
if (!linksResult.ok) {
|
|
1907
|
-
errors.push({
|
|
1908
|
-
relPath: doc.relPath,
|
|
1909
|
-
code: linksResult.error.code,
|
|
1910
|
-
message: linksResult.error.message,
|
|
1911
|
-
});
|
|
1912
|
-
continue;
|
|
1913
|
-
}
|
|
1914
|
-
|
|
1915
|
-
const wikiEdges: DocEdgeInput[] = [];
|
|
1916
|
-
const markdownEdges: DocEdgeInput[] = [];
|
|
1917
|
-
for (const link of linksResult.value) {
|
|
1918
|
-
const targetRef =
|
|
1919
|
-
link.linkType === "markdown"
|
|
1920
|
-
? `${doc.collection}/${link.targetRefNorm}`
|
|
1921
|
-
: link.targetCollection
|
|
1922
|
-
? `${link.targetCollection}:${link.targetRef}`
|
|
1923
|
-
: link.targetRefNorm;
|
|
1924
|
-
const targetDoc = resolveRelationTarget(activeDocs, doc, targetRef);
|
|
1925
|
-
if (!targetDoc || relationTargetIds.has(targetDoc.id)) {
|
|
1926
|
-
continue;
|
|
1927
|
-
}
|
|
1928
|
-
const edge = {
|
|
1929
|
-
targetDocId: targetDoc.id,
|
|
1930
|
-
edgeType: primaryHint,
|
|
1931
|
-
confidence: "configured" as const,
|
|
1932
|
-
};
|
|
1933
|
-
if (link.linkType === "wiki") {
|
|
1934
|
-
wikiEdges.push(edge);
|
|
1935
|
-
} else {
|
|
1936
|
-
markdownEdges.push(edge);
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
const wikiResult = await store.setDocEdges(doc.id, wikiEdges, "wikilink");
|
|
1941
|
-
if (!wikiResult.ok) {
|
|
1942
|
-
errors.push({
|
|
1943
|
-
relPath: doc.relPath,
|
|
1944
|
-
code: wikiResult.error.code,
|
|
1945
|
-
message: wikiResult.error.message,
|
|
1946
|
-
});
|
|
1947
|
-
}
|
|
1948
|
-
const markdownResult = await store.setDocEdges(
|
|
1949
|
-
doc.id,
|
|
1950
|
-
markdownEdges,
|
|
1951
|
-
"markdown-link"
|
|
1952
|
-
);
|
|
1953
|
-
if (!markdownResult.ok) {
|
|
1954
|
-
errors.push({
|
|
1955
|
-
relPath: doc.relPath,
|
|
1956
|
-
code: markdownResult.error.code,
|
|
1957
|
-
message: markdownResult.error.message,
|
|
1958
|
-
});
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
return errors;
|
|
1699
|
+
return projectGraph(store, options, sourceDocumentIds);
|
|
1963
1700
|
}
|
|
1964
1701
|
|
|
1965
1702
|
/** Run an exact global typed-edge reconciliation with cooperative yields. */
|
|
@@ -1967,7 +1704,7 @@ export class SyncService {
|
|
|
1967
1704
|
store: StorePort,
|
|
1968
1705
|
options: SyncOptions = {}
|
|
1969
1706
|
): Promise<Array<{ relPath: string; code: string; message: string }>> {
|
|
1970
|
-
return
|
|
1707
|
+
return projectGraph(store, options, undefined, true);
|
|
1971
1708
|
}
|
|
1972
1709
|
|
|
1973
1710
|
/**
|
|
@@ -21,6 +21,8 @@ import { classifyHttpDestination, prepareHttpDestination } from "./http-policy";
|
|
|
21
21
|
const REDIRECT_STATUSES = new Set([301, 302, 307, 308]);
|
|
22
22
|
|
|
23
23
|
export interface HttpInferenceOptions {
|
|
24
|
+
/** Resolved models.inferenceTimeout; measured across the complete HTTP call. */
|
|
25
|
+
inferenceTimeout?: number;
|
|
24
26
|
collections: readonly Collection[];
|
|
25
27
|
collectionNames: readonly string[];
|
|
26
28
|
authenticated?: boolean;
|
|
@@ -64,6 +66,7 @@ export const requestHttpInference = async (
|
|
|
64
66
|
init: BunFetchRequestInit,
|
|
65
67
|
options: HttpInferenceOptions
|
|
66
68
|
): Promise<Response> => {
|
|
69
|
+
init.signal?.throwIfAborted();
|
|
67
70
|
const states = scopedStates(options);
|
|
68
71
|
if (states.length === 0) {
|
|
69
72
|
enforce(states, "remote", options);
|
|
@@ -118,6 +121,7 @@ export const requestHttpInference = async (
|
|
|
118
121
|
|
|
119
122
|
let currentUrl = url;
|
|
120
123
|
for (;;) {
|
|
124
|
+
init.signal?.throwIfAborted();
|
|
121
125
|
enforce(states, prepared.value.classification.zone, options);
|
|
122
126
|
const connection = await prepared.value.acquireConnection();
|
|
123
127
|
if (!connection.ok) {
|
|
@@ -134,7 +138,9 @@ export const requestHttpInference = async (
|
|
|
134
138
|
})
|
|
135
139
|
);
|
|
136
140
|
}
|
|
141
|
+
init.signal?.throwIfAborted();
|
|
137
142
|
const response = await connection.value.request(init, options.fetchFn);
|
|
143
|
+
init.signal?.throwIfAborted();
|
|
138
144
|
if (!REDIRECT_STATUSES.has(response.status)) return response;
|
|
139
145
|
|
|
140
146
|
const location = response.headers.get("location");
|