@markii/host 0.17.0-next.4 → 0.17.0-next.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +28 -1
  2. package/dist/browser-worker.classic.js +43 -43
  3. package/dist/browser-worker.js +43 -43
  4. package/dist/conformance/host/17-export-linked-set/expected.json +17 -0
  5. package/dist/conformance/host/17-export-linked-set/files/second.mk.md +3 -0
  6. package/dist/conformance/host/17-export-linked-set/note.mk.md +4 -0
  7. package/dist/conformance/host/17-export-linked-set/scenario.json +6 -0
  8. package/dist/conformance/host/18-last-run-and-grants/expected.json +42 -0
  9. package/dist/conformance/host/18-last-run-and-grants/note.mk.md +5 -0
  10. package/dist/conformance/host/18-last-run-and-grants/scenario.json +27 -0
  11. package/dist/conformance/host/README.md +24 -14
  12. package/dist/conformance.d.ts +1 -1
  13. package/dist/conformance.js +1 -1
  14. package/dist/diagnostics/render-diagnostics.d.ts +1 -1
  15. package/dist/host/adapter.d.ts +28 -6
  16. package/dist/host/cascade-export-behavior.d.ts +26 -8
  17. package/dist/host/cascade-export-behavior.js +64 -1
  18. package/dist/host/conformance-runner.d.ts +11 -1
  19. package/dist/host/conformance-runner.js +80 -4
  20. package/dist/host/create-host.d.ts +250 -44
  21. package/dist/host/create-host.js +222 -96
  22. package/dist/host/export-behavior.d.ts +2 -0
  23. package/dist/host/export-behavior.js +10 -4
  24. package/dist/host/pack-archive.d.ts +7 -6
  25. package/dist/host/pack-archive.js +11 -7
  26. package/dist/host/pack-install.js +9 -7
  27. package/dist/host/pack-remove.d.ts +7 -18
  28. package/dist/host/pack-remove.js +2 -0
  29. package/dist/host/pack-trust-behavior.d.ts +13 -36
  30. package/dist/host/pack-trust-behavior.js +23 -2
  31. package/dist/host/run-behavior.d.ts +25 -34
  32. package/dist/host/run-behavior.js +31 -5
  33. package/dist/host/terminal-packs.d.ts +1 -1
  34. package/dist/index.d.ts +8 -10
  35. package/dist/index.js +1 -1
  36. package/dist/internal.d.ts +10 -5
  37. package/dist/internal.js +4 -3
  38. package/dist/node-worker.js +3 -1
  39. package/dist/node.d.ts +1 -2
  40. package/dist/node.js +1 -1
  41. package/dist/run/bundle-run.d.ts +1 -1
  42. package/dist/run/bundle-run.js +1 -1
  43. package/dist/run/node-isolate.d.ts +6 -2
  44. package/dist/run/node-isolate.js +2 -0
  45. package/dist/run/run-host.d.ts +2 -2
  46. package/dist/run/worker-entry-browser.d.ts +6 -1
  47. package/dist/run/worker-entry-browser.js +62 -5
  48. package/package.json +11 -11
@@ -5,30 +5,42 @@
5
5
  * environment-neutral. VS Code's webview imports only the pure pieces and
6
6
  * never calls this function.
7
7
  *
8
- * It provides `run`, `diagnostics`, `open`, `exportNote`, `installPack`, `loadPacks`, `completeAt`,
9
- * `hoverAt`, and `insertComponent`, over the behavior modules (`./export-behavior.js`, `./pack-install.js`,
10
- * `./pack-load.js`, `./editor-behavior.js`). Every one of them
11
- * returns the shared `Unsupported` outcome, with one diagnostics line,
12
- * when the adapter lacks the capability it needs — AGENTS.md's "clean is
13
- * not silent": a decline is never a silent no-op.
8
+ * It provides `run`, `lastRun`, `forgetGrants`, `diagnostics`, `open`,
9
+ * `exportNote`, `exportLinkedSet`, `installPack`, `loadPacks`, `completeAt`,
10
+ * `hoverAt`, and `insertComponent`, over the behavior modules
11
+ * (`./export-behavior.js`, `./pack-install.js`, `./pack-load.js`,
12
+ * `./editor-behavior.js`). A behavior that needs a capability the adapter
13
+ * lacks returns the shared `Unsupported` outcome with one diagnostics line,
14
+ * so a decline is never a silent no-op ("clean is not silent").
15
+ *
16
+ * Outcome vocabulary, the same in every behavior:
17
+ * `declined` is a user's "no" to a prompt or a cancelled picker; `failed`
18
+ * is an I/O or runtime failure and carries a `reason`; `invalid` is input
19
+ * that was read and judged bad and carries a `reason`; `unsupported` is a
20
+ * host that lacks the capability. No behavior rejects.
14
21
  */
15
22
  import type { HostAdapter, HostExportFormat, HostTextEdit } from './adapter.js';
16
23
  import type { RunResult, SpawnRunRequest } from '../run/run-host.js';
17
- import type { StoredValue } from '@markii/runtime';
24
+ import type { RunTrigger, StoredValue } from '@markii/runtime';
25
+ import type { BundleManifest } from '@markii/bundle';
26
+ import type { PinPolicy } from '../run/net-pinning.js';
27
+ import type { PackModulesMap } from '../run/lua-resolver.js';
28
+ import type { ValuesFailure } from '../values-failure.js';
29
+ import { type RunTrace } from '../run/run-trace.js';
18
30
  import type { OnDiagnostic, UnavailableComponent } from '@markii/stdlib';
19
31
  import type { CompletionItem, ComponentDocumentation, LineColumn } from '@markii/stdlib/editor';
20
- import { type RunViaAdapterRequest, type RunViaAdapterResult } from './run-behavior.js';
21
32
  import { type PackDiscoveryIo } from './pack-load.js';
22
33
  import type { ExportBodyRenderer, ExportPackStylesheet, ExportRenderInfo, HtmlExportEngine, StaticExportReason } from '../export/note-export.js';
23
34
  import type { EmbeddedImageReport, ExportImageReader } from '../export/image-embed.js';
35
+ import type { CascadeLinkResolver, CascadeTruncation } from '../export/cascade.js';
36
+ import { type CascadeExportedNote, type UnreadableCascadeNote } from './cascade-export-behavior.js';
24
37
  import type { DiscoveredPack, SkippedPackFolder } from '../packs/discover.js';
25
38
  import { type TerminalPackScript } from './terminal-packs.js';
26
- import { type RemovePackOutcome } from './pack-remove.js';
27
- import type { DisablePackOutcome, EnablePackOutcome, InstalledPacksListing } from './pack-trust-behavior.js';
39
+ import type { InstalledPacksListing } from './pack-trust-behavior.js';
28
40
  /** The shared decline shape every behavior returns when the adapter lacks the capability it needs. */
29
41
  export interface Unsupported {
30
42
  readonly kind: 'unsupported';
31
- readonly capability: 'isolate' | 'editor' | 'packs' | 'pack-trust' | 'export-format';
43
+ readonly capability: 'isolate' | 'editor' | 'packs' | 'pack-trust' | 'export-format' | 'linked-set-export';
32
44
  readonly detail?: string;
33
45
  }
34
46
  export interface OpenRequest {
@@ -41,17 +53,63 @@ export type OpenOutcome = {
41
53
  readonly kind: 'failed';
42
54
  readonly reason: string;
43
55
  };
44
- export type RunRequest = RunViaAdapterRequest;
45
- export type RunOutcome = ({
46
- readonly kind: 'ran';
47
- } & RunViaAdapterResult) | Unsupported;
48
- export interface ExportRequest {
49
- readonly format: HostExportFormat;
50
- /** The note's own path, used to name the exported file. */
51
- readonly notePath: string;
56
+ export interface RunRequest {
57
+ /** Stable identity for the note this run belongs to. The same key reads the run back through `lastRun` and clears its grants through `forgetGrants`. */
58
+ readonly documentKey: string;
52
59
  readonly text: string;
53
- /** The note's last-run values, baked into an html/pdf export. Omitted or empty exports the note's standard empty states. */
54
- readonly values?: Record<string, StoredValue>;
60
+ readonly trigger: RunTrigger;
61
+ /** The address policy for the run's network access. Omitted keeps the fail-closed default, which refuses private and loopback addresses. */
62
+ readonly netPolicy?: PinPolicy;
63
+ /** Present only for a bundle-backed note. */
64
+ readonly bundle?: {
65
+ readonly manifest: BundleManifest;
66
+ /** Called once per run, before the grant flow, to read the bundle's files. */
67
+ readonly buildSnapshot: () => Promise<Record<string, Uint8Array>>;
68
+ /** Receives the bundle's `.cache/` subtree after a run that produced one. */
69
+ readonly persistCacheOut: (cacheOut: Record<string, Uint8Array>) => Promise<void>;
70
+ };
71
+ /** Pre-read pack Lua modules, so a script's `require` of a pack module resolves. Omit it when no packs are loaded. */
72
+ readonly packModules?: PackModulesMap;
73
+ /** Called once per script as its value arrives, already scrubbed for the wire. */
74
+ readonly onValue?: (name: string, value: StoredValue) => void;
75
+ /** The wall-clock budget for the run. Defaults to 15 seconds. */
76
+ readonly timeoutMs?: number;
77
+ }
78
+ export type RunOutcome = {
79
+ readonly kind: 'ran';
80
+ readonly values: Record<string, StoredValue>;
81
+ readonly failures: ValuesFailure[];
82
+ /** The same failures with their messages, for the diagnostics surface only. */
83
+ readonly failureDetails: {
84
+ name: string;
85
+ kind: ValuesFailure['kind'];
86
+ message: string;
87
+ }[];
88
+ /** Lines describing a mismatch between declared and reached hosts, for the diagnostics surface only. */
89
+ readonly netDeclarationDiagnostics: string[];
90
+ /** The outcome this run recorded, for the in-note marker. */
91
+ readonly trace: RunTrace;
92
+ /** How many of this run's values came back `fresh`. */
93
+ readonly freshCount: number;
94
+ /** How many of this run's values came back `error`. */
95
+ readonly errorCount: number;
96
+ }
97
+ /** The run threw. The diagnostics line and a failed trace are already written. */
98
+ | {
99
+ readonly kind: 'failed';
100
+ readonly reason: string;
101
+ } | Unsupported;
102
+ /** What a note's last run left in the adapter's memento. */
103
+ export interface LastRunOutcome {
104
+ /** The stored values marked for showing on open: a `fresh` value reads `stale` until a new run lands. Empty when nothing is stored. */
105
+ readonly values: Record<string, StoredValue>;
106
+ /** The stored values exactly as persisted, for an export that bakes a snapshot in. Empty when nothing is stored. */
107
+ readonly persistedValues: Record<string, StoredValue>;
108
+ /** The last run's recorded outcome, absent when nothing is stored. */
109
+ readonly trace?: RunTrace;
110
+ }
111
+ /** The render options a single-note export and a linked-set export share. */
112
+ export interface ExportRenderOptions {
55
113
  /**
56
114
  * Installed pack components the static HTML engine cannot draw. A
57
115
  * directive naming one is labeled "no HTML view" instead of "unknown
@@ -61,7 +119,7 @@ export interface ExportRequest {
61
119
  readonly unavailableComponents?: readonly UnavailableComponent[];
62
120
  /** Receives the static engine's render diagnostics, such as the `no-engine-view` event. */
63
121
  readonly onDiagnostic?: OnDiagnostic;
64
- /** The host's own render of the body (a React pass bound to its loaded packs). Omitted means the static engine renders, and `staticReason` says why. Used by the `html` and `pdf` formats. */
122
+ /** The host's own render of the body (a React pass bound to its loaded packs). Omitted means the static engine renders, and `staticReason` says why. */
65
123
  readonly renderBody?: ExportBodyRenderer;
66
124
  /** Why the static engine renders when `renderBody` is omitted. Defaults to `no-packs`. */
67
125
  readonly staticReason?: StaticExportReason;
@@ -69,11 +127,21 @@ export interface ExportRequest {
69
127
  readonly packStylesheets?: readonly ExportPackStylesheet[];
70
128
  /** How many loaded packs contributed to the render. Diagnostics only. */
71
129
  readonly packCount?: number;
72
- /** Reads one of the note's local images so the export embeds it as a `data:` URI. Omitted leaves every image source as written. */
73
- readonly embedImages?: ExportImageReader;
74
130
  /** Hides the collapsed script marker in the exported file. Defaults to `false`. */
75
131
  readonly hideScriptBlocks?: boolean;
76
132
  }
133
+ export interface ExportRequest extends ExportRenderOptions {
134
+ readonly format: HostExportFormat;
135
+ /** The note's own path, used to name the exported file. */
136
+ readonly notePath: string;
137
+ readonly text: string;
138
+ /** The note's last-run values, baked into an html/pdf export. Omitted or empty exports the note's standard empty states. */
139
+ readonly values?: Record<string, StoredValue>;
140
+ /** Reads one of the note's local images so the export embeds it as a `data:` URI. Omitted leaves every image source as written. */
141
+ readonly embedImages?: ExportImageReader;
142
+ /** Where to write the file. When present the adapter's `resolveTarget` is not asked. */
143
+ readonly targetPath?: string;
144
+ }
77
145
  export type ExportOutcome = {
78
146
  readonly kind: 'exported';
79
147
  readonly path: string;
@@ -90,9 +158,41 @@ export type ExportOutcome = {
90
158
  readonly kind: 'failed';
91
159
  readonly reason: string;
92
160
  }
93
- /** `adapter.exports.resolveTarget`/`htmlToPdf`/an injected `renderAnsi` was unavailable at the moment of export — a picker cancel, or a seam this host declared but did not wire up. */
161
+ /** The picker was cancelled, or a seam this host declared (`htmlToPdf`, an injected `renderAnsi`) was not wired up at the moment of export. Nothing was written. */
162
+ | {
163
+ readonly kind: 'declined';
164
+ } | Unsupported;
165
+ export interface ExportLinkedSetRequest extends ExportRenderOptions {
166
+ /** The root note's path, in whatever form `adapter.readFile` and `resolveLink` understand. */
167
+ readonly rootPath: string;
168
+ /** Resolves one link in a note to the path of a note this host can export, or `undefined` to leave the link as written. */
169
+ readonly resolveLink: CascadeLinkResolver;
170
+ /** Reads one note's persisted last-run values, keyed by that note's own path. An empty object exports that note's standard empty states. */
171
+ readonly readValues: (notePath: string) => Record<string, StoredValue>;
172
+ /** Builds the image reader for one note, bound to that note's own folder. Omitted embeds no images. */
173
+ readonly embedImagesFor?: (notePath: string) => ExportImageReader;
174
+ /** Where to write the archive. When present the adapter's `resolveLinkedSetTarget` is not asked. */
175
+ readonly targetPath?: string;
176
+ }
177
+ export type ExportLinkedSetOutcome = {
178
+ readonly kind: 'exported';
179
+ /** The written archive's display path. */
180
+ readonly path: string;
181
+ readonly bytes: number;
182
+ /** Every note the archive contains, breadth first, the root note first. */
183
+ readonly notes: readonly CascadeExportedNote[];
184
+ /** Notes a link pointed at that could not be read. */
185
+ readonly unreadable: readonly UnreadableCascadeNote[];
186
+ /** Set when a bound stopped the walk before it ran out of links to follow. */
187
+ readonly truncated?: CascadeTruncation;
188
+ } | {
189
+ readonly kind: 'failed';
190
+ readonly path?: string;
191
+ readonly reason: string;
192
+ }
193
+ /** The host's picker was cancelled, so nothing was written. */
94
194
  | {
95
- readonly kind: 'cancelled';
195
+ readonly kind: 'declined';
96
196
  } | Unsupported;
97
197
  export interface InstallPackRequest {
98
198
  readonly archiveBytes: Uint8Array;
@@ -112,8 +212,15 @@ export type InstallPackOutcome = {
112
212
  } | {
113
213
  readonly kind: 'reserved';
114
214
  readonly namespace: string;
115
- } | {
116
- readonly kind: 'rejected';
215
+ }
216
+ /** The archive was read and judged bad: it is not a valid pack archive. Nothing was written. */
217
+ | {
218
+ readonly kind: 'invalid';
219
+ readonly reason: string;
220
+ }
221
+ /** A prompt, a check or a write failed. */
222
+ | {
223
+ readonly kind: 'failed';
117
224
  readonly reason: string;
118
225
  } | Unsupported;
119
226
  export type LoadPacksOutcome = {
@@ -127,6 +234,11 @@ export type LoadPacksOutcome = {
127
234
  readonly components: readonly UnavailableComponent[];
128
235
  /** The installed components with no view for this host's engine, for a renderer's `unavailableComponents` option. */
129
236
  readonly unavailable: readonly UnavailableComponent[];
237
+ }
238
+ /** An adapter primitive rejected while the packs were read. The diagnostics line is already written. */
239
+ | {
240
+ readonly kind: 'failed';
241
+ readonly reason: string;
130
242
  } | Unsupported;
131
243
  export type LoadTerminalPacksOutcome = {
132
244
  readonly kind: 'loaded';
@@ -147,13 +259,76 @@ export type LoadTerminalPacksOutcome = {
147
259
  * shows these.
148
260
  */
149
261
  readonly failureLines: readonly string[];
262
+ }
263
+ /** An adapter primitive rejected while the packs were read. The diagnostics line is already written. */
264
+ | {
265
+ readonly kind: 'failed';
266
+ readonly reason: string;
267
+ } | Unsupported;
268
+ export type RemovePackOutcome = {
269
+ readonly kind: 'removed';
270
+ readonly namespace: string;
271
+ } | {
272
+ readonly kind: 'not-installed';
273
+ readonly namespace: string;
274
+ } | {
275
+ readonly kind: 'reserved';
276
+ readonly namespace: string;
277
+ }
278
+ /** The namespace is not a valid pack name. */
279
+ | {
280
+ readonly kind: 'invalid';
281
+ readonly reason: string;
282
+ } | {
283
+ readonly kind: 'failed';
284
+ readonly reason: string;
150
285
  } | Unsupported;
151
- export type RemovePackResult = RemovePackOutcome | Unsupported;
152
286
  export type InstalledPacksOutcome = ({
153
287
  readonly kind: 'listed';
154
- } & InstalledPacksListing) | Unsupported;
155
- export type EnablePackResult = EnablePackOutcome | Unsupported;
156
- export type DisablePackResult = DisablePackOutcome | Unsupported;
288
+ } & InstalledPacksListing)
289
+ /** An adapter primitive rejected while the install root was read. The diagnostics line is already written. */
290
+ | {
291
+ readonly kind: 'failed';
292
+ readonly reason: string;
293
+ } | Unsupported;
294
+ export type EnablePackOutcome = {
295
+ readonly kind: 'enabled';
296
+ readonly namespace: string;
297
+ }
298
+ /** The user refused the consent prompt. */
299
+ | {
300
+ readonly kind: 'declined';
301
+ readonly namespace: string;
302
+ } | {
303
+ readonly kind: 'not-installed';
304
+ readonly namespace: string;
305
+ } | {
306
+ readonly kind: 'reserved';
307
+ readonly namespace: string;
308
+ }
309
+ /** The namespace is not a valid pack name. */
310
+ | {
311
+ readonly kind: 'invalid';
312
+ readonly reason: string;
313
+ } | {
314
+ readonly kind: 'failed';
315
+ readonly reason: string;
316
+ } | Unsupported;
317
+ export type DisablePackOutcome = {
318
+ readonly kind: 'disabled';
319
+ readonly namespace: string;
320
+ } | {
321
+ readonly kind: 'not-enabled';
322
+ readonly namespace: string;
323
+ }
324
+ /** The namespace is not a valid pack name. */
325
+ | {
326
+ readonly kind: 'invalid';
327
+ readonly reason: string;
328
+ } | {
329
+ readonly kind: 'failed';
330
+ readonly reason: string;
331
+ } | Unsupported;
157
332
  export interface EditorPositionRequest {
158
333
  readonly line: number;
159
334
  readonly column: number;
@@ -181,6 +356,11 @@ export type CompleteOutcome = {
181
356
  /** Nothing to offer here: no directive context, or a bare colon run closing an open container. Not a failure. */
182
357
  | {
183
358
  readonly kind: 'none';
359
+ }
360
+ /** The editor or the catalog threw. The diagnostics line is already written. */
361
+ | {
362
+ readonly kind: 'failed';
363
+ readonly reason: string;
184
364
  } | Unsupported;
185
365
  export type HoverOutcome = {
186
366
  readonly kind: 'hover';
@@ -192,6 +372,11 @@ export type HoverOutcome = {
192
372
  readonly end: number;
193
373
  } | {
194
374
  readonly kind: 'none';
375
+ }
376
+ /** The editor or the catalog threw. The diagnostics line is already written. */
377
+ | {
378
+ readonly kind: 'failed';
379
+ readonly reason: string;
195
380
  } | Unsupported;
196
381
  export interface InsertComponentRequest {
197
382
  readonly name: string;
@@ -211,13 +396,27 @@ export type InsertOutcome = {
211
396
  } | {
212
397
  readonly kind: 'not-found';
213
398
  readonly name: string;
214
- } | {
399
+ }
400
+ /** The edit was not applied, or the editor or the catalog threw. The diagnostics line is already written. */
401
+ | {
215
402
  readonly kind: 'failed';
403
+ readonly reason: string;
216
404
  } | Unsupported;
217
405
  export interface MarkiiHost {
218
406
  open(request: OpenRequest): Promise<OpenOutcome>;
219
407
  run(request: RunRequest): Promise<RunOutcome>;
408
+ /**
409
+ * What the last run of `documentKey` left in the adapter's memento: the
410
+ * values as they should be shown on open, the values as stored, and the
411
+ * recorded trace. Empty when nothing is stored. Synchronous, because the
412
+ * memento read is.
413
+ */
414
+ lastRun(documentKey: string): LastRunOutcome;
415
+ /** Clears the stored script grants of `documentKey`, so its next manual run prompts again for every host. Nothing stored is not an error. */
416
+ forgetGrants(documentKey: string): Promise<void>;
220
417
  exportNote(request: ExportRequest): Promise<ExportOutcome>;
418
+ /** Exports a note and the notes it links to as one zip archive of HTML files. */
419
+ exportLinkedSet(request: ExportLinkedSetRequest): Promise<ExportLinkedSetOutcome>;
221
420
  installPack(request: InstallPackRequest): Promise<InstallPackOutcome>;
222
421
  loadPacks(): Promise<LoadPacksOutcome>;
223
422
  /**
@@ -227,7 +426,7 @@ export interface MarkiiHost {
227
426
  */
228
427
  loadTerminalPacks(): Promise<LoadTerminalPacksOutcome>;
229
428
  /** Removes one installed pack by namespace, through the install root. Writes its outcome to the diagnostics surface. Under `trust: 'device-list'` it also withdraws the namespace's trust entry. */
230
- removePack(namespace: string): Promise<RemovePackResult>;
429
+ removePack(namespace: string): Promise<RemovePackOutcome>;
231
430
  /**
232
431
  * Under `trust: 'device-list'`: the install root's folders split into the
233
432
  * ones this device has enabled and the ones merely present. Unsupported
@@ -235,9 +434,9 @@ export interface MarkiiHost {
235
434
  */
236
435
  installedPacks(): Promise<InstalledPacksOutcome>;
237
436
  /** Asks the install consent prompt, then trusts an installed folder on this device. Unsupported without the trust list. */
238
- enablePack(namespace: string): Promise<EnablePackResult>;
437
+ enablePack(namespace: string): Promise<EnablePackOutcome>;
239
438
  /** Withdraws a namespace's trust entry and leaves its folder in place. Unsupported without the trust list. */
240
- disablePack(namespace: string): Promise<DisablePackResult>;
439
+ disablePack(namespace: string): Promise<DisablePackOutcome>;
241
440
  completeAt(request: EditorPositionRequest): Promise<CompleteOutcome>;
242
441
  /**
243
442
  * `completeAt` for a caller that must answer synchronously (Obsidian's
@@ -253,19 +452,26 @@ export interface MarkiiHost {
253
452
  diagnostics(line: string): void;
254
453
  }
255
454
  /**
256
- * Injectables a test needs to make a run/export deterministic. Defaults
257
- * are the real implementations; no option changes behavior for a real
258
- * host.
455
+ * What an outside host may pass to `createMarkiiHost`. Neither field
456
+ * changes what a behavior decides; each supplies an engine this package
457
+ * never imports itself.
259
458
  */
260
459
  export interface MarkiiHostOptions {
261
- readonly spawnRun?: (options: SpawnRunRequest) => Promise<RunResult>;
262
460
  /** The static HTML engine behind the `html` and `pdf` exports (`createHtmlExportEngine()` from `@markii/host/html-engine`). Without it those formats decline, like `renderAnsi` for `ansi`. */
263
461
  readonly htmlEngine?: HtmlExportEngine;
264
- /** Pack discovery's file reads. Defaults to reads through the adapter's own `readFile` and `listFolder`. */
265
- readonly packDiscoveryIo?: PackDiscoveryIo;
266
462
  /** `@markii/ansi`'s renderer, injected because this package never depends on `@markii/ansi` (a platform renderer, never a `@markii/host` dependency). A host declaring `'ansi'` in `adapter.exports.formats` without supplying this gets `Unsupported` at export time. */
267
463
  readonly renderAnsi?: (text: string) => Promise<string>;
268
- /** Composes a pack-aware render registry (webview registration, in-process evaluation, ...). Reserved for a future slice that renders through `exportNote`'s `html` path with packs; unused today, since `buildExportDocument`'s default (no `renderBody`) already produces a correct, pack-free static export. */
269
- readonly buildPackRegistration?: unknown;
464
+ }
465
+ /**
466
+ * The test seams of `createMarkiiHostWithSeams`, which `@markii/host/internal`
467
+ * exports. They make a run or a pack discovery deterministic. Defaults are
468
+ * the real implementations.
469
+ */
470
+ export interface MarkiiHostSeams extends MarkiiHostOptions {
471
+ readonly spawnRun?: (options: SpawnRunRequest) => Promise<RunResult>;
472
+ /** Pack discovery's file reads. Defaults to reads through the adapter's own `readFile` and `listFolder`. */
473
+ readonly packDiscoveryIo?: PackDiscoveryIo;
270
474
  }
271
475
  export declare function createMarkiiHost(adapter: HostAdapter, options?: MarkiiHostOptions): MarkiiHost;
476
+ /** `createMarkiiHost` with the test seams. Exported from `@markii/host/internal` only. */
477
+ export declare function createMarkiiHostWithSeams(adapter: HostAdapter, options?: MarkiiHostSeams): MarkiiHost;