@gmickel/gno 1.46.0 → 2.1.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 +17 -5
- package/THIRD_PARTY_NOTICES.md +46 -0
- package/assets/skill/SKILL.md +7 -6
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.1.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 +29 -4
- 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/detach.ts +3 -2
- 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/components/PublishExportDialog.tsx +266 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/globals.css +35 -0
- package/src/serve/public/lib/publish-export.ts +81 -1
- package/src/serve/public/lib/shiki-language-ids.ts +14 -0
- package/src/serve/public/pages/Collections.tsx +12 -46
- package/src/serve/public/pages/DocView.tsx +14 -52
- 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.46.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.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
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
type WriteLeaseContention,
|
|
23
23
|
withCliWriteLease,
|
|
24
24
|
} from "../../core/write-lease";
|
|
25
|
+
import { embedBacklog, prepareEmbeddingBacklog } from "../../embed/backlog";
|
|
25
26
|
import { getEmbeddingFingerprint } from "../../embed/fingerprint";
|
|
26
27
|
import {
|
|
27
28
|
addUniqueSamples,
|
|
@@ -38,6 +39,7 @@ import {
|
|
|
38
39
|
markIndexStageRunning,
|
|
39
40
|
readIndexStageState,
|
|
40
41
|
} from "../../embed/stage-state";
|
|
42
|
+
import { countVariantBacklog } from "../../embed/variant-plan";
|
|
41
43
|
import { LlmAdapter } from "../../llm/nodeLlamaCpp/adapter";
|
|
42
44
|
import { resolveDownloadPolicy } from "../../llm/policy";
|
|
43
45
|
import { resolveModelUri } from "../../llm/registry";
|
|
@@ -139,18 +141,6 @@ function isDisposedBatchError(message: string): boolean {
|
|
|
139
141
|
return message.toLowerCase().includes("object is disposed");
|
|
140
142
|
}
|
|
141
143
|
|
|
142
|
-
async function checkVecAvailable(
|
|
143
|
-
db: import("bun:sqlite").Database
|
|
144
|
-
): Promise<boolean> {
|
|
145
|
-
try {
|
|
146
|
-
const sqliteVec = await import("sqlite-vec");
|
|
147
|
-
sqliteVec.load(db);
|
|
148
|
-
return true;
|
|
149
|
-
} catch {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
144
|
interface BatchContext {
|
|
155
145
|
db: import("bun:sqlite").Database;
|
|
156
146
|
stats: VectorStatsPort;
|
|
@@ -506,28 +496,6 @@ export async function embed(options: EmbedOptions = {}): Promise<EmbedResult> {
|
|
|
506
496
|
const stats: VectorStatsPort = createVectorStatsPort(db);
|
|
507
497
|
|
|
508
498
|
let totalToEmbed = 0;
|
|
509
|
-
if (force) {
|
|
510
|
-
const forceCount = await getActiveChunkCount(db, options.collection);
|
|
511
|
-
if (!forceCount.ok) {
|
|
512
|
-
return { success: false, error: forceCount.error.message };
|
|
513
|
-
}
|
|
514
|
-
totalToEmbed = forceCount.value;
|
|
515
|
-
|
|
516
|
-
if (totalToEmbed === 0 || dryRun) {
|
|
517
|
-
const vecAvailable = await checkVecAvailable(db);
|
|
518
|
-
return {
|
|
519
|
-
success: true,
|
|
520
|
-
embedded: totalToEmbed,
|
|
521
|
-
errors: 0,
|
|
522
|
-
contentionErrors: 0,
|
|
523
|
-
duration: 0,
|
|
524
|
-
model: modelUri,
|
|
525
|
-
searchAvailable: vecAvailable,
|
|
526
|
-
errorSamples: [],
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
499
|
// Create LLM adapter and embedding port with auto-download
|
|
532
500
|
let offline = options.offline;
|
|
533
501
|
if (offline === undefined) {
|
|
@@ -585,12 +553,16 @@ export async function embed(options: EmbedOptions = {}): Promise<EmbedResult> {
|
|
|
585
553
|
process.stderr.write("\n");
|
|
586
554
|
}
|
|
587
555
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
556
|
+
const initializedPort = await embedPort.init();
|
|
557
|
+
if (!initializedPort.ok)
|
|
558
|
+
return { success: false, error: initializedPort.error.message };
|
|
559
|
+
let dimensions = embedPort.dimensions();
|
|
560
|
+
if (!embedPort.getIdentity?.()) {
|
|
561
|
+
const probeResult = await embedPort.embed("dimension probe");
|
|
562
|
+
if (!probeResult.ok)
|
|
563
|
+
return { success: false, error: probeResult.error.message };
|
|
564
|
+
dimensions = probeResult.value.length;
|
|
592
565
|
}
|
|
593
|
-
const dimensions = probeResult.value.length;
|
|
594
566
|
|
|
595
567
|
// Create vector index port
|
|
596
568
|
const vectorResult = await createVectorIndexPort(db, {
|
|
@@ -602,6 +574,70 @@ export async function embed(options: EmbedOptions = {}): Promise<EmbedResult> {
|
|
|
602
574
|
}
|
|
603
575
|
vectorIndex = vectorResult.value;
|
|
604
576
|
|
|
577
|
+
const prepared = await prepareEmbeddingBacklog({
|
|
578
|
+
statsPort: stats,
|
|
579
|
+
embedPort,
|
|
580
|
+
vectorIndex,
|
|
581
|
+
modelUri,
|
|
582
|
+
collection: options.collection,
|
|
583
|
+
batchSize,
|
|
584
|
+
force,
|
|
585
|
+
});
|
|
586
|
+
if (!prepared.ok)
|
|
587
|
+
return { success: false, error: prepared.error.message };
|
|
588
|
+
if (prepared.value.variantStore) {
|
|
589
|
+
totalToEmbed = countVariantBacklog(prepared.value);
|
|
590
|
+
const startedAt = Date.now();
|
|
591
|
+
if (dryRun)
|
|
592
|
+
return {
|
|
593
|
+
success: true,
|
|
594
|
+
embedded: totalToEmbed,
|
|
595
|
+
errors: 0,
|
|
596
|
+
contentionErrors: 0,
|
|
597
|
+
duration: 0,
|
|
598
|
+
model: modelUri,
|
|
599
|
+
searchAvailable: prepared.value.variantStore.searchAvailable,
|
|
600
|
+
errorSamples: [],
|
|
601
|
+
};
|
|
602
|
+
const processed = await embedBacklog({
|
|
603
|
+
...prepared.value,
|
|
604
|
+
onProgress: !options.json
|
|
605
|
+
? (embedded, errors) =>
|
|
606
|
+
process.stderr.write(
|
|
607
|
+
`\rEmbedded ${embedded}/${totalToEmbed} owners; ${errors} errors`
|
|
608
|
+
)
|
|
609
|
+
: undefined,
|
|
610
|
+
});
|
|
611
|
+
if (!options.json) process.stderr.write("\n");
|
|
612
|
+
if (!processed.ok)
|
|
613
|
+
return { success: false, error: processed.error.message };
|
|
614
|
+
return {
|
|
615
|
+
success: true,
|
|
616
|
+
...processed.value,
|
|
617
|
+
contentionErrors: processed.value.contentionErrors ?? 0,
|
|
618
|
+
duration: (Date.now() - startedAt) / 1000,
|
|
619
|
+
model: modelUri,
|
|
620
|
+
searchAvailable: prepared.value.variantStore.searchAvailable,
|
|
621
|
+
errorSamples: [],
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
if (force) {
|
|
625
|
+
const count = await getActiveChunkCount(db, options.collection);
|
|
626
|
+
if (!count.ok) return { success: false, error: count.error.message };
|
|
627
|
+
totalToEmbed = count.value;
|
|
628
|
+
if (dryRun || !totalToEmbed)
|
|
629
|
+
return {
|
|
630
|
+
success: true,
|
|
631
|
+
embedded: totalToEmbed,
|
|
632
|
+
errors: 0,
|
|
633
|
+
contentionErrors: 0,
|
|
634
|
+
duration: 0,
|
|
635
|
+
model: modelUri,
|
|
636
|
+
searchAvailable: vectorIndex.searchAvailable,
|
|
637
|
+
errorSamples: [],
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
605
641
|
if (!force) {
|
|
606
642
|
const embedFingerprint = getEmbeddingFingerprint({
|
|
607
643
|
modelUri,
|
|
@@ -773,7 +809,7 @@ function getActiveChunks(
|
|
|
773
809
|
const sql = after
|
|
774
810
|
? `
|
|
775
811
|
SELECT c.mirror_hash as mirrorHash, c.seq, c.text,
|
|
776
|
-
(SELECT d.title FROM documents d WHERE d.mirror_hash = c.mirror_hash AND d.active = 1 LIMIT 1) as title,
|
|
812
|
+
(SELECT d.title FROM documents d WHERE d.mirror_hash = c.mirror_hash AND d.active = 1 ORDER BY d.id LIMIT 1) as title,
|
|
777
813
|
'force' as reason
|
|
778
814
|
FROM content_chunks c
|
|
779
815
|
WHERE EXISTS (
|
|
@@ -786,7 +822,7 @@ function getActiveChunks(
|
|
|
786
822
|
`
|
|
787
823
|
: `
|
|
788
824
|
SELECT c.mirror_hash as mirrorHash, c.seq, c.text,
|
|
789
|
-
(SELECT d.title FROM documents d WHERE d.mirror_hash = c.mirror_hash AND d.active = 1 LIMIT 1) as title,
|
|
825
|
+
(SELECT d.title FROM documents d WHERE d.mirror_hash = c.mirror_hash AND d.active = 1 ORDER BY d.id LIMIT 1) as title,
|
|
790
826
|
'force' as reason
|
|
791
827
|
FROM content_chunks c
|
|
792
828
|
WHERE EXISTS (
|
package/src/cli/detach.ts
CHANGED
|
@@ -25,6 +25,7 @@ import type { ResidentStatus } from "../serve/status-model";
|
|
|
25
25
|
import { VERSION, resolveDirs } from "../app/constants";
|
|
26
26
|
import { toAbsolutePath } from "../config/paths";
|
|
27
27
|
import { atomicWrite } from "../core/file-ops";
|
|
28
|
+
import { RESIDENT_STOP_GRACE_MS } from "../core/shutdown-budget";
|
|
28
29
|
import { isResidentStatus } from "../serve/resident-status";
|
|
29
30
|
import { CliError } from "./errors";
|
|
30
31
|
|
|
@@ -877,7 +878,7 @@ export async function inspectForeignLive(options: {
|
|
|
877
878
|
export interface StopOptions {
|
|
878
879
|
kind: DetachKind;
|
|
879
880
|
pidFile: string;
|
|
880
|
-
/** Grace period for SIGTERM before we escalate to SIGKILL. Default
|
|
881
|
+
/** Grace period for SIGTERM before we escalate to SIGKILL. Default 12s. */
|
|
881
882
|
timeoutMs?: number;
|
|
882
883
|
/** Poll interval while waiting for the process to exit. Default 100ms. */
|
|
883
884
|
pollIntervalMs?: number;
|
|
@@ -921,7 +922,7 @@ async function waitForExit(
|
|
|
921
922
|
* unlinks stale pid-files it discovers on entry.
|
|
922
923
|
*/
|
|
923
924
|
export async function stopProcess(options: StopOptions): Promise<StopOutcome> {
|
|
924
|
-
const timeoutMs = options.timeoutMs ??
|
|
925
|
+
const timeoutMs = options.timeoutMs ?? RESIDENT_STOP_GRACE_MS;
|
|
925
926
|
const pollIntervalMs = options.pollIntervalMs ?? 100;
|
|
926
927
|
const killTimeoutMs = options.killTimeoutMs ?? 2_000;
|
|
927
928
|
const sleep = options.sleep ?? defaultSleep;
|
package/src/config/types.ts
CHANGED
|
@@ -425,9 +425,9 @@ export const ModelConfigSchema = z.object({
|
|
|
425
425
|
/** Model presets */
|
|
426
426
|
presets: z.array(ModelPresetSchema).default(DEFAULT_MODEL_PRESETS),
|
|
427
427
|
/** Model load timeout in ms */
|
|
428
|
-
loadTimeout: z.number().default(60_000),
|
|
429
|
-
/** Inference timeout in ms */
|
|
430
|
-
inferenceTimeout: z.number().default(30_000),
|
|
428
|
+
loadTimeout: z.number().int().min(1).max(2_147_483_647).default(60_000),
|
|
429
|
+
/** Inference timeout in ms, measured from native evaluation start. */
|
|
430
|
+
inferenceTimeout: z.number().int().min(1).max(2_147_483_647).default(30_000),
|
|
431
431
|
/** Context size used for query expansion generation */
|
|
432
432
|
expandContextSize: z.number().int().min(256).default(2_048),
|
|
433
433
|
/** Keep warm model TTL in ms (5 min) */
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
* Uses convertBuffer() with bytes for determinism.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { MarkItDown } from "markitdown-ts";
|
|
7
|
-
|
|
8
6
|
import type {
|
|
9
7
|
Converter,
|
|
10
8
|
ConvertInput,
|
|
@@ -12,6 +10,7 @@ import type {
|
|
|
12
10
|
ConvertWarning,
|
|
13
11
|
} from "../../types";
|
|
14
12
|
|
|
13
|
+
import { MarkItDown } from "../../../../vendor/converters/markitdown-ts";
|
|
15
14
|
import {
|
|
16
15
|
adapterError,
|
|
17
16
|
corruptError,
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
* Uses parseOffice() v7 API with Buffer for in-memory extraction.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { parseOffice } from "officeparser";
|
|
7
|
-
|
|
8
6
|
import type {
|
|
9
7
|
Converter,
|
|
10
8
|
ConvertInput,
|
|
@@ -12,6 +10,7 @@ import type {
|
|
|
12
10
|
ConvertWarning,
|
|
13
11
|
} from "../../types";
|
|
14
12
|
|
|
13
|
+
import { parseOffice } from "../../../../vendor/converters/officeparser";
|
|
15
14
|
import { adapterError, corruptError, tooLargeError } from "../../errors";
|
|
16
15
|
import { basenameWithoutExt } from "../../path";
|
|
17
16
|
import { ADAPTER_VERSIONS } from "../../versions";
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Centralized converter version tracking.
|
|
3
3
|
*
|
|
4
4
|
* Native converters use our own versioning.
|
|
5
|
-
* Adapter versions
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Run `bun pm ls markitdown-ts officeparser` to check current versions.
|
|
5
|
+
* Adapter versions identify upstream code and security-sensitive parser versions.
|
|
6
|
+
* Update them when changing the vendored distributions or parser dependencies.
|
|
7
|
+
* Upstream identities live in vendor/converters/upstream-manifest.json.
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
/** Native converter versions (our own) */
|
|
@@ -15,10 +14,9 @@ export const NATIVE_VERSIONS = {
|
|
|
15
14
|
} as const;
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
19
|
-
* Update these when running `bun update`.
|
|
17
|
+
* Include repaired parser versions so existing converted content is invalidated.
|
|
20
18
|
*/
|
|
21
19
|
export const ADAPTER_VERSIONS = {
|
|
22
|
-
"markitdown-ts": "0.0.
|
|
23
|
-
officeparser: "
|
|
20
|
+
"markitdown-ts": "0.0.10+xlsx.0.20.3",
|
|
21
|
+
officeparser: "7.8.0+pdfjs.6.3.289",
|
|
24
22
|
} as const;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Strict indexed-evidence loading for Context Capsule compilation. */
|
|
2
2
|
|
|
3
3
|
import type { EgressPolicy } from "../config/types";
|
|
4
|
+
import type { RequestHydration } from "../pipeline/hydration";
|
|
4
5
|
import type { SearchResults } from "../pipeline/types";
|
|
5
6
|
import type {
|
|
6
7
|
ActivationIndexSnapshot,
|
|
@@ -127,6 +128,7 @@ export interface ContextEvidenceProjectionContext {
|
|
|
127
128
|
|
|
128
129
|
export interface ContextEvidenceCompilerDeps<P> {
|
|
129
130
|
store: ContextEvidenceStore;
|
|
131
|
+
hydration?: Pick<RequestHydration, "getContentBatch" | "getChunksBatch">;
|
|
130
132
|
retrieve: (request: ContextRetrievalRequest) => Promise<SearchResults>;
|
|
131
133
|
projectCanonical: (
|
|
132
134
|
draft: ContextCanonicalPlanDraft<ContextEvidenceValue>,
|
|
@@ -329,7 +331,8 @@ const referenceDocument = (
|
|
|
329
331
|
export const materializeContextEvidenceCandidates = async (
|
|
330
332
|
store: ContextEvidenceStore,
|
|
331
333
|
candidates: ContextRetrievalCandidate[],
|
|
332
|
-
indexNameInput: string
|
|
334
|
+
indexNameInput: string,
|
|
335
|
+
hydration?: ContextEvidenceCompilerDeps<unknown>["hydration"]
|
|
333
336
|
): Promise<ContextMaterialization<ContextEvidenceValue>[]> => {
|
|
334
337
|
if (candidates.length === 0) return [];
|
|
335
338
|
const indexName = canonicalizeIndexName(indexNameInput);
|
|
@@ -363,8 +366,8 @@ export const materializeContextEvidenceCandidates = async (
|
|
|
363
366
|
),
|
|
364
367
|
];
|
|
365
368
|
const [contentResult, chunksResult] = await Promise.all([
|
|
366
|
-
store.getContentBatch(mirrorHashes),
|
|
367
|
-
store.getChunksBatch(mirrorHashes),
|
|
369
|
+
(hydration ?? store).getContentBatch(mirrorHashes),
|
|
370
|
+
(hydration ?? store).getChunksBatch(mirrorHashes),
|
|
368
371
|
]);
|
|
369
372
|
const contentByHash = unwrapStore(
|
|
370
373
|
contentResult,
|
|
@@ -517,7 +520,8 @@ export const compileContextEvidence = async <P>(
|
|
|
517
520
|
materializeContextEvidenceCandidates(
|
|
518
521
|
deps.store,
|
|
519
522
|
candidates,
|
|
520
|
-
input.indexName
|
|
523
|
+
input.indexName,
|
|
524
|
+
deps.hydration
|
|
521
525
|
),
|
|
522
526
|
projectCanonical: (draft) => deps.projectCanonical(draft, fingerprints),
|
|
523
527
|
}
|
package/src/core/job-manager.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import type { SyncResult } from "../ingestion";
|
|
1
2
|
/**
|
|
2
3
|
* Background job manager for MCP write operations.
|
|
3
4
|
*
|
|
4
5
|
* @module src/core/job-manager
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
import
|
|
8
|
-
|
|
8
|
+
import {
|
|
9
|
+
assertInferenceActive,
|
|
10
|
+
withOwnedInferenceScope,
|
|
11
|
+
withBackgroundInference,
|
|
12
|
+
} from "../llm/inference-scope";
|
|
9
13
|
import { MCP_ERRORS } from "./errors";
|
|
10
14
|
import { acquireWriteLock, type WriteLockHandle } from "./file-lock";
|
|
11
15
|
|
|
@@ -78,7 +82,10 @@ export class JobManager {
|
|
|
78
82
|
#jobs = new Map<string, JobRecord>();
|
|
79
83
|
#jobAuthorizationEpochs = new Map<string, string>();
|
|
80
84
|
#activeJobs = new Set<Promise<void>>();
|
|
85
|
+
#jobControllers = new Map<string, AbortController>();
|
|
81
86
|
#authorizationEpoch = "egress-epoch-uninitialized";
|
|
87
|
+
#accepting = true;
|
|
88
|
+
#releaseJobLocks = new Map<string, () => Promise<void>>();
|
|
82
89
|
|
|
83
90
|
constructor(options: JobManagerOptions) {
|
|
84
91
|
this.#lockPath = options.lockPath;
|
|
@@ -89,8 +96,10 @@ export class JobManager {
|
|
|
89
96
|
|
|
90
97
|
async startJob(
|
|
91
98
|
type: JobType,
|
|
92
|
-
fn: () => Promise<SyncResult>
|
|
99
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>
|
|
93
100
|
): Promise<string> {
|
|
101
|
+
assertInferenceActive();
|
|
102
|
+
this.#assertAccepting();
|
|
94
103
|
this.#cleanupExpiredJobs();
|
|
95
104
|
|
|
96
105
|
if (this.#activeJobId) {
|
|
@@ -105,14 +114,21 @@ export class JobManager {
|
|
|
105
114
|
throw new JobError("LOCKED", MCP_ERRORS.LOCKED.message);
|
|
106
115
|
}
|
|
107
116
|
|
|
117
|
+
if (!this.#accepting) {
|
|
118
|
+
await lock.release();
|
|
119
|
+
this.#assertAccepting();
|
|
120
|
+
}
|
|
121
|
+
|
|
108
122
|
return this.#startJobWithLock(type, fn, lock);
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
async startJobWithLock(
|
|
112
126
|
type: JobType,
|
|
113
127
|
lock: WriteLockHandle,
|
|
114
|
-
fn: () => Promise<SyncResult>
|
|
128
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>
|
|
115
129
|
): Promise<string> {
|
|
130
|
+
assertInferenceActive();
|
|
131
|
+
this.#assertAccepting();
|
|
116
132
|
this.#cleanupExpiredJobs();
|
|
117
133
|
|
|
118
134
|
if (this.#activeJobId) {
|
|
@@ -132,8 +148,10 @@ export class JobManager {
|
|
|
132
148
|
async startTypedJobWithLock(
|
|
133
149
|
type: JobType,
|
|
134
150
|
lock: WriteLockHandle,
|
|
135
|
-
fn: () => Promise<JobResult>
|
|
151
|
+
fn: (signal: AbortSignal) => Promise<JobResult>
|
|
136
152
|
): Promise<string> {
|
|
153
|
+
assertInferenceActive();
|
|
154
|
+
this.#assertAccepting();
|
|
137
155
|
this.#cleanupExpiredJobs();
|
|
138
156
|
|
|
139
157
|
if (this.#activeJobId) {
|
|
@@ -205,10 +223,56 @@ export class JobManager {
|
|
|
205
223
|
return { active, recent };
|
|
206
224
|
}
|
|
207
225
|
|
|
226
|
+
/** Internal owner control; cancellation retains the existing failed job schema. */
|
|
227
|
+
cancelJob(jobId: string): boolean {
|
|
228
|
+
const controller = this.#jobControllers.get(jobId);
|
|
229
|
+
if (!controller) return false;
|
|
230
|
+
controller.abort();
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
208
234
|
async shutdown(): Promise<void> {
|
|
235
|
+
this.stop();
|
|
209
236
|
await Promise.allSettled(this.#activeJobs);
|
|
210
237
|
}
|
|
211
238
|
|
|
239
|
+
stop(): void {
|
|
240
|
+
this.#accepting = false;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
cancel(): void {
|
|
244
|
+
this.stop();
|
|
245
|
+
for (const controller of this.#jobControllers.values()) controller.abort();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Call only after the shared shutdown budget; late callbacks stay canceled. */
|
|
249
|
+
async failUnfinished(): Promise<void> {
|
|
250
|
+
this.cancel();
|
|
251
|
+
for (const job of this.#jobs.values()) {
|
|
252
|
+
if (job.status !== "running") continue;
|
|
253
|
+
job.status = "failed";
|
|
254
|
+
job.error = "Resident shutdown deadline exceeded";
|
|
255
|
+
job.completedAt = Date.now();
|
|
256
|
+
}
|
|
257
|
+
await Promise.allSettled(
|
|
258
|
+
Array.from(this.#releaseJobLocks.values(), (release) => release())
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
#assertAccepting(): void {
|
|
263
|
+
if (!this.#accepting) throw new Error("Resident runtime is shutting down");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
#ownLock(jobId: string, lock: WriteLockHandle): WriteLockHandle {
|
|
267
|
+
let releasing: Promise<void> | undefined;
|
|
268
|
+
const owned = {
|
|
269
|
+
release: () =>
|
|
270
|
+
(releasing ??= Promise.resolve().then(() => lock.release())),
|
|
271
|
+
};
|
|
272
|
+
this.#releaseJobLocks.set(jobId, owned.release);
|
|
273
|
+
return owned;
|
|
274
|
+
}
|
|
275
|
+
|
|
212
276
|
#track(jobPromise: Promise<void>): void {
|
|
213
277
|
const tracked = jobPromise.catch(() => undefined);
|
|
214
278
|
this.#activeJobs.add(tracked);
|
|
@@ -219,14 +283,16 @@ export class JobManager {
|
|
|
219
283
|
|
|
220
284
|
async #runJob(
|
|
221
285
|
job: JobRecord,
|
|
222
|
-
fn: () => Promise<SyncResult>,
|
|
286
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>,
|
|
223
287
|
lock: { release: () => Promise<void> }
|
|
224
288
|
): Promise<void> {
|
|
225
289
|
try {
|
|
226
290
|
const release = await this.#toolMutex.acquire();
|
|
227
291
|
try {
|
|
228
292
|
this.#assertAuthorizationEpoch(job);
|
|
229
|
-
|
|
293
|
+
assertInferenceActive();
|
|
294
|
+
const result = await fn(this.#jobControllers.get(job.id)!.signal);
|
|
295
|
+
assertInferenceActive();
|
|
230
296
|
job.status = "completed";
|
|
231
297
|
job.result = result;
|
|
232
298
|
} catch (e) {
|
|
@@ -239,6 +305,8 @@ export class JobManager {
|
|
|
239
305
|
job.status = "failed";
|
|
240
306
|
job.error = e instanceof Error ? e.message : String(e);
|
|
241
307
|
} finally {
|
|
308
|
+
this.#releaseJobLocks.delete(job.id);
|
|
309
|
+
this.#jobControllers.delete(job.id);
|
|
242
310
|
job.completedAt = Date.now();
|
|
243
311
|
this.#activeJobId = null;
|
|
244
312
|
await lock.release().catch(() => undefined);
|
|
@@ -248,10 +316,11 @@ export class JobManager {
|
|
|
248
316
|
|
|
249
317
|
#startJobWithLock(
|
|
250
318
|
type: JobType,
|
|
251
|
-
fn: () => Promise<SyncResult>,
|
|
319
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>,
|
|
252
320
|
lock: WriteLockHandle
|
|
253
321
|
): string {
|
|
254
322
|
const jobId = crypto.randomUUID();
|
|
323
|
+
const ownedLock = this.#ownLock(jobId, lock);
|
|
255
324
|
const job: JobRecord = {
|
|
256
325
|
id: jobId,
|
|
257
326
|
type,
|
|
@@ -260,11 +329,15 @@ export class JobManager {
|
|
|
260
329
|
serverInstanceId: this.#serverInstanceId,
|
|
261
330
|
};
|
|
262
331
|
|
|
332
|
+
this.#jobControllers.set(jobId, new AbortController());
|
|
263
333
|
this.#jobs.set(jobId, job);
|
|
264
334
|
this.#jobAuthorizationEpochs.set(jobId, this.#authorizationEpoch);
|
|
265
335
|
this.#activeJobId = jobId;
|
|
266
336
|
|
|
267
|
-
const jobPromise =
|
|
337
|
+
const jobPromise = withOwnedInferenceScope(
|
|
338
|
+
{ signal: this.#jobControllers.get(jobId)!.signal },
|
|
339
|
+
() => withBackgroundInference(() => this.#runJob(job, fn, ownedLock))
|
|
340
|
+
);
|
|
268
341
|
this.#track(jobPromise);
|
|
269
342
|
|
|
270
343
|
return jobId;
|
|
@@ -272,10 +345,11 @@ export class JobManager {
|
|
|
272
345
|
|
|
273
346
|
#startTypedJobWithLock(
|
|
274
347
|
type: JobType,
|
|
275
|
-
fn: () => Promise<JobResult>,
|
|
348
|
+
fn: (signal: AbortSignal) => Promise<JobResult>,
|
|
276
349
|
lock: WriteLockHandle
|
|
277
350
|
): string {
|
|
278
351
|
const jobId = crypto.randomUUID();
|
|
352
|
+
const ownedLock = this.#ownLock(jobId, lock);
|
|
279
353
|
const job: JobRecord = {
|
|
280
354
|
id: jobId,
|
|
281
355
|
type,
|
|
@@ -284,11 +358,15 @@ export class JobManager {
|
|
|
284
358
|
serverInstanceId: this.#serverInstanceId,
|
|
285
359
|
};
|
|
286
360
|
|
|
361
|
+
this.#jobControllers.set(jobId, new AbortController());
|
|
287
362
|
this.#jobs.set(jobId, job);
|
|
288
363
|
this.#jobAuthorizationEpochs.set(jobId, this.#authorizationEpoch);
|
|
289
364
|
this.#activeJobId = jobId;
|
|
290
365
|
|
|
291
|
-
const jobPromise =
|
|
366
|
+
const jobPromise = withOwnedInferenceScope(
|
|
367
|
+
{ signal: this.#jobControllers.get(jobId)!.signal },
|
|
368
|
+
() => withBackgroundInference(() => this.#runTypedJob(job, fn, ownedLock))
|
|
369
|
+
);
|
|
292
370
|
this.#track(jobPromise);
|
|
293
371
|
|
|
294
372
|
return jobId;
|
|
@@ -296,14 +374,16 @@ export class JobManager {
|
|
|
296
374
|
|
|
297
375
|
async #runTypedJob(
|
|
298
376
|
job: JobRecord,
|
|
299
|
-
fn: () => Promise<JobResult>,
|
|
377
|
+
fn: (signal: AbortSignal) => Promise<JobResult>,
|
|
300
378
|
lock: { release: () => Promise<void> }
|
|
301
379
|
): Promise<void> {
|
|
302
380
|
try {
|
|
303
381
|
const release = await this.#toolMutex.acquire();
|
|
304
382
|
try {
|
|
305
383
|
this.#assertAuthorizationEpoch(job);
|
|
306
|
-
|
|
384
|
+
assertInferenceActive();
|
|
385
|
+
const result = await fn(this.#jobControllers.get(job.id)!.signal);
|
|
386
|
+
assertInferenceActive();
|
|
307
387
|
job.status = "completed";
|
|
308
388
|
job.typedResult = result;
|
|
309
389
|
} catch (e) {
|
|
@@ -316,6 +396,8 @@ export class JobManager {
|
|
|
316
396
|
job.status = "failed";
|
|
317
397
|
job.error = e instanceof Error ? e.message : String(e);
|
|
318
398
|
} finally {
|
|
399
|
+
this.#releaseJobLocks.delete(job.id);
|
|
400
|
+
this.#jobControllers.delete(job.id);
|
|
319
401
|
job.completedAt = Date.now();
|
|
320
402
|
this.#activeJobId = null;
|
|
321
403
|
await lock.release().catch(() => undefined);
|
|
@@ -149,6 +149,16 @@ export const NETWORK_BOUNDARY_INVENTORY = [
|
|
|
149
149
|
action: "remote_inference",
|
|
150
150
|
enforcement: "collection_policy",
|
|
151
151
|
},
|
|
152
|
+
{
|
|
153
|
+
// Collection text crosses owned local IPC only. The child receives approved
|
|
154
|
+
// model paths and a restricted environment with downloads/builds disabled.
|
|
155
|
+
id: "native-inference-worker",
|
|
156
|
+
key: "src/llm/native-worker/client.ts::child_process#1",
|
|
157
|
+
path: "src/llm/native-worker/client.ts",
|
|
158
|
+
primitive: "child_process",
|
|
159
|
+
action: null,
|
|
160
|
+
enforcement: "local_process_only",
|
|
161
|
+
},
|
|
152
162
|
{
|
|
153
163
|
id: "pinned-http-fetch",
|
|
154
164
|
key: "src/llm/pinned-http-connection.ts::fetch#1",
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Internal resident shutdown clock. Every participant shares these deadlines. */
|
|
2
|
+
export const SHUTDOWN_DRAIN_MS = 5_000;
|
|
3
|
+
export const SHUTDOWN_ABORT_MS = 5_000;
|
|
4
|
+
export const SHUTDOWN_EXIT_MS = 1_000;
|
|
5
|
+
// The detached parent must not be killed before it can reap its native child.
|
|
6
|
+
export const RESIDENT_STOP_GRACE_MS = 12_000;
|
|
7
|
+
|
|
8
|
+
/** Observe settlement without abandoning rejection handling or retaining a timer. */
|
|
9
|
+
export async function settlesBy(
|
|
10
|
+
work: Promise<unknown>,
|
|
11
|
+
deadline: number,
|
|
12
|
+
interrupt?: AbortSignal
|
|
13
|
+
): Promise<boolean> {
|
|
14
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
15
|
+
let interrupted: (() => void) | undefined;
|
|
16
|
+
try {
|
|
17
|
+
return await Promise.race([
|
|
18
|
+
work.then(() => true),
|
|
19
|
+
new Promise<false>((resolve) => {
|
|
20
|
+
interrupted = () => resolve(false);
|
|
21
|
+
interrupt?.addEventListener("abort", interrupted, { once: true });
|
|
22
|
+
if (interrupt?.aborted) resolve(false);
|
|
23
|
+
timer = setTimeout(
|
|
24
|
+
() => resolve(false),
|
|
25
|
+
Math.max(0, deadline - performance.now())
|
|
26
|
+
);
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
} finally {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
if (interrupted) interrupt?.removeEventListener("abort", interrupted);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function shutdownDuration(
|
|
36
|
+
value: number | undefined,
|
|
37
|
+
fallback: number
|
|
38
|
+
): number {
|
|
39
|
+
const duration = value ?? fallback;
|
|
40
|
+
if (!Number.isSafeInteger(duration) || duration < 0)
|
|
41
|
+
throw new RangeError(
|
|
42
|
+
"Shutdown duration must be a nonnegative finite integer"
|
|
43
|
+
);
|
|
44
|
+
return duration;
|
|
45
|
+
}
|