@inflexa-ai/harness 0.31.1 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/conversation-agent.d.ts +15 -0
- package/dist/agents/conversation-agent.js +16 -6
- package/dist/agents/report-session-agent.d.ts +9 -0
- package/dist/agents/report-session-agent.js +10 -2
- package/dist/agents/sandbox/shared.d.ts +13 -1
- package/dist/agents/sandbox/shared.js +22 -5
- package/dist/app/chat-turn.d.ts +11 -0
- package/dist/app/chat-turn.js +17 -1
- package/dist/app/spawn-report-session.d.ts +12 -0
- package/dist/app/spawn-report-session.js +21 -1
- package/dist/config/environment-stores.d.ts +53 -5
- package/dist/contracts/report-blocks.d.ts +8 -8
- package/dist/contracts/schemas/chat-parts.d.ts +6 -6
- package/dist/index.d.ts +8 -1
- package/dist/index.js +11 -0
- package/dist/prompts/briefing.d.ts +1 -1
- package/dist/prompts/briefing.js +4 -0
- package/dist/prompts/planner.js +13 -0
- package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.js +5 -5
- package/dist/prompts/sandbox/network-agent.d.ts +1 -1
- package/dist/prompts/sandbox/network-agent.js +4 -3
- package/dist/prompts/sandbox-standards.d.ts +20 -0
- package/dist/prompts/sandbox-standards.js +65 -0
- package/dist/provenance/seam.d.ts +203 -0
- package/dist/provenance/seam.js +71 -0
- package/dist/reference-data/catalog.js +11 -9
- package/dist/report-model/authoring-grammar.d.ts +2 -2
- package/dist/report-render/assets.d.ts +10 -0
- package/dist/report-render/assets.js +14 -0
- package/dist/report-render/design.js +256 -0
- package/dist/report-render/page.d.ts +75 -0
- package/dist/report-render/page.js +793 -1
- package/dist/report-render/provenance-data.d.ts +42 -0
- package/dist/report-render/provenance-data.js +62 -0
- package/dist/report-render/render.d.ts +20 -1
- package/dist/report-render/render.js +23 -10
- package/dist/report-render/types.d.ts +3 -0
- package/dist/report-render/views/chart-view.d.ts +5 -1
- package/dist/report-render/views/chart-view.js +6 -2
- package/dist/report-render/views/lineage.d.ts +93 -0
- package/dist/report-render/views/lineage.js +86 -0
- package/dist/report-render/views/page-view.d.ts +22 -1
- package/dist/report-render/views/page-view.js +12 -3
- package/dist/report-render/views/prose.d.ts +7 -1
- package/dist/report-render/views/prose.js +10 -6
- package/dist/report-render/views/references-view.d.ts +17 -1
- package/dist/report-render/views/references-view.js +12 -4
- package/dist/report-render/views/values.d.ts +17 -4
- package/dist/report-render/views/values.js +21 -8
- package/dist/runtime/assemble.d.ts +22 -0
- package/dist/runtime/assemble.js +4 -0
- package/dist/sandbox/create-sandbox.d.ts +20 -4
- package/dist/sandbox/create-sandbox.js +4 -0
- package/dist/sandbox/docker-client.d.ts +16 -6
- package/dist/sandbox/docker-client.js +47 -31
- package/dist/sandbox/farm.d.ts +95 -0
- package/dist/sandbox/farm.js +127 -0
- package/dist/sandbox/k8s-client.d.ts +24 -10
- package/dist/sandbox/k8s-client.js +85 -122
- package/dist/sandbox/mount-plan.d.ts +23 -1
- package/dist/sandbox/mount-plan.js +44 -7
- package/dist/sandbox/sandbox-error.d.ts +12 -0
- package/dist/sandbox/sandbox-error.js +2 -0
- package/dist/sandbox/types.d.ts +118 -0
- package/dist/schemas/artifact-manifest.d.ts +4 -4
- package/dist/schemas/plan-schemas.d.ts +3 -0
- package/dist/schemas/plan-schemas.js +1 -1
- package/dist/schemas/validate-plan.js +20 -1
- package/dist/schemas/workflow-state.d.ts +4 -0
- package/dist/schemas/workflow-state.js +10 -0
- package/dist/tasks/data-profile.d.ts +15 -0
- package/dist/tasks/data-profile.js +36 -26
- package/dist/tools/display/show-user.d.ts +1 -1
- package/dist/tools/execute-analysis.d.ts +18 -0
- package/dist/tools/execute-analysis.js +87 -0
- package/dist/tools/report-authoring/authoring-tools.d.ts +16 -1
- package/dist/tools/report-authoring/authoring-tools.js +58 -16
- package/dist/tools/report-session/derive-table.d.ts +3 -0
- package/dist/tools/report-session/derive-table.js +15 -0
- package/dist/tools/report-session/preview-report.d.ts +13 -4
- package/dist/tools/report-session/preview-report.js +23 -6
- package/dist/tools/report-session/record-version.d.ts +3 -0
- package/dist/tools/report-session/record-version.js +7 -3
- package/dist/tools/research/generate-plan.js +12 -2
- package/dist/tools/sandbox/index.d.ts +1 -0
- package/dist/tools/sandbox/index.js +1 -0
- package/dist/tools/sandbox/link-packages.d.ts +27 -0
- package/dist/tools/sandbox/link-packages.js +52 -0
- package/dist/tools/sandbox/list-available-packages.d.ts +50 -30
- package/dist/tools/sandbox/list-available-packages.js +131 -40
- package/dist/tools/start-report-session.d.ts +7 -0
- package/dist/tools/start-report-session.js +1 -0
- package/dist/workflows/execute-analysis.d.ts +15 -69
- package/dist/workflows/execute-analysis.js +5 -4
- package/package.json +2 -1
|
@@ -16,10 +16,26 @@ import { type DerivationChains, type ReferenceLedger } from "../references.js";
|
|
|
16
16
|
*
|
|
17
17
|
* A bracket reads as a reference inside prose, and it stays a span beside the words. One notation serves
|
|
18
18
|
* every kind, thus one list answers every marker.
|
|
19
|
+
*
|
|
20
|
+
* Every grounded kind renders its marker here. Thus the lineage control has one emission point, and a
|
|
21
|
+
* marker that names no place carries no control. The page shows the control only where a stamp gives the
|
|
22
|
+
* script a key to walk.
|
|
19
23
|
*/
|
|
20
|
-
export declare function Marker({ n }: {
|
|
24
|
+
export declare function Marker({ n, lineage }: {
|
|
21
25
|
n: number;
|
|
26
|
+
lineage?: number;
|
|
22
27
|
}): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
28
|
+
/**
|
|
29
|
+
* The count of hash characters that a chain line shows.
|
|
30
|
+
*
|
|
31
|
+
* A content hash is 64 hex characters, and a line that carries three whole ones reads as noise. The head
|
|
32
|
+
* identifies the bytes, and it matches the count that a staged file name carries. Thus a reader compares the
|
|
33
|
+
* two by sight.
|
|
34
|
+
*
|
|
35
|
+
* The appendix line and the hop of the lineage popover both cut a hash to this count. Thus one hash reads
|
|
36
|
+
* the same in the two places.
|
|
37
|
+
*/
|
|
38
|
+
export declare const CHAIN_HASH_CHARS = 12;
|
|
23
39
|
/**
|
|
24
40
|
* The one appendix list: one entry for each distinct reference of the page, in the order of the ladder.
|
|
25
41
|
*
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
|
|
2
2
|
import { citationRecordOf } from "../../report-model/reference-resolver.js";
|
|
3
3
|
import { citationKeyOf } from "../references.js";
|
|
4
|
+
import { LineageControl } from "./lineage.js";
|
|
4
5
|
/**
|
|
5
6
|
* One evidence marker as a bracket number that links to its appendix entry.
|
|
6
7
|
*
|
|
7
8
|
* A bracket reads as a reference inside prose, and it stays a span beside the words. One notation serves
|
|
8
9
|
* every kind, thus one list answers every marker.
|
|
10
|
+
*
|
|
11
|
+
* Every grounded kind renders its marker here. Thus the lineage control has one emission point, and a
|
|
12
|
+
* marker that names no place carries no control. The page shows the control only where a stamp gives the
|
|
13
|
+
* script a key to walk.
|
|
9
14
|
*/
|
|
10
|
-
export function Marker({ n }) {
|
|
11
|
-
return (
|
|
15
|
+
export function Marker({ n, lineage }) {
|
|
16
|
+
return (_jsxs("span", { class: "report-marker", children: [_jsx("a", { href: `#ref-${n}`, children: `[${n}]` }), lineage !== undefined ? _jsx(LineageControl, { place: lineage }) : null] }));
|
|
12
17
|
}
|
|
13
18
|
/** The kind label of one reference entry. */
|
|
14
19
|
function RefKind({ children }) {
|
|
@@ -32,8 +37,11 @@ function HashCode({ children }) {
|
|
|
32
37
|
* A content hash is 64 hex characters, and a line that carries three whole ones reads as noise. The head
|
|
33
38
|
* identifies the bytes, and it matches the count that a staged file name carries. Thus a reader compares the
|
|
34
39
|
* two by sight.
|
|
40
|
+
*
|
|
41
|
+
* The appendix line and the hop of the lineage popover both cut a hash to this count. Thus one hash reads
|
|
42
|
+
* the same in the two places.
|
|
35
43
|
*/
|
|
36
|
-
const CHAIN_HASH_CHARS = 12;
|
|
44
|
+
export const CHAIN_HASH_CHARS = 12;
|
|
37
45
|
/** The head of one content hash: the hex after the algorithm name, cut to the shown length. */
|
|
38
46
|
function hashHead(hash) {
|
|
39
47
|
return hash.slice(hash.lastIndexOf(":") + 1).slice(0, CHAIN_HASH_CHARS);
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
import type { CitationBlock, FigureBlock, MetricBlock, TableBlock } from "../../contracts/report-blocks.js";
|
|
27
27
|
import { type ArtifactTableReference } from "../../contracts/report-reference.js";
|
|
28
28
|
import type { CitationRecord } from "../../report-model/reference-resolver.js";
|
|
29
|
+
import { type ViewOptions } from "./lineage.js";
|
|
29
30
|
import { type ReferenceLedger } from "../references.js";
|
|
30
31
|
import type { ColumnDisplay } from "../table-data.js";
|
|
31
32
|
import type { RenderValue } from "../types.js";
|
|
@@ -76,8 +77,11 @@ type FigureValue = Extract<RenderValue, {
|
|
|
76
77
|
* The value binding joins the reference ladder, thus the label line carries the marker and the appendix
|
|
77
78
|
* names the cell. The marker sits on the label and never on the value, because the value line is the one
|
|
78
79
|
* figure that a reader takes from the card.
|
|
80
|
+
*
|
|
81
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps its keys, and the
|
|
82
|
+
* marker carries the control that opens the chain.
|
|
79
83
|
*/
|
|
80
|
-
export declare function renderMetric(block: MetricBlock, ledger: ReferenceLedger, value: ScalarValue): string;
|
|
84
|
+
export declare function renderMetric(block: MetricBlock, ledger: ReferenceLedger, value: ScalarValue, view?: ViewOptions): string;
|
|
81
85
|
/**
|
|
82
86
|
* Wrap a run of stat cards in one responsive grid. The caller renders each card first, and it passes the
|
|
83
87
|
* markup as one already-escaped string, thus `raw()` inserts it byte for byte. The grid carries its own
|
|
@@ -141,8 +145,11 @@ export declare function tableStatusText(shown: number, total: number): string;
|
|
|
141
145
|
* The whole-table binding joins the reference ladder, thus the title line carries the marker and the
|
|
142
146
|
* appendix names the artifact. Every evidentiary block ledgers this way, and a card with no title still
|
|
143
147
|
* shows its marker on the same line.
|
|
148
|
+
*
|
|
149
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps its keys, and the
|
|
150
|
+
* marker carries the control that opens the chain.
|
|
144
151
|
*/
|
|
145
|
-
export declare function renderTable(block: TableBlock, ledger: ReferenceLedger, rowCount: number, total?: number): string;
|
|
152
|
+
export declare function renderTable(block: TableBlock, ledger: ReferenceLedger, rowCount: number, total?: number, view?: ViewOptions): string;
|
|
146
153
|
/**
|
|
147
154
|
* Render a figure block as a corner-accent card. The source rides the `src` attribute, and the caption
|
|
148
155
|
* renders below the image. The caption also fills the `alt` attribute, thus the escape keeps a hostile
|
|
@@ -151,8 +158,11 @@ export declare function renderTable(block: TableBlock, ledger: ReferenceLedger,
|
|
|
151
158
|
* The whole-file binding joins the reference ladder, thus the caption line carries the marker and the
|
|
152
159
|
* appendix names the image. A figure with no caption still shows its marker on that line. The marker stays
|
|
153
160
|
* out of the `alt` text, because a screen reader reads the alt as the picture and not as a footnote.
|
|
161
|
+
*
|
|
162
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps its keys, and the
|
|
163
|
+
* marker carries the control that opens the chain.
|
|
154
164
|
*/
|
|
155
|
-
export declare function renderFigure(block: FigureBlock, ledger: ReferenceLedger, value: FigureValue): string;
|
|
165
|
+
export declare function renderFigure(block: FigureBlock, ledger: ReferenceLedger, value: FigureValue, view?: ViewOptions): string;
|
|
156
166
|
/**
|
|
157
167
|
* Render a citation block as a bibliography card. The binding joins the one reference ladder like a claim
|
|
158
168
|
* binding, thus one shared source keeps one bracket number. The card shows the marker, the short citation
|
|
@@ -161,6 +171,9 @@ export declare function renderFigure(block: FigureBlock, ledger: ReferenceLedger
|
|
|
161
171
|
* The short citation of a `pmid:` record carries the PubMed link of its identifier. A key of another
|
|
162
172
|
* identifier space shows the citation as text. A key with no pinned record shows the key and the note
|
|
163
173
|
* alone, because absence is a normal condition and no text stands in for the paper.
|
|
174
|
+
*
|
|
175
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps the identity of
|
|
176
|
+
* the external record in place of a pin, because a paper is no artifact and no data chain reaches it.
|
|
164
177
|
*/
|
|
165
|
-
export declare function renderCitation(block: CitationBlock, ledger: ReferenceLedger, record?: CitationRecord): string;
|
|
178
|
+
export declare function renderCitation(block: CitationBlock, ledger: ReferenceLedger, record?: CitationRecord, view?: ViewOptions): string;
|
|
166
179
|
export {};
|
|
@@ -27,6 +27,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-
|
|
|
27
27
|
import { raw } from "hono/html";
|
|
28
28
|
import { declaredForColumn } from "../../contracts/report-reference.js";
|
|
29
29
|
import { stagedSource, tableSidecarName } from "../assets.js";
|
|
30
|
+
import { DEFAULT_VIEW_OPTIONS, lineagePlace, lineageStamp } from "./lineage.js";
|
|
30
31
|
import { Marker } from "./references-view.js";
|
|
31
32
|
import { formatNumberCell, formatTableCell, holdsANumber, selectColumnKind, selectNumberKind, smallestPositiveValue } from "../number-format.js";
|
|
32
33
|
import { citationKeyOf } from "../references.js";
|
|
@@ -67,11 +68,14 @@ const DOWNLOAD_LABEL = "Download";
|
|
|
67
68
|
* The value binding joins the reference ladder, thus the label line carries the marker and the appendix
|
|
68
69
|
* names the cell. The marker sits on the label and never on the value, because the value line is the one
|
|
69
70
|
* figure that a reader takes from the card.
|
|
71
|
+
*
|
|
72
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps its keys, and the
|
|
73
|
+
* marker carries the control that opens the chain.
|
|
70
74
|
*/
|
|
71
|
-
export function renderMetric(block, ledger, value) {
|
|
75
|
+
export function renderMetric(block, ledger, value, view = DEFAULT_VIEW_OPTIONS) {
|
|
72
76
|
const n = ledger.mark(block.value);
|
|
73
77
|
const shown = formatNumberCell(value.value, selectNumberKind(block.label, value.value));
|
|
74
|
-
return String(_jsxs("div", { class: "stat-card corner-accents", children: [_jsx("div", { class: "stat-card-value", title: shown.full, children: shown.text }), _jsxs("div", { class: "stat-card-label", children: [block.label, _jsx(Marker, { n: n })] })] }));
|
|
78
|
+
return String(_jsxs("div", { class: "stat-card corner-accents", ...lineageStamp(view.lineage, block.id, [block.value]), children: [_jsx("div", { class: "stat-card-value", title: shown.full, children: shown.text }), _jsxs("div", { class: "stat-card-label", children: [block.label, _jsx(Marker, { n: n, lineage: lineagePlace(view.lineage, block.value) })] })] }));
|
|
75
79
|
}
|
|
76
80
|
/**
|
|
77
81
|
* Wrap a run of stat cards in one responsive grid. The caller renders each card first, and it passes the
|
|
@@ -199,13 +203,16 @@ export function tableStatusText(shown, total) {
|
|
|
199
203
|
* The whole-table binding joins the reference ladder, thus the title line carries the marker and the
|
|
200
204
|
* appendix names the artifact. Every evidentiary block ledgers this way, and a card with no title still
|
|
201
205
|
* shows its marker on the same line.
|
|
206
|
+
*
|
|
207
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps its keys, and the
|
|
208
|
+
* marker carries the control that opens the chain.
|
|
202
209
|
*/
|
|
203
|
-
export function renderTable(block, ledger, rowCount, total) {
|
|
210
|
+
export function renderTable(block, ledger, rowCount, total, view = DEFAULT_VIEW_OPTIONS) {
|
|
204
211
|
const binding = block.binding;
|
|
205
212
|
const n = ledger.mark(binding);
|
|
206
213
|
const download = tableSidecarName(binding.hash, binding.path);
|
|
207
214
|
const bound = boundText(binding);
|
|
208
|
-
return String(_jsxs("div", { class: "report-table", children: [_jsxs("div", { class: "report-table-title", children: [block.title, _jsx(Marker, { n: n })] }), _jsxs("div", { class: "corner-accents", children: [_jsx("div", { class: "report-grid", [GRID_MOUNT_ATTRIBUTE]: block.id }), _jsxs("div", { class: "report-table-footer", children: [_jsxs("div", { class: "report-table-footer-row", children: [_jsxs("span", { class: "report-table-status", children: [_jsx("span", { class: GRID_COUNT_CLASS, children: tableStatusText(rowCount, total ?? rowCount) }), bound !== undefined ? _jsx("span", { class: "report-table-bound", children: bound }) : null] }), _jsx("a", { class: "report-table-download", href: stagedSource(download), download: download, children: downloadLabel(binding.path) })] }), _jsx("div", { class: GRID_NOTE_CLASS })] })] }), block.caption !== undefined ? _jsx("p", { class: "report-caption", children: block.caption }) : null] }));
|
|
215
|
+
return String(_jsxs("div", { class: "report-table", ...lineageStamp(view.lineage, block.id, [binding]), children: [_jsxs("div", { class: "report-table-title", children: [block.title, _jsx(Marker, { n: n, lineage: lineagePlace(view.lineage, binding) })] }), _jsxs("div", { class: "corner-accents", children: [_jsx("div", { class: "report-grid", [GRID_MOUNT_ATTRIBUTE]: block.id }), _jsxs("div", { class: "report-table-footer", children: [_jsxs("div", { class: "report-table-footer-row", children: [_jsxs("span", { class: "report-table-status", children: [_jsx("span", { class: GRID_COUNT_CLASS, children: tableStatusText(rowCount, total ?? rowCount) }), bound !== undefined ? _jsx("span", { class: "report-table-bound", children: bound }) : null] }), _jsx("a", { class: "report-table-download", href: stagedSource(download), download: download, children: downloadLabel(binding.path) })] }), _jsx("div", { class: GRID_NOTE_CLASS })] })] }), block.caption !== undefined ? _jsx("p", { class: "report-caption", children: block.caption }) : null] }));
|
|
209
216
|
}
|
|
210
217
|
/**
|
|
211
218
|
* Render a figure block as a corner-accent card. The source rides the `src` attribute, and the caption
|
|
@@ -215,11 +222,14 @@ export function renderTable(block, ledger, rowCount, total) {
|
|
|
215
222
|
* The whole-file binding joins the reference ladder, thus the caption line carries the marker and the
|
|
216
223
|
* appendix names the image. A figure with no caption still shows its marker on that line. The marker stays
|
|
217
224
|
* out of the `alt` text, because a screen reader reads the alt as the picture and not as a footnote.
|
|
225
|
+
*
|
|
226
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps its keys, and the
|
|
227
|
+
* marker carries the control that opens the chain.
|
|
218
228
|
*/
|
|
219
|
-
export function renderFigure(block, ledger, value) {
|
|
229
|
+
export function renderFigure(block, ledger, value, view = DEFAULT_VIEW_OPTIONS) {
|
|
220
230
|
const n = ledger.mark(block.binding);
|
|
221
231
|
const caption = block.caption;
|
|
222
|
-
return String(_jsxs("figure", { class: "report-figure corner-accents", children: [_jsx("img", { src: value.src, alt: caption !== undefined ? caption : "", class: "report-figure-image" }), _jsxs("figcaption", { class: "report-caption", children: [caption, _jsx(Marker, { n: n })] })] }));
|
|
232
|
+
return String(_jsxs("figure", { class: "report-figure corner-accents", ...lineageStamp(view.lineage, block.id, [block.binding]), children: [_jsx("img", { src: value.src, alt: caption !== undefined ? caption : "", class: "report-figure-image" }), _jsxs("figcaption", { class: "report-caption", children: [caption, _jsx(Marker, { n: n, lineage: lineagePlace(view.lineage, block.binding) })] })] }));
|
|
223
233
|
}
|
|
224
234
|
/**
|
|
225
235
|
* The PubMed address of one identifier. The address is deterministic, and an anchor loads nothing, thus a
|
|
@@ -234,10 +244,13 @@ const PUBMED_BASE = "https://pubmed.ncbi.nlm.nih.gov/";
|
|
|
234
244
|
* The short citation of a `pmid:` record carries the PubMed link of its identifier. A key of another
|
|
235
245
|
* identifier space shows the citation as text. A key with no pinned record shows the key and the note
|
|
236
246
|
* alone, because absence is a normal condition and no text stands in for the paper.
|
|
247
|
+
*
|
|
248
|
+
* `view.lineage` states that the page carries a provenance document. The card then stamps the identity of
|
|
249
|
+
* the external record in place of a pin, because a paper is no artifact and no data chain reaches it.
|
|
237
250
|
*/
|
|
238
|
-
export function renderCitation(block, ledger, record) {
|
|
251
|
+
export function renderCitation(block, ledger, record, view = DEFAULT_VIEW_OPTIONS) {
|
|
239
252
|
const n = ledger.mark(block.binding);
|
|
240
253
|
const binding = block.binding;
|
|
241
254
|
const key = citationKeyOf(binding);
|
|
242
|
-
return String(_jsxs("div", { class: "report-citation corner-accents", children: [_jsx(Marker, { n: n }), record !== undefined ? (_jsxs(_Fragment, { children: [" ", binding.idKind === "pmid" ? (_jsx("a", { class: "report-citation-source", href: `${PUBMED_BASE}${encodeURIComponent(binding.id)}/`, children: record.citation })) : (_jsx("span", { class: "report-citation-source", children: record.citation }))] })) : null, block.note !== undefined ? (_jsxs(_Fragment, { children: [" ", _jsx("span", { class: "report-citation-note", children: block.note })] })) : null, " ", _jsx("span", { class: "report-citation-key", children: key })] }));
|
|
255
|
+
return String(_jsxs("div", { class: "report-citation corner-accents", ...lineageStamp(view.lineage, block.id, [binding]), children: [_jsx(Marker, { n: n, lineage: lineagePlace(view.lineage, binding) }), record !== undefined ? (_jsxs(_Fragment, { children: [" ", binding.idKind === "pmid" ? (_jsx("a", { class: "report-citation-source", href: `${PUBMED_BASE}${encodeURIComponent(binding.id)}/`, children: record.citation })) : (_jsx("span", { class: "report-citation-source", children: record.citation }))] })) : null, block.note !== undefined ? (_jsxs(_Fragment, { children: [" ", _jsx("span", { class: "report-citation-note", children: block.note })] })) : null, " ", _jsx("span", { class: "report-citation-key", children: key })] }));
|
|
243
256
|
}
|
|
@@ -34,6 +34,7 @@ import { type CitationResolverConfig } from "../citations/resolve.js";
|
|
|
34
34
|
import type { CitationResolver } from "../citations/types.js";
|
|
35
35
|
import type { AuthContext } from "../auth/types.js";
|
|
36
36
|
import type { ReferenceResolver } from "../report-model/reference-resolver.js";
|
|
37
|
+
import type { ProvenanceSeam } from "../provenance/seam.js";
|
|
37
38
|
import type { MakeSessionPagePublisher, ResolvePageAsset, ResolvePageUrl } from "../tools/report-session/index.js";
|
|
38
39
|
/** Registered child sandbox-step callable the parent's child dispatch closes over. */
|
|
39
40
|
export type SandboxStepCallable = (input: SandboxStepInput) => Promise<SandboxStepResult>;
|
|
@@ -160,6 +161,27 @@ export interface CoreRuntimeDeps {
|
|
|
160
161
|
* the eyes tool of a report session then reports that condition.
|
|
161
162
|
*/
|
|
162
163
|
readonly eyes?: AcquireEyes;
|
|
164
|
+
/**
|
|
165
|
+
* The provenance seam. Each act of a session — the creation of the session, the block operations, the
|
|
166
|
+
* title, the derivation, the preview, and the record — rides the session emit as one typed event, and
|
|
167
|
+
* the embedder lands the events in the record of the analysis that it owns. The emit is
|
|
168
|
+
* fire-and-forget: it gives no result, a throw of the realization reaches the log alone, and an unbound
|
|
169
|
+
* member emits nothing. Thus a composition that binds none behaves the same as one that never had the
|
|
170
|
+
* seam.
|
|
171
|
+
*
|
|
172
|
+
* The document read gives the signed document of the analysis back, as opaque text. The preview of a
|
|
173
|
+
* report session carries a frozen copy into the page, and the page then shows the chain of a grounded
|
|
174
|
+
* block with no host and no network. The harness parses nothing. Absence is a normal result: an unbound
|
|
175
|
+
* member, and a bound member that holds no document for the analysis, both give a page with no
|
|
176
|
+
* provenance and no other change.
|
|
177
|
+
*
|
|
178
|
+
* Each member is optional alone, thus a composition binds the members that it records.
|
|
179
|
+
*
|
|
180
|
+
* The assembly reaches two consumers with the seam: the report agent, and the conversation agent, whose
|
|
181
|
+
* start tool passes it to the spawn. The creation of a conversation thread rides `prepareChatTurn`,
|
|
182
|
+
* which an embedder calls on its own. Thus that composition binds the seam there as well.
|
|
183
|
+
*/
|
|
184
|
+
readonly provenance?: ProvenanceSeam;
|
|
163
185
|
}
|
|
164
186
|
/**
|
|
165
187
|
* The refusal a thread type carries no agent yet. `report` is a valid
|
package/dist/runtime/assemble.js
CHANGED
|
@@ -124,6 +124,9 @@ export function assembleCoreRuntime(deps) {
|
|
|
124
124
|
usageRecorder,
|
|
125
125
|
citationResolver,
|
|
126
126
|
...(eyes ? { eyes } : {}),
|
|
127
|
+
// The start tool passes it to the spawn, which emits the creation of a
|
|
128
|
+
// report session. The same seam reaches the report agent below.
|
|
129
|
+
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
127
130
|
});
|
|
128
131
|
// The report agent is a singleton over the conversation deps, the same way the
|
|
129
132
|
// session runtime is. Its preview tool writes the page into the analysis tree
|
|
@@ -173,6 +176,7 @@ export function assembleCoreRuntime(deps) {
|
|
|
173
176
|
...(deps.resolveReportPageAsset ? { resolvePageAsset: deps.resolveReportPageAsset } : {}),
|
|
174
177
|
...(deps.makeSessionPagePublisher ? { makeSessionPages: deps.makeSessionPagePublisher } : {}),
|
|
175
178
|
...(deps.resolveReportPageUrl ? { resolvePageUrl: deps.resolveReportPageUrl } : {}),
|
|
179
|
+
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
176
180
|
...(conversation.logger ? { logger: conversation.logger } : {}),
|
|
177
181
|
});
|
|
178
182
|
// The single registration point for every typed agent. A future thread type's
|
|
@@ -20,7 +20,7 @@ import { clearSandboxRef } from "../state/index.js";
|
|
|
20
20
|
import { type AwaitExecOptions } from "./await-exec.js";
|
|
21
21
|
import type { SandboxClient } from "./client.js";
|
|
22
22
|
import { type SubmitExecDeps } from "./submit-exec.js";
|
|
23
|
-
import { type CreateSandboxMeta, type SandboxTransport } from "./types.js";
|
|
23
|
+
import { type CreateSandboxMeta, type FarmSource, type SandboxTransport, type ToolchainSource } from "./types.js";
|
|
24
24
|
/**
|
|
25
25
|
* Narrow config slice the sandbox factory reads off `Env` — the backend
|
|
26
26
|
* default and the K8s namespace fallback. Composition roots map their
|
|
@@ -65,6 +65,21 @@ export interface CreateSandboxClientConfig {
|
|
|
65
65
|
resolveWorkspaceRoot: ResolveWorkspaceRoot;
|
|
66
66
|
/** Docker: host dir bind-mounted read-only at `/mnt/libs`. */
|
|
67
67
|
libStorePath?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Where the farm of an analysis comes from. Required of every embedder —
|
|
70
|
+
* the harness never invents a farm location, and it reads no store-root
|
|
71
|
+
* `current` pointer. On Docker, `FarmLocation.farmPath` is a host
|
|
72
|
+
* directory. On K8s, it is a `subPath` into `libStorePvc`. Consulted only
|
|
73
|
+
* when a store is configured.
|
|
74
|
+
*/
|
|
75
|
+
farmSource: FarmSource;
|
|
76
|
+
/**
|
|
77
|
+
* The declared toolchain owner. `"image"` keys the resolver env and the
|
|
78
|
+
* orient-core prompt text onto the image-owned toolchain. Absent means
|
|
79
|
+
* `"store"`: the legacy environment, byte-identical to the one before
|
|
80
|
+
* this field existed.
|
|
81
|
+
*/
|
|
82
|
+
toolchainSource?: ToolchainSource;
|
|
68
83
|
/** Docker: host dir bind-mounted read-only at `/mnt/refs`. */
|
|
69
84
|
refStorePath?: string;
|
|
70
85
|
/** Docker: force the container platform (e.g. `linux/amd64`) so the sandbox matches the mounted lib store's arch. */
|
|
@@ -109,9 +124,10 @@ export interface CreateSandboxClientConfig {
|
|
|
109
124
|
/** Override the backend selection — defaults to `env.SANDBOX_BACKEND`. */
|
|
110
125
|
backend?: "docker" | "k8s";
|
|
111
126
|
/**
|
|
112
|
-
* Optional logger forwarded to the Docker backend so a
|
|
113
|
-
* (a
|
|
114
|
-
* observable rather than a silent mount drop. No-op when
|
|
127
|
+
* Optional logger forwarded to the Docker backend so a store degradation
|
|
128
|
+
* (a resolved farm whose `inflexa.lock` vanished or went invalid
|
|
129
|
+
* mid-session) is observable rather than a silent mount drop. No-op when
|
|
130
|
+
* unset.
|
|
115
131
|
*/
|
|
116
132
|
logger?: Logger;
|
|
117
133
|
/** Dependency seams (fetch, durable step/sleep, clock, recv, warn sink) forwarded to submit/await. */
|
|
@@ -86,6 +86,8 @@ export function createSandboxClient(config) {
|
|
|
86
86
|
sessionPvcRoot: config.sessionPvcRoot,
|
|
87
87
|
resolveWorkspaceRoot: config.resolveWorkspaceRoot,
|
|
88
88
|
libStorePvc: config.libStorePvc,
|
|
89
|
+
farmSource: config.farmSource,
|
|
90
|
+
toolchainSource: config.toolchainSource,
|
|
89
91
|
refStorePvc: config.refStorePvc,
|
|
90
92
|
nodeSelector: config.nodeSelector,
|
|
91
93
|
tolerations: config.tolerations,
|
|
@@ -98,6 +100,8 @@ export function createSandboxClient(config) {
|
|
|
98
100
|
transport,
|
|
99
101
|
resolveWorkspaceRoot: config.resolveWorkspaceRoot,
|
|
100
102
|
libStorePath: config.libStorePath,
|
|
103
|
+
farmSource: config.farmSource,
|
|
104
|
+
toolchainSource: config.toolchainSource,
|
|
101
105
|
refStorePath: config.refStorePath,
|
|
102
106
|
platform: config.platform,
|
|
103
107
|
engineSocketPath: config.engineSocketPath,
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Thin wrapper around `dockerode`. Storage is wired via `HostConfig.Binds`:
|
|
5
5
|
* a flat read-only mount of the analysis tree at `/{resourceId}`, a nested
|
|
6
|
-
* read-write mount of the step's artifact dir,
|
|
7
|
-
* `/mnt/libs`
|
|
8
|
-
*
|
|
6
|
+
* read-write mount of the step's artifact dir, the package store at
|
|
7
|
+
* `/mnt/libs` with the resolved farm nested inside it, and the ref store at
|
|
8
|
+
* `/mnt/refs` when its host path is configured. Container paths and
|
|
9
|
+
* lib-store env come from the shared mount plan (`mount-plan.ts`).
|
|
9
10
|
*
|
|
10
11
|
* ## The cpu files
|
|
11
12
|
*
|
|
@@ -42,7 +43,7 @@ import { ResultAsync } from "neverthrow";
|
|
|
42
43
|
import type { Logger } from "../lib/logger.js";
|
|
43
44
|
import { type ResolveWorkspaceRoot } from "../workspace/paths.js";
|
|
44
45
|
import { type SandboxError } from "./sandbox-error.js";
|
|
45
|
-
import type { CreateSandboxMeta, ManagedSandbox, SandboxIdentity, SandboxLiveness, SandboxRef, SandboxTransport } from "./types.js";
|
|
46
|
+
import type { CreateSandboxMeta, FarmSource, ManagedSandbox, SandboxIdentity, SandboxLiveness, SandboxRef, SandboxTransport, ToolchainSource } from "./types.js";
|
|
46
47
|
export interface DockerClientConfig {
|
|
47
48
|
image: string;
|
|
48
49
|
/** Cortex base URL injected into the sandbox env in callback mode so callbacks land here. Unused in poll mode. */
|
|
@@ -53,6 +54,15 @@ export interface DockerClientConfig {
|
|
|
53
54
|
resolveWorkspaceRoot: ResolveWorkspaceRoot;
|
|
54
55
|
/** Host lib store; bind-mounted read-only at `/mnt/libs` when set. */
|
|
55
56
|
libStorePath?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Where the farm of an analysis comes from. Required — the harness never
|
|
59
|
+
* invents a farm location. `FarmLocation.farmPath` is a host directory
|
|
60
|
+
* here, bind-mounted read-only at the farm container path. Consulted only
|
|
61
|
+
* when `libStorePath` is set.
|
|
62
|
+
*/
|
|
63
|
+
farmSource: FarmSource;
|
|
64
|
+
/** The declared toolchain owner. Absent means `"store"`, the legacy environment. */
|
|
65
|
+
toolchainSource?: ToolchainSource;
|
|
56
66
|
/**
|
|
57
67
|
* Host ref store; bind-mounted read-only at `/mnt/refs`. Embedders pass the
|
|
58
68
|
* configured store location unconditionally — existence is (re-)checked at each
|
|
@@ -85,8 +95,8 @@ export interface DockerClientConfig {
|
|
|
85
95
|
*/
|
|
86
96
|
readHostCpuinfo?: () => Promise<string | undefined>;
|
|
87
97
|
/**
|
|
88
|
-
* Optional logger so a
|
|
89
|
-
*
|
|
98
|
+
* Optional logger so a store degradation (a resolved farm whose `inflexa.lock`
|
|
99
|
+
* is absent or invalid by sandbox-create time) is observable instead of a
|
|
90
100
|
* silent libs-mount drop. Matches the `reaper`/`watchdog` logger seam.
|
|
91
101
|
*/
|
|
92
102
|
logger?: Logger;
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Thin wrapper around `dockerode`. Storage is wired via `HostConfig.Binds`:
|
|
5
5
|
* a flat read-only mount of the analysis tree at `/{resourceId}`, a nested
|
|
6
|
-
* read-write mount of the step's artifact dir,
|
|
7
|
-
* `/mnt/libs`
|
|
8
|
-
*
|
|
6
|
+
* read-write mount of the step's artifact dir, the package store at
|
|
7
|
+
* `/mnt/libs` with the resolved farm nested inside it, and the ref store at
|
|
8
|
+
* `/mnt/refs` when its host path is configured. Container paths and
|
|
9
|
+
* lib-store env come from the shared mount plan (`mount-plan.ts`).
|
|
9
10
|
*
|
|
10
11
|
* ## The cpu files
|
|
11
12
|
*
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
* Either way the workload ends as uid 1000 with `no-new-privileges` and no
|
|
38
39
|
* effective capabilities.
|
|
39
40
|
*/
|
|
40
|
-
import {
|
|
41
|
+
import { lstatSync } from "node:fs";
|
|
41
42
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
42
43
|
import { dirname, join } from "node:path";
|
|
43
44
|
import Docker from "dockerode";
|
|
@@ -45,6 +46,7 @@ import { ResultAsync, err, ok } from "neverthrow";
|
|
|
45
46
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
46
47
|
import { tailWritePrefix } from "../workspace/paths.js";
|
|
47
48
|
import { trySandbox } from "./sandbox-error.js";
|
|
49
|
+
import { readFarmLock, resolveFarmSource } from "./farm.js";
|
|
48
50
|
import { buildMountPlan, sandboxWriteTail } from "./mount-plan.js";
|
|
49
51
|
import { CPU_ONLINE_PATH, CPUINFO_PATH, cpuFiles, readHostCpuinfoOnce } from "./cpu-files.js";
|
|
50
52
|
import { threadLimitEnv } from "./thread-env.js";
|
|
@@ -74,26 +76,6 @@ const RUN_ID_LABEL = "cortex/run-id";
|
|
|
74
76
|
const STEP_ID_LABEL = "cortex/step-id";
|
|
75
77
|
/** The directory next to the workspace root that holds the cpu files of each sandbox. */
|
|
76
78
|
const CPU_FILES_DIR = ".cpu";
|
|
77
|
-
/**
|
|
78
|
-
* Whether the lib store's `current` resolves to a COMPLETE, usable version, not merely a
|
|
79
|
-
* present symlink. By sandbox-create time `current` may be gone (concurrent prune/`rm`), a
|
|
80
|
-
* dangling symlink (its target pruned), or an incomplete tree. Binding a missing source
|
|
81
|
-
* makes Docker auto-create a root-owned dir (bricking a later store refresh); binding a broken
|
|
82
|
-
* one mounts broken content. Require a resolved directory carrying both completeness
|
|
83
|
-
* markers `activate` writes before it flips the pointer.
|
|
84
|
-
*/
|
|
85
|
-
function libStoreUsable(libStorePath) {
|
|
86
|
-
const current = join(libStorePath, "current");
|
|
87
|
-
try {
|
|
88
|
-
// statSync FOLLOWS the symlink, so a dangling `current` throws here and is rejected.
|
|
89
|
-
if (!statSync(current).isDirectory())
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
return existsSync(join(current, "packages.txt")) && existsSync(join(current, "meta.json"));
|
|
96
|
-
}
|
|
97
79
|
/**
|
|
98
80
|
* Whether `refStorePath` is, right now, a real directory fit to be a bind authority.
|
|
99
81
|
* Deliberately shallow — it checks existence-as-a-directory only, never the store's
|
|
@@ -253,13 +235,41 @@ export function createDockerSandboxOps(config) {
|
|
|
253
235
|
createSandbox(meta, identity) {
|
|
254
236
|
return new ResultAsync((async () => {
|
|
255
237
|
const { sandboxId, callbackSecret } = identity;
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
238
|
+
// Farm resolution comes before any container work: a resolver
|
|
239
|
+
// refusal and a resolver throw refuse the whole call, and no
|
|
240
|
+
// container is made. The reason of the embedder rides in the error.
|
|
241
|
+
let farm;
|
|
242
|
+
if (config.libStorePath) {
|
|
243
|
+
const resolved = await resolveFarmSource(config.farmSource, meta.analysisId, "docker.createSandbox");
|
|
244
|
+
if (resolved.isErr())
|
|
245
|
+
return err(resolved.error);
|
|
246
|
+
farm = resolved.value;
|
|
247
|
+
}
|
|
248
|
+
// The `inflexa.lock` gate runs at each create: the store may have
|
|
249
|
+
// gone away, or the farm may be half-written. A gate failure
|
|
250
|
+
// degrades — both store mounts drop, the container is still made,
|
|
251
|
+
// and the sandbox reports the store as unavailable. The warning is
|
|
252
|
+
// logged because an otherwise-silent mount drop is invisible to
|
|
253
|
+
// operators.
|
|
254
|
+
let libsMounted = false;
|
|
255
|
+
if (config.libStorePath && farm) {
|
|
256
|
+
const lock = readFarmLock(farm.farmPath);
|
|
257
|
+
libsMounted = lock.isOk();
|
|
258
|
+
if (lock.isErr()) {
|
|
259
|
+
logger.warn("the farm of the analysis has no usable inflexa.lock at sandbox creation — mounting no package store (sandbox degrades to available:false)", { libStorePath: config.libStorePath, farmPath: farm.farmPath, lockError: lock.error.type, sandboxId });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// The cache path is the one farm value with no gate of its
|
|
263
|
+
// own: the lock gate proves `farmPath`, and this bind string
|
|
264
|
+
// would carry a malformed cache path verbatim. An unusable
|
|
265
|
+
// value degrades to no cache mount — the rule of a missing
|
|
266
|
+
// one — because the entrypoint fallback covers the caches.
|
|
267
|
+
const cacheBindable = farm?.cachePath !== undefined && farm.cachePath.startsWith("/") && !farm.cachePath.includes(":");
|
|
268
|
+
if (farm?.cachePath !== undefined && !cacheBindable) {
|
|
269
|
+
logger.warn("the farm cache path cannot ride a docker bind — mounting no cache", {
|
|
270
|
+
cachePath: farm.cachePath,
|
|
271
|
+
sandboxId,
|
|
272
|
+
});
|
|
263
273
|
}
|
|
264
274
|
// Re-checked here too, so a ref store installed after boot is mounted into
|
|
265
275
|
// the next sandbox. Unlike libs, a missing ref store is NOT warned: a missing
|
|
@@ -271,6 +281,8 @@ export function createDockerSandboxOps(config) {
|
|
|
271
281
|
const plan = buildMountPlan(meta, {
|
|
272
282
|
libs: libsMounted,
|
|
273
283
|
refs: refsMounted,
|
|
284
|
+
toolchainSource: config.toolchainSource,
|
|
285
|
+
cache: cacheBindable,
|
|
274
286
|
});
|
|
275
287
|
const hostTreePath = config.resolveWorkspaceRoot(meta.analysisId);
|
|
276
288
|
// `tailWritePrefix` (not a raw `join`) so the RW bind source runs through
|
|
@@ -290,12 +302,16 @@ export function createDockerSandboxOps(config) {
|
|
|
290
302
|
const cpuBinds = await writeCpuFiles(cpuDir, cpuFiles(threads, cpuinfo), logger, sandboxId);
|
|
291
303
|
if (cpuBinds.length > 0)
|
|
292
304
|
cpuDirs.set(sandboxId, cpuDir);
|
|
305
|
+
// The farm bind comes after the store bind, thus the nesting is
|
|
306
|
+
// stable; the cache bind comes after the two store binds.
|
|
293
307
|
const binds = [
|
|
294
308
|
`${hostTreePath}:${plan.readonlyTreePath}:ro`,
|
|
295
309
|
...(write && plan.writableStepPath
|
|
296
310
|
? [`${tailWritePrefix({ workspaceRoot: hostTreePath, tail: write.tail })}:${plan.writableStepPath}:rw`]
|
|
297
311
|
: []),
|
|
298
312
|
...(libsMounted && config.libStorePath ? [`${config.libStorePath}:${plan.libsPath}:ro`] : []),
|
|
313
|
+
...(libsMounted && farm && plan.farmPath ? [`${farm.farmPath}:${plan.farmPath}:ro`] : []),
|
|
314
|
+
...(libsMounted && cacheBindable && farm?.cachePath && plan.cachePath ? [`${farm.cachePath}:${plan.cachePath}:rw`] : []),
|
|
299
315
|
...(refsMounted && config.refStorePath ? [`${config.refStorePath}:${plan.refsPath}:ro`] : []),
|
|
300
316
|
...cpuBinds,
|
|
301
317
|
];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Farm-source resolution and the `inflexa.lock` farm contract.
|
|
3
|
+
*
|
|
4
|
+
* A farm carries exactly one metadata file, `inflexa.lock`, beside its link
|
|
5
|
+
* trees and its caches (the lib-store spec). The mount gate and the package
|
|
6
|
+
* inventory read this one file — `packages.txt`, `meta.json`, and
|
|
7
|
+
* `lock.json` are not part of the farm contract.
|
|
8
|
+
*
|
|
9
|
+
* The resolution and the gate refuse differently, on purpose:
|
|
10
|
+
* - A resolver refusal (`unavailable`, or a throw) is a `farm_unavailable`
|
|
11
|
+
* `SandboxError` — the call refuses and no container is made.
|
|
12
|
+
* - A lock-gate failure degrades — the backend drops both store mounts,
|
|
13
|
+
* logs a warning, and still makes the container.
|
|
14
|
+
*/
|
|
15
|
+
import { type Result } from "neverthrow";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import type { SandboxError } from "./sandbox-error.js";
|
|
18
|
+
import type { FarmLocation, FarmSource } from "./types.js";
|
|
19
|
+
/** The one metadata file of a farm. */
|
|
20
|
+
export declare const FARM_LOCK_FILE = "inflexa.lock";
|
|
21
|
+
/** One linked distribution. `requested` obeys the PEP 376 meaning: true for a direct ask, false for a transitive dependency. */
|
|
22
|
+
export declare const FarmLockPackageSchema: z.ZodObject<{
|
|
23
|
+
name: z.ZodString;
|
|
24
|
+
version: z.ZodString;
|
|
25
|
+
track: z.ZodString;
|
|
26
|
+
store_dir: z.ZodString;
|
|
27
|
+
hash: z.ZodString;
|
|
28
|
+
requested: z.ZodBoolean;
|
|
29
|
+
}, z.core.$loose>;
|
|
30
|
+
/**
|
|
31
|
+
* `inflexa.lock` at schema version 1. Additive fields pass through — a
|
|
32
|
+
* breaking change to the shape must move the schema number instead.
|
|
33
|
+
*/
|
|
34
|
+
export declare const FarmLockSchema: z.ZodObject<{
|
|
35
|
+
schema: z.ZodLiteral<1>;
|
|
36
|
+
arch: z.ZodEnum<{
|
|
37
|
+
amd64: "amd64";
|
|
38
|
+
arm64: "arm64";
|
|
39
|
+
}>;
|
|
40
|
+
packages: z.ZodArray<z.ZodObject<{
|
|
41
|
+
name: z.ZodString;
|
|
42
|
+
version: z.ZodString;
|
|
43
|
+
track: z.ZodString;
|
|
44
|
+
store_dir: z.ZodString;
|
|
45
|
+
hash: z.ZodString;
|
|
46
|
+
requested: z.ZodBoolean;
|
|
47
|
+
}, z.core.$loose>>;
|
|
48
|
+
languages: z.ZodObject<{
|
|
49
|
+
python: z.ZodOptional<z.ZodObject<{
|
|
50
|
+
version: z.ZodString;
|
|
51
|
+
index: z.ZodString;
|
|
52
|
+
}, z.core.$loose>>;
|
|
53
|
+
r: z.ZodOptional<z.ZodObject<{
|
|
54
|
+
version: z.ZodString;
|
|
55
|
+
bioc_releases: z.ZodArray<z.ZodString>;
|
|
56
|
+
pak_lock: z.ZodOptional<z.ZodUnknown>;
|
|
57
|
+
}, z.core.$loose>>;
|
|
58
|
+
}, z.core.$loose>;
|
|
59
|
+
warm: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
60
|
+
script_sha256: z.ZodString;
|
|
61
|
+
cache_entries: z.ZodArray<z.ZodString>;
|
|
62
|
+
}, z.core.$loose>>>;
|
|
63
|
+
merge_conflicts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
64
|
+
entry: z.ZodString;
|
|
65
|
+
action: z.ZodEnum<{
|
|
66
|
+
skipped: "skipped";
|
|
67
|
+
"kept-first": "kept-first";
|
|
68
|
+
}>;
|
|
69
|
+
}, z.core.$loose>>>;
|
|
70
|
+
}, z.core.$loose>;
|
|
71
|
+
export type FarmLock = z.infer<typeof FarmLockSchema>;
|
|
72
|
+
export type FarmLockError = {
|
|
73
|
+
readonly type: "lock_unreadable";
|
|
74
|
+
readonly lockPath: string;
|
|
75
|
+
readonly cause: unknown;
|
|
76
|
+
} | {
|
|
77
|
+
readonly type: "lock_invalid";
|
|
78
|
+
readonly lockPath: string;
|
|
79
|
+
readonly cause: unknown;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Read and validate the `inflexa.lock` of a farm directory. The mount gate
|
|
83
|
+
* accepts a farm only when this returns ok — a farm whose lock is absent,
|
|
84
|
+
* unparseable, or at an unknown schema version is not usable.
|
|
85
|
+
*/
|
|
86
|
+
export declare function readFarmLock(farmPath: string): Result<FarmLock, FarmLockError>;
|
|
87
|
+
/** Read and validate one `inflexa.lock` by its file path. The package inventory reads through this too. */
|
|
88
|
+
export declare function readFarmLockFile(lockPath: string): Result<FarmLock, FarmLockError>;
|
|
89
|
+
/**
|
|
90
|
+
* Resolve the farm source of one analysis. Runs before any container work.
|
|
91
|
+
* `fixed` answers at once. `per-analysis` calls the resolver of the
|
|
92
|
+
* embedder — an `unavailable` result and a throw both refuse the call with
|
|
93
|
+
* `farm_unavailable`, and the reason of the embedder rides in the error.
|
|
94
|
+
*/
|
|
95
|
+
export declare function resolveFarmSource(source: FarmSource, analysisId: string, op: string): Promise<Result<FarmLocation, SandboxError>>;
|