@llblab/pi-actors 0.49.2 → 0.51.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/AGENTS.md +1 -1
- package/BACKLOG.md +1 -11
- package/CHANGELOG.md +17 -1
- package/README.md +22 -4
- package/dist/index.js +1 -1
- package/dist/lib/extension-runtime.d.ts +1 -1
- package/dist/lib/extension-runtime.js +1 -1
- package/dist/lib/inspector-overlay.d.ts +3 -0
- package/dist/lib/inspector-overlay.js +120 -38
- package/dist/lib/limits.d.ts +1 -0
- package/dist/lib/limits.js +1 -0
- package/dist/lib/observability.js +3 -1
- package/dist/lib/runs-artifacts.js +24 -4
- package/dist/lib/session-evidence.d.ts +1 -0
- package/dist/lib/session-evidence.js +3 -2
- package/dist/lib/state-readers.d.ts +5 -1
- package/dist/lib/state-readers.js +30 -3
- package/dist/lib/tools-access.d.ts +1 -0
- package/dist/lib/tools-access.js +13 -11
- package/dist/lib/tools-inspect.js +5 -5
- package/dist/lib/tools-message.d.ts +1 -0
- package/dist/lib/tools-message.js +3 -1
- package/dist/scripts/async-runner.mjs +5 -19
- package/docs/README.md +1 -0
- package/docs/actor-inspector.md +21 -5
- package/docs/async-runs.md +22 -7
- package/docs/command-templates.md +5 -4
- package/docs/inspection.md +83 -0
- package/docs/recipe-library.md +1 -1
- package/docs/template-recipes.md +225 -66
- package/docs/tool-registry.md +24 -3
- package/index.ts +1 -1
- package/lib/extension-runtime.ts +2 -2
- package/lib/inspector-overlay.ts +161 -33
- package/lib/limits.ts +1 -0
- package/lib/observability.ts +2 -1
- package/lib/runs-artifacts.ts +34 -4
- package/lib/session-evidence.ts +7 -2
- package/lib/state-readers.ts +45 -3
- package/lib/tools-access.ts +26 -12
- package/lib/tools-inspect.ts +9 -5
- package/lib/tools-message.ts +8 -1
- package/package.json +3 -3
- package/scripts/async-runner.mjs +5 -19
package/AGENTS.md
CHANGED
|
@@ -84,7 +84,7 @@ Canonical event:
|
|
|
84
84
|
{"id":"…","ts":"…","kind":"…","summary":"…","data":{},"level":"info","attention":"notify"}
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
Trace is a bounded retained suffix, not an audit archive. Every first-party writer must call `appendRunTraceEvent`; under the canonical token-owned lock it appends within both fixed bounds or atomically retains the newest suffix plus one cumulative warning-only `runtime.trace_compacted` marker. The marker means older history was discarded; terminal/result/execution/artifact files remain authoritative independently. Reads are newline-safe and order equal timestamps by same-source ordinal, fixed source rank, then stable id without exposing ordering metadata. Never write `trace.jsonl` directly.
|
|
87
|
+
Trace is a bounded retained suffix, not an audit archive. Every first-party writer must call `appendRunTraceEvent`; under the canonical token-owned lock it appends within both fixed bounds or atomically retains the newest suffix plus one cumulative warning-only `runtime.trace_compacted` marker. The marker means older history was discarded; terminal/result/execution/artifact files remain authoritative independently. Reads are newline-safe and order equal timestamps by same-source ordinal, fixed source rank, then stable id without exposing ordering metadata. Never write `trace.jsonl` directly. Generic command lifecycle is Trace-only: `command.done` preserves complete bounded execution evidence but never requests or projects attention, and Recipe grammar has no command-completion delivery switch. Attention is an explicit semantic wake hint: persist durable state or an artifact first; `attention: "followup"` remains rare. Reconcile root terminal transitions before attention. One normal finite Run defaults to one automatic agent turn from its root terminal result; sequence, parallel, repeat, and import branches remain internal, while each separately launched Run owns a separate generation.
|
|
88
88
|
|
|
89
89
|
### Control
|
|
90
90
|
|
package/BACKLOG.md
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
# Project Backlog
|
|
2
2
|
|
|
3
|
-
- [ ] `
|
|
4
|
-
- [ ] `Run boundary checkpoint`: Public Run operations remain owner-safe and bounded under missing identity and adversarial evidence sizes.
|
|
5
|
-
- [ ] Make Run-specific `inspect` and `message` operations fail closed when the caller session identity is unavailable, keep runtime inventory owner-filtered, and add missing-context plus cross-owner regressions.
|
|
6
|
-
- [ ] Bound session-evidence and artifact-manifest inspection before full-file materialization; use capped/streaming reads or hashing as appropriate and add adversarial-size regressions.
|
|
7
|
-
- [ ] `Operator truth checkpoint`: Public status and recovery guidance exactly match supported runtime behavior.
|
|
8
|
-
- [ ] Route automatic-review status through the canonical policy parser so `0`, `false`, and `off` are reported consistently without case sensitivity.
|
|
9
|
-
- [ ] Replace the removed `session:<id>` and `session:all` recovery hints with supported inspection guidance.
|
|
10
|
-
- [ ] Document exact `message target=run:<id>` examples for runtime-owned `kill`, `archive`, and `prune`, including their state and artifact-preservation constraints.
|
|
11
|
-
- [ ] Pass focused boundary and operator-contract regressions plus full package validation before release.
|
|
12
|
-
|
|
13
|
-
- [ ] `Future minor — Linux MPRIS media integration`: Expose the active `music-player/playback` singleton as one optional generation-fenced MPRIS2 player so GNOME and compatible desktop shells can show current media and native controls without making D-Bus a second playback authority; keep this feature outside the 0.49.2 and 0.50.0 cohorts.
|
|
3
|
+
- [ ] `Future minor — Linux MPRIS media integration`: Expose the active `music-player/playback` singleton as one optional generation-fenced MPRIS2 player so GNOME and compatible desktop shells can show current media and native controls without making D-Bus a second playback authority.
|
|
14
4
|
- [ ] Publish `PlaybackStatus`, track metadata, duration, read-time position, volume, and supported capabilities under one stable session-scoped bus identity; disappear cleanly when the Run stops or its generation is replaced, and fail soft when the user D-Bus session is unavailable.
|
|
15
5
|
- [ ] Map `Play`, `Pause`, `PlayPause`, `Next`, `Previous`, `Stop`, `Seek`, `SetPosition`, and `Volume` back into the existing generation-fenced music-player Control/helper contract rather than signaling the backend or editing Run state directly.
|
|
16
6
|
- [ ] Validate deterministic D-Bus contract behavior plus a live GNOME smoke showing the media surface, metadata, progress, volume, and controls while preserving backend independence and exact Actor ownership.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
> Each release keeps at most 8 outcome records of at most 512 characters.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 0.51.0: Monotonic Run Follow-Ups
|
|
6
|
+
|
|
7
|
+
- `Root-Owned Follow-Up`: A normal finite Run now produces one automatic agent turn from its root terminal result. Sequence, parallel, repeat, and imported branches remain internal execution topology; each separately launched Run still owns a separate generation and terminal lifecycle.
|
|
8
|
+
- `Trace-Only Command Lifecycle`: Consolidates each command completion into one complete bounded `command.done` observation with level, captures, session provenance, artifacts, and execution evidence, but no attention. Legacy `command.done` attention remains non-projectable, and the removed Recipe-level delivery grammar stays removed.
|
|
9
|
+
- `Monotonic Reconciliation`: Delivers terminal transitions before explicit semantic attention, preserves silent Runs, synchronous stop behavior, generation fencing, terminal retry evidence, and semantic checkpoints, and removes branch exit-code heuristics that could wake the coordinator from stale process-level events.
|
|
10
|
+
- `Settled Pi Baseline`: Requires Pi and Pi TUI 0.84.4 or newer and schedules automatic Recipe review on `agent_settled`, after queued follow-ups, retries, and compaction complete. Source and packed-package regressions pin the lifecycle and minimum peer contract.
|
|
11
|
+
|
|
12
|
+
## 0.50.0: Hardened Actor Baseline
|
|
13
|
+
|
|
14
|
+
- `Template Recipe Standard`: Rebuilt the Recipe authoring guide around one current-state contract: formats, identity, uniformly detailed file-level and command-node field tables, resolution precedence, imports, async/singleton lifecycle, Control, artifacts, runtime origins, provenance, authoring workflow, and validation. Removed migration history and legacy-reference narration from the normative document.
|
|
15
|
+
- `Documentation Contract Reconciliation`: Audited every human-facing document against package metadata, public schemas, implementation, maintained Skills, and tests. Added the canonical Inspect target/view matrix and exact-owner authorization boundary; completed installation, runtime triage, registered-tool lifecycle/schema, detached-build, and bounded-evidence guidance; corrected lifecycle ownership, command-template shapes, Inspector zero-based navigation/focus behavior, and remaining historical or ambiguous prose.
|
|
16
|
+
- `Owner-Safe Public Runs`: Run-specific Inspect and Control now require a live coordinator identity, reject ownerless and cross-owner state, and keep runtime Run inventory exact-owner filtered. Missing-session and mismatch failures provide supported runtime inspection guidance instead of removed session targets.
|
|
17
|
+
- `Bounded Evidence Inspection`: Session evidence rejects oversized JSONL before materialization with explicit truncation diagnostics, while artifact manifests compute exact size and SHA-256 through fixed-size chunks instead of loading complete artifacts into memory.
|
|
18
|
+
- `Operator Truth`: Runtime status now uses the canonical automatic-review policy for `0`, `false`, and case-insensitive `off`. Maintained guidance documents exact runtime-owned `kill`, `archive`, and artifact-preserving `prune` calls with their running/terminal state constraints.
|
|
19
|
+
- `Consistent Inspector Indexing`: Actor Inspector now uses zero-based numbering for Runs, Trace rows, and complex array items. Structured items render as accent keys such as `#0: {` on one line, removing list bullets and redundant opening-brace rows while preserving nested indentation, commas, wrapping, and object-label grammar.
|
|
20
|
+
- `Inspector Focus Semantics`: Alternating content stripes retain `customMessageBg`, while focused Run controls, tabs, Trace rows, selector options, and confirmation choices use `selectedBg`. Trace focus gains symmetric trailing padding and composes its selected span beside—rather than around—the independent full-row stripe, avoiding nested ANSI background resets.
|
|
21
|
+
- `Layered Inspector Selectors`: Run choices open directly below the focused Run control, and Trace-source choices below the focused tabs. Each menu is ANSI-aware composited over only its bounded rectangle while the underlying tabs, separator, documents, Trace rows, stripes, overlay height, and footer remain rendered and restore unchanged on close. The parent Run control or Trace tab retains `selectedBg` while its child selector is active. Trace-source choices use the compact `Trace: <source>` label, begin twelve cells into the base layer beneath the tab region, and preserve distinct label/value colors under selection. A non-`all` source projects onto the parent tab with the same colon grammar and value color while `Trace:`, including the colon, and its focus brackets retain their established tab accent. Run choices use aligned zero-based sequence, name, and status columns without a redundant `run:` prefix, preserve the same semantic status colors as the parent control, and begin four cells inside the outer frame. Both insets preserve—rather than blank—the underlying base-layer prefix before the composited menu rectangle.
|
|
6
22
|
|
|
7
23
|
## 0.49.2: Stale-Context Lifecycle Hotfix
|
|
8
24
|
|
package/README.md
CHANGED
|
@@ -19,6 +19,8 @@ This topology does not require every task to become a subagent. Short work with
|
|
|
19
19
|
|
|
20
20
|
## Install
|
|
21
21
|
|
|
22
|
+
Requires Node.js 22.19.0 or newer and Pi 0.84.4 or newer.
|
|
23
|
+
|
|
22
24
|
```bash
|
|
23
25
|
pi install npm:@llblab/pi-actors
|
|
24
26
|
```
|
|
@@ -59,7 +61,7 @@ Send one exact Control:
|
|
|
59
61
|
}
|
|
60
62
|
```
|
|
61
63
|
|
|
62
|
-
Run targets accept
|
|
64
|
+
Run targets accept Recipe-declared actor-local actions plus runtime-owned `kill`, `archive`, and `prune`, subject to Run state. Runtime targets accept only reserved review actions:
|
|
63
65
|
|
|
64
66
|
```text
|
|
65
67
|
message target=runtime action=review.retry input={"scope":"draft"}
|
|
@@ -79,12 +81,14 @@ inspect target=run:test view=recipe
|
|
|
79
81
|
inspect target=run:test view=trace source=lifecycle lines=40
|
|
80
82
|
inspect target=run:test view=control
|
|
81
83
|
inspect target=runtime view=status
|
|
84
|
+
inspect target=runtime view=runs status=failed
|
|
85
|
+
inspect target=runtime view=triage
|
|
82
86
|
inspect target=recipes view=status
|
|
83
87
|
inspect target=recipes view=doctor identity=music-player/playback
|
|
84
88
|
inspect target=tool:my_tool view=status
|
|
85
89
|
```
|
|
86
90
|
|
|
87
|
-
A Run exposes exactly `recipe`, `trace`, and `control` views.
|
|
91
|
+
A Run exposes exactly `recipe`, `trace`, and `control` views. Run-specific `inspect` and `message` require a current coordinator session whose id exactly matches the persisted non-empty Run owner; possessing `run:<id>` alone is not authorization. Missing-session, ownerless, and cross-owner access fails closed. Use `inspect target=runtime view=runs` for the current session's exact-owner inventory. See the complete [management inspection matrix](./docs/inspection.md).
|
|
88
92
|
|
|
89
93
|
### `register_tool`
|
|
90
94
|
|
|
@@ -147,11 +151,23 @@ String command-template leaves execute directly without shell interpretation. Us
|
|
|
147
151
|
|
|
148
152
|
Trace fields are exact: `id`, `ts`, `kind`, and optional `summary`, `data`, `level`, `attention`. Address, sender, recipient, reply, and routing fields fail validation. Trace is a bounded retained suffix, not an audit archive: the canonical authority appends within 2,048 events and 4 MiB or atomically keeps the newest suffix plus one warning-only `runtime.trace_compacted` marker. That marker means older history was discarded; `result.json`, `execution.json`, terminal state, and declared artifacts retain their own authority. `inspect view=trace` reports whether retained history is complete. Reads are newline-safe and deterministic; first-party scripts never write this file directly.
|
|
149
153
|
|
|
150
|
-
Attention is a live wake hint, not a durable queue: persist recovery state or an artifact first
|
|
154
|
+
Generic command lifecycle is Trace-only: runner-owned `command.done` records preserve completion and execution evidence but never request or project attention. There is no Recipe-level command-completion delivery switch. Attention is an explicit semantic opt-in and a live wake hint, not a durable queue: persist recovery state or an artifact first, use `attention: "notify"` for visible status and `attention: "followup"` only when the coordinator needs semantic follow-up context, and expect compaction to discard older hints. Store large evidence in artifacts or bounded execution captures.
|
|
155
|
+
|
|
156
|
+
By default, one normal finite Run produces one automatic agent turn from its root terminal result. Sequence, parallel, repeat, and imported branches remain internal to that Run and do not create branch-level turns; each separately launched Run owns its own generation and terminal follow-up.
|
|
151
157
|
|
|
152
158
|
## Control
|
|
153
159
|
|
|
154
|
-
Controls persist to `controls.jsonl` before transport. One token-owned lock rejects a 65th pending Control or 1 MiB rewrite before admission, fails closed on malformed or stale-generation evidence, and atomically admits one record. Canonical transitions retain a 128-terminal tail, expected-state fencing, and 4 KiB errors. Admitted nonterminal Controls never expire automatically. Every record carries immutable `run_instance_id`. `inspect view=control` reports pending capacity, saturation, stale work, journal bytes, and bounded diagnostics.
|
|
160
|
+
Controls persist to `controls.jsonl` before transport. One token-owned lock rejects a 65th pending Control or 1 MiB rewrite before admission, fails closed on malformed or stale-generation evidence, and atomically admits one record. Canonical transitions retain a 128-terminal tail, expected-state fencing, and 4 KiB errors. Admitted nonterminal Controls never expire automatically. Every record carries immutable `run_instance_id`. `inspect view=control` reports pending capacity, saturation, stale work, journal bytes, and bounded diagnostics.
|
|
161
|
+
|
|
162
|
+
Runtime-owned lifecycle and retention actions use the same `message` tool:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
message target=run:<id> action=kill
|
|
166
|
+
message target=run:<id> action=archive
|
|
167
|
+
message target=run:<id> action=prune input={"preserve_artifacts":true}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`kill` accepts only a currently running owned generation, bypasses actor-local capacity, and creates no synthetic Control. `archive` and `prune` accept only terminal owned Runs. Archive moves the entire Run state directory and leaves a tombstone. Prune removes Run state; declared existing artifacts survive only when `preserve_artifacts` is explicitly true, in which case they are copied to retained artifact storage before removal.
|
|
155
171
|
|
|
156
172
|
Long-lived services publish `control-endpoint.json` only when ready:
|
|
157
173
|
|
|
@@ -222,6 +238,8 @@ npm run validate
|
|
|
222
238
|
npm run test:preservation
|
|
223
239
|
```
|
|
224
240
|
|
|
241
|
+
The build produces the JavaScript runtime used by detached Actor processes in npm installations. Pi can load a TypeScript extension entrypoint, but standalone Node processes cannot type-strip modules under `node_modules`; keeping compiled Run modules preserves process isolation without a runtime TypeScript loader.
|
|
242
|
+
|
|
225
243
|
See the [documentation index](./docs/README.md), [Run lifecycle](./docs/async-runs.md), and [Recipe library](./docs/recipe-library.md).
|
|
226
244
|
|
|
227
245
|
Project context: [AGENTS.md](./AGENTS.md) · [BACKLOG.md](./BACKLOG.md) · [CHANGELOG.md](./CHANGELOG.md).
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export default function toolRegistryExtension(pi) {
|
|
|
9
9
|
const runtime = ExtensionRuntime.createActorExtensionRuntime(pi);
|
|
10
10
|
pi.on("resources_discover", async () => runtime.discoverResources(import.meta.url));
|
|
11
11
|
pi.on("session_start", async (_event, ctx) => runtime.onSessionStart(ctx));
|
|
12
|
-
pi.on("
|
|
12
|
+
pi.on("agent_settled", async (_event, ctx) => runtime.onAgentSettled(ctx));
|
|
13
13
|
pi.on("session_shutdown", async (event, ctx) => runtime.onSessionShutdown(event.reason, ctx));
|
|
14
14
|
pi.on("before_agent_start", async (event, ctx) => runtime.beforeAgentStart(event.systemPrompt, event.systemPromptOptions.skills ?? [], ctx));
|
|
15
15
|
InspectorCommand.registerActorInspectorCommand(pi, runtime.getRunOwnerId);
|
|
@@ -13,7 +13,7 @@ export interface ActorExtensionRuntime {
|
|
|
13
13
|
skillPaths: string[];
|
|
14
14
|
} | undefined;
|
|
15
15
|
getRunOwnerId(ctx: Pi.ExtensionContext): string;
|
|
16
|
-
|
|
16
|
+
onAgentSettled(ctx: Pi.ExtensionContext): void;
|
|
17
17
|
onSessionShutdown(reason: string, ctx: Pi.ExtensionContext): void;
|
|
18
18
|
onSessionStart(ctx: Pi.ExtensionContext): Promise<void>;
|
|
19
19
|
registerCoreTools(): void;
|
|
@@ -112,7 +112,7 @@ export function createActorExtensionRuntime(pi) {
|
|
|
112
112
|
return skillPaths.length > 0 ? { skillPaths } : undefined;
|
|
113
113
|
},
|
|
114
114
|
getRunOwnerId,
|
|
115
|
-
|
|
115
|
+
onAgentSettled(ctx) {
|
|
116
116
|
if (activeRunContext === ctx)
|
|
117
117
|
automaticReview.schedule();
|
|
118
118
|
},
|
|
@@ -32,6 +32,7 @@ export declare class ActorInspectorOverlay {
|
|
|
32
32
|
private readonly theme;
|
|
33
33
|
private readonly tui;
|
|
34
34
|
private readonly refreshTimer;
|
|
35
|
+
private contentSelectedRows;
|
|
35
36
|
private contentStripeIndices;
|
|
36
37
|
private documentScroll;
|
|
37
38
|
private detailScroll;
|
|
@@ -71,6 +72,7 @@ export declare class ActorInspectorOverlay {
|
|
|
71
72
|
private renderTabs;
|
|
72
73
|
private renderContent;
|
|
73
74
|
private renderSelector;
|
|
75
|
+
private runSelectorOptions;
|
|
74
76
|
private renderMenuBox;
|
|
75
77
|
private renderTraceList;
|
|
76
78
|
private renderTraceDetail;
|
|
@@ -91,6 +93,7 @@ export declare class ActorInspectorOverlay {
|
|
|
91
93
|
private renderKeyHints;
|
|
92
94
|
private statusColor;
|
|
93
95
|
private footerBorder;
|
|
96
|
+
private compositeMenuLine;
|
|
94
97
|
private stripeBackground;
|
|
95
98
|
private stripedRow;
|
|
96
99
|
private row;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync, statSync } from "node:fs";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
-
import { matchesKey, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
8
|
+
import { matchesKey, sliceByColumn, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
9
9
|
import * as ActorInspector from "./inspector.js";
|
|
10
10
|
import * as ControlProjection from "./control-projection.js";
|
|
11
11
|
import * as RunsControls from "./runs-controls.js";
|
|
@@ -35,6 +35,7 @@ export class ActorInspectorOverlay {
|
|
|
35
35
|
theme;
|
|
36
36
|
tui;
|
|
37
37
|
refreshTimer;
|
|
38
|
+
contentSelectedRows = new Set();
|
|
38
39
|
contentStripeIndices = [];
|
|
39
40
|
documentScroll = 0;
|
|
40
41
|
detailScroll = 0;
|
|
@@ -219,9 +220,10 @@ export class ActorInspectorOverlay {
|
|
|
219
220
|
if (this.killConfirmation)
|
|
220
221
|
return this.renderKillDialog(innerWidth);
|
|
221
222
|
const lines = [this.border("╭", " Actor Inspector ", "╮", innerWidth)];
|
|
222
|
-
lines.push(this.row(this.renderRunControl(run, runs.length - this.runIndex), innerWidth));
|
|
223
|
+
lines.push(this.row(this.renderRunControl(run, runs.length - this.runIndex - 1), innerWidth));
|
|
223
224
|
lines.push(this.row(this.renderTabs(run), innerWidth));
|
|
224
225
|
lines.push(this.border("├", "", "┤", innerWidth));
|
|
226
|
+
this.contentSelectedRows.clear();
|
|
225
227
|
this.contentStripeIndices = [];
|
|
226
228
|
let content = this.renderContent(run, innerWidth);
|
|
227
229
|
if (this.feedback) {
|
|
@@ -231,14 +233,28 @@ export class ActorInspectorOverlay {
|
|
|
231
233
|
? "error"
|
|
232
234
|
: "warning";
|
|
233
235
|
content = [this.theme.fg(color, ` ${this.feedback.message}`), ...content];
|
|
236
|
+
this.contentSelectedRows = new Set([...this.contentSelectedRows].map((index) => index + 1));
|
|
234
237
|
this.contentStripeIndices = [0, ...this.contentStripeIndices];
|
|
235
238
|
}
|
|
236
239
|
const viewportRows = this.contentViewportRows();
|
|
237
240
|
content = content.slice(0, viewportRows);
|
|
238
241
|
for (let index = 0; index < viewportRows; index += 1) {
|
|
239
|
-
lines.push(this.stripedRow(content[index] ?? "", innerWidth, this.contentStripeIndices[index] ?? index));
|
|
242
|
+
lines.push(this.stripedRow(content[index] ?? "", innerWidth, this.contentStripeIndices[index] ?? index, this.contentSelectedRows.has(index)));
|
|
240
243
|
}
|
|
241
244
|
lines.push(this.footerBorder(this.renderKeyHints(), innerWidth));
|
|
245
|
+
if (this.focus === "select") {
|
|
246
|
+
const runSelector = this.selectorMode === "run";
|
|
247
|
+
const startRow = runSelector ? 2 : 3;
|
|
248
|
+
const horizontalOffset = runSelector ? 4 : 12;
|
|
249
|
+
const availableRows = Math.max(3, lines.length - startRow - 1);
|
|
250
|
+
const menu = this.renderSelector(run, availableRows);
|
|
251
|
+
for (const [offset, menuLine] of menu.entries()) {
|
|
252
|
+
const target = startRow + offset;
|
|
253
|
+
if (target >= lines.length - 1)
|
|
254
|
+
break;
|
|
255
|
+
lines[target] = this.compositeMenuLine(lines[target], menuLine, innerWidth, horizontalOffset);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
242
258
|
return lines;
|
|
243
259
|
}
|
|
244
260
|
get tab() {
|
|
@@ -399,10 +415,10 @@ export class ActorInspectorOverlay {
|
|
|
399
415
|
renderKillDialog(innerWidth) {
|
|
400
416
|
const confirmation = this.killConfirmation;
|
|
401
417
|
const cancel = this.killDialogChoice === "cancel"
|
|
402
|
-
? this.theme.bg("
|
|
418
|
+
? this.theme.bg("selectedBg", this.theme.fg("accent", " Cancel "))
|
|
403
419
|
: this.theme.fg("muted", " Cancel ");
|
|
404
420
|
const kill = this.killDialogChoice === "kill"
|
|
405
|
-
? this.theme.bg("
|
|
421
|
+
? this.theme.bg("selectedBg", this.theme.fg("error", " Kill actor "))
|
|
406
422
|
: this.theme.fg("error", " Kill actor ");
|
|
407
423
|
const body = [
|
|
408
424
|
"",
|
|
@@ -433,30 +449,36 @@ export class ActorInspectorOverlay {
|
|
|
433
449
|
const suffix = active ? this.theme.fg("accent", " → ") : " ";
|
|
434
450
|
if (!run) {
|
|
435
451
|
const empty = this.theme.fg("muted", `${prefix}Run: none${suffix}`);
|
|
436
|
-
return
|
|
452
|
+
return active ? this.theme.bg("selectedBg", empty) : empty;
|
|
437
453
|
}
|
|
438
454
|
const value = `${prefix}${this.theme.fg("muted", "Run: ")}${this.theme.fg("text", `#${sequence}`)} ${this.theme.fg("accent", run.run)} ${this.theme.fg(this.statusColor(run.status), run.status)}${suffix}`;
|
|
439
|
-
return
|
|
455
|
+
return active ? this.theme.bg("selectedBg", value) : value;
|
|
440
456
|
}
|
|
441
457
|
renderTabs(run) {
|
|
442
458
|
const source = this.traceSource(run);
|
|
443
459
|
return TABS.map((tab, index) => {
|
|
444
460
|
const base = `${tab[0].toUpperCase()}${tab.slice(1)}`;
|
|
445
|
-
const label = tab === "trace" && source !== "all" ? `${base}
|
|
461
|
+
const label = tab === "trace" && source !== "all" ? `${base}: ${source}` : base;
|
|
446
462
|
const selected = index === this.tabIndex;
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return this.theme.fg("muted",
|
|
451
|
-
|
|
452
|
-
|
|
463
|
+
const bracketed = selected && this.focus !== "runs";
|
|
464
|
+
if (!selected) {
|
|
465
|
+
const display = bracketed ? `[ ${label} ]` : ` ${label} `;
|
|
466
|
+
return this.theme.fg("muted", ` ${display} `);
|
|
467
|
+
}
|
|
468
|
+
const coloredLabel = tab === "trace" && source !== "all"
|
|
469
|
+
? `${this.theme.fg("accent", `${base}:`)} ${this.theme.fg("text", source)}`
|
|
470
|
+
: this.theme.fg("accent", label);
|
|
471
|
+
const colored = bracketed
|
|
472
|
+
? ` ${this.theme.fg("accent", "[ ")}${coloredLabel}${this.theme.fg("accent", " ]")} `
|
|
473
|
+
: ` ${coloredLabel} `;
|
|
474
|
+
const active = this.focus === "tabs"
|
|
475
|
+
|| (this.focus === "select" && this.selectorMode === "source");
|
|
476
|
+
return active ? this.theme.bg("selectedBg", colored) : colored;
|
|
453
477
|
}).join(" ");
|
|
454
478
|
}
|
|
455
479
|
renderContent(run, width) {
|
|
456
480
|
if (!run)
|
|
457
481
|
return [this.theme.fg("muted", " No owned actor runs")];
|
|
458
|
-
if (this.focus === "select")
|
|
459
|
-
return this.renderSelector(run);
|
|
460
482
|
if (this.focus === "detail")
|
|
461
483
|
return this.renderTraceDetail(width);
|
|
462
484
|
if (this.tab === "trace")
|
|
@@ -471,30 +493,49 @@ export class ActorInspectorOverlay {
|
|
|
471
493
|
this.contentStripeIndices = projection.stripes.slice(this.documentScroll, this.documentScroll + this.contentViewportRows());
|
|
472
494
|
return projection.lines.slice(this.documentScroll, this.documentScroll + this.contentViewportRows());
|
|
473
495
|
}
|
|
474
|
-
renderSelector(run) {
|
|
496
|
+
renderSelector(run, availableRows) {
|
|
475
497
|
const options = this.selectorMode === "run"
|
|
476
|
-
? this.
|
|
477
|
-
: this.traceSources(run).map((source) =>
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
498
|
+
? this.runSelectorOptions()
|
|
499
|
+
: this.traceSources(run).map((source) => ({
|
|
500
|
+
content: `${this.theme.fg("accent", "Trace:")} ${this.theme.fg("text", source)}`,
|
|
501
|
+
preserveColors: true,
|
|
502
|
+
}));
|
|
503
|
+
return this.renderMenuBox(options, this.selectorIndex, availableRows);
|
|
504
|
+
}
|
|
505
|
+
runSelectorOptions() {
|
|
506
|
+
const runs = this.runs();
|
|
507
|
+
const sequenceWidth = Math.max(2, ...runs.map((_item, index) => `#${runs.length - index - 1}`.length));
|
|
508
|
+
const runWidth = Math.max(1, ...runs.map((item) => visibleWidth(item.run)));
|
|
509
|
+
return runs.map((item, index) => ({
|
|
510
|
+
content: [
|
|
511
|
+
this.theme.fg("text", this.fit(`#${runs.length - index - 1}`, sequenceWidth)),
|
|
512
|
+
this.theme.fg("accent", this.fit(item.run, runWidth)),
|
|
513
|
+
this.theme.fg(this.statusColor(item.status), item.status),
|
|
514
|
+
].join(" "),
|
|
515
|
+
preserveColors: true,
|
|
516
|
+
}));
|
|
517
|
+
}
|
|
518
|
+
renderMenuBox(options, focusedIndex, availableRows) {
|
|
483
519
|
if (options.length === 0)
|
|
484
520
|
return [this.theme.fg("muted", " No options")];
|
|
485
|
-
const visibleLimit = Math.max(1, Math.min(
|
|
521
|
+
const visibleLimit = Math.max(1, Math.min(availableRows - 2, options.length));
|
|
486
522
|
const maxStart = Math.max(0, options.length - visibleLimit);
|
|
487
523
|
const start = Math.max(0, Math.min(focusedIndex - Math.floor(visibleLimit / 2), maxStart));
|
|
488
524
|
const visible = options.slice(start, start + visibleLimit);
|
|
489
|
-
const width = Math.max(8, ...options.map((option) => visibleWidth(option) + 4));
|
|
525
|
+
const width = Math.max(8, ...options.map((option) => visibleWidth(option.content) + 4));
|
|
490
526
|
const border = (left, right, marker = "") => this.theme.fg("borderAccent", `${left}${marker}${"─".repeat(Math.max(0, width - visibleWidth(marker)))}${right}`);
|
|
491
527
|
return [
|
|
492
528
|
border("╭", "╮", start > 0 ? "↑" : ""),
|
|
493
529
|
...visible.map((option, offset) => {
|
|
494
530
|
const index = start + offset;
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
531
|
+
const marker = index === focusedIndex
|
|
532
|
+
? this.theme.fg("accent", " ▶ ")
|
|
533
|
+
: " ";
|
|
534
|
+
const row = this.fit(`${marker}${option.content}`, width);
|
|
535
|
+
const colored = index === focusedIndex && !option.preserveColors
|
|
536
|
+
? this.theme.fg("accent", row)
|
|
537
|
+
: row;
|
|
538
|
+
const styled = index === focusedIndex ? this.theme.bg("selectedBg", colored) : colored;
|
|
498
539
|
return `${this.theme.fg("borderAccent", "│")}${styled}${this.theme.fg("borderAccent", "│")}`;
|
|
499
540
|
}),
|
|
500
541
|
border("╰", "╯", start + visible.length < options.length ? "↓" : ""),
|
|
@@ -523,6 +564,12 @@ export class ActorInspectorOverlay {
|
|
|
523
564
|
this.contentStripeIndices = items
|
|
524
565
|
.slice(start, start + viewportRows)
|
|
525
566
|
.map((_item, offset) => start + offset);
|
|
567
|
+
const selectedViewportRow = banner.length + this.rowIndex - start;
|
|
568
|
+
if (this.focus === "list" &&
|
|
569
|
+
selectedViewportRow >= banner.length &&
|
|
570
|
+
selectedViewportRow < viewportRows) {
|
|
571
|
+
this.contentSelectedRows.add(selectedViewportRow);
|
|
572
|
+
}
|
|
526
573
|
return [...banner, ...items.slice(start, start + viewportRows - banner.length).map((item, offset) => {
|
|
527
574
|
const index = start + offset;
|
|
528
575
|
const detail = item.detail && typeof item.detail === "object"
|
|
@@ -536,7 +583,7 @@ export class ActorInspectorOverlay {
|
|
|
536
583
|
const prefix = this.focus === "list" && index === this.rowIndex
|
|
537
584
|
? this.theme.fg("accent", " ▶ ")
|
|
538
585
|
: " ";
|
|
539
|
-
const row = `${prefix}${this.theme.fg("text", `#${items.length - index}`)} ${marker} ${this.theme.fg("muted", item.source)}/${this.theme.fg(item.level === "error" ? "error" : "accent", item.kind)} ${this.theme.fg("text", item.summary)}`;
|
|
586
|
+
const row = `${prefix}${this.theme.fg("text", `#${items.length - index - 1}`)} ${marker} ${this.theme.fg("muted", item.source)}/${this.theme.fg(item.level === "error" ? "error" : "accent", item.kind)} ${this.theme.fg("text", item.summary)}`;
|
|
540
587
|
return this.focus === "list" && index === this.rowIndex
|
|
541
588
|
? this.theme.fg("accent", row)
|
|
542
589
|
: row;
|
|
@@ -676,11 +723,27 @@ export class ActorInspectorOverlay {
|
|
|
676
723
|
return [
|
|
677
724
|
`${indent}[`,
|
|
678
725
|
...value.flatMap((item, index) => {
|
|
679
|
-
const
|
|
726
|
+
const itemDepth = depth + 1;
|
|
727
|
+
const itemIndent = " ".repeat(itemDepth);
|
|
728
|
+
const marker = `#${index}`;
|
|
680
729
|
const itemInline = this.inlineDocumentValue(item);
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
730
|
+
let lines;
|
|
731
|
+
if (itemInline !== undefined) {
|
|
732
|
+
lines = [`${itemIndent}${marker}: ${itemInline}`];
|
|
733
|
+
}
|
|
734
|
+
else if (item && typeof item === "object") {
|
|
735
|
+
const nested = this.document(item, itemDepth);
|
|
736
|
+
lines = [
|
|
737
|
+
`${itemIndent}${marker}: ${nested[0].slice(itemIndent.length)}`,
|
|
738
|
+
...nested.slice(1),
|
|
739
|
+
];
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
lines = this.labeledScalarLines(marker, item, itemDepth);
|
|
743
|
+
}
|
|
744
|
+
if (index < value.length - 1)
|
|
745
|
+
lines[lines.length - 1] += ",";
|
|
746
|
+
return lines;
|
|
684
747
|
}),
|
|
685
748
|
`${indent}]`,
|
|
686
749
|
];
|
|
@@ -731,9 +794,13 @@ export class ActorInspectorOverlay {
|
|
|
731
794
|
styleDocumentLine(line) {
|
|
732
795
|
const indent = line.match(/^ */u)?.[0] ?? "";
|
|
733
796
|
const content = line.slice(indent.length);
|
|
734
|
-
if (
|
|
797
|
+
if (content.endsWith(":")) {
|
|
735
798
|
return `${indent}${this.theme.fg("accent", content)}`;
|
|
736
799
|
}
|
|
800
|
+
const indexed = /^(#\d+:)(.*)$/u.exec(content);
|
|
801
|
+
if (indexed) {
|
|
802
|
+
return `${indent}${this.theme.fg("accent", indexed[1])}${this.theme.fg("text", indexed[2])}`;
|
|
803
|
+
}
|
|
737
804
|
const labeled = /^([^:]+:)(.*)$/u.exec(content);
|
|
738
805
|
if (labeled) {
|
|
739
806
|
return `${indent}${this.theme.fg("muted", labeled[1])}${this.theme.fg("text", labeled[2])}`;
|
|
@@ -799,12 +866,27 @@ export class ActorInspectorOverlay {
|
|
|
799
866
|
const fill = "─".repeat(Math.max(0, width - visibleWidth(prefix) - visibleWidth(suffix) - visibleWidth(content)));
|
|
800
867
|
return `${this.theme.fg("borderAccent", `╰${prefix}`)}${content}${this.theme.fg("borderAccent", `${suffix}${fill}╯`)}`;
|
|
801
868
|
}
|
|
869
|
+
compositeMenuLine(baseLine, menuLine, innerWidth, horizontalOffset) {
|
|
870
|
+
const offset = Math.max(0, Math.min(horizontalOffset, innerWidth));
|
|
871
|
+
const menuWidth = Math.min(innerWidth - offset, visibleWidth(menuLine));
|
|
872
|
+
const baseInner = sliceByColumn(baseLine, 1, innerWidth, true);
|
|
873
|
+
const prefix = sliceByColumn(baseInner, 0, offset, true);
|
|
874
|
+
const suffixStart = offset + menuWidth;
|
|
875
|
+
const suffix = sliceByColumn(baseInner, suffixStart, Math.max(0, innerWidth - suffixStart), true);
|
|
876
|
+
const remainder = this.fit(suffix, innerWidth - suffixStart);
|
|
877
|
+
return `${this.theme.fg("borderAccent", "│")}${this.fit(prefix, offset)}${truncateToWidth(menuLine, menuWidth, "")}${remainder}${this.theme.fg("borderAccent", "│")}`;
|
|
878
|
+
}
|
|
802
879
|
stripeBackground(content, index) {
|
|
803
880
|
return index % 2 === 0 ? content : this.theme.bg("customMessageBg", content);
|
|
804
881
|
}
|
|
805
|
-
stripedRow(content, width, index) {
|
|
806
|
-
|
|
807
|
-
|
|
882
|
+
stripedRow(content, width, index, selected) {
|
|
883
|
+
if (!selected) {
|
|
884
|
+
const fitted = this.fit(content, width);
|
|
885
|
+
return `${this.theme.fg("borderAccent", "│")}${this.stripeBackground(fitted, index)}${this.theme.fg("borderAccent", "│")}`;
|
|
886
|
+
}
|
|
887
|
+
const selectedContent = truncateToWidth(`${content} `, width, "");
|
|
888
|
+
const remainder = " ".repeat(Math.max(0, width - visibleWidth(selectedContent)));
|
|
889
|
+
return `${this.theme.fg("borderAccent", "│")}${this.theme.bg("selectedBg", selectedContent)}${this.stripeBackground(remainder, index)}${this.theme.fg("borderAccent", "│")}`;
|
|
808
890
|
}
|
|
809
891
|
row(content, width) {
|
|
810
892
|
return `${this.theme.fg("borderAccent", "│")}${this.fit(content, width)}${this.theme.fg("borderAccent", "│")}`;
|
package/dist/lib/limits.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare const CONTROL_INPUT_MAX_BYTES = 380;
|
|
|
11
11
|
export declare const CONTROL_WIRE_MAX_BYTES = 512;
|
|
12
12
|
export declare const INSPECTOR_BODY_PREVIEW_CHARS = 320;
|
|
13
13
|
export declare const DOCTOR_ACTION_PREVIEW_CHARS = 72;
|
|
14
|
+
export declare const SESSION_EVIDENCE_MAX_BYTES: number;
|
|
14
15
|
export declare const SESSION_EVIDENCE_MAX_TURNS = 100;
|
|
15
16
|
export declare const SESSION_EVIDENCE_TEXT_CHARS = 4000;
|
|
16
17
|
export declare const SESSION_EVIDENCE_MAX_TOOL_CALLS = 100;
|
package/dist/lib/limits.js
CHANGED
|
@@ -11,6 +11,7 @@ export const CONTROL_INPUT_MAX_BYTES = 380;
|
|
|
11
11
|
export const CONTROL_WIRE_MAX_BYTES = 512;
|
|
12
12
|
export const INSPECTOR_BODY_PREVIEW_CHARS = 320;
|
|
13
13
|
export const DOCTOR_ACTION_PREVIEW_CHARS = 72;
|
|
14
|
+
export const SESSION_EVIDENCE_MAX_BYTES = 4 * 1024 * 1024;
|
|
14
15
|
export const SESSION_EVIDENCE_MAX_TURNS = 100;
|
|
15
16
|
export const SESSION_EVIDENCE_TEXT_CHARS = 4_000;
|
|
16
17
|
export const SESSION_EVIDENCE_MAX_TOOL_CALLS = 100;
|
|
@@ -75,9 +75,9 @@ export function reconcileRunTerminalNotifications(input) {
|
|
|
75
75
|
includeAttention: input.includeAttention,
|
|
76
76
|
stateRoot: input.stateRoot,
|
|
77
77
|
});
|
|
78
|
+
deliverRunTransitionNotifications(snapshot.transitions, input.sink, input.inFlight);
|
|
78
79
|
if (input.includeAttention)
|
|
79
80
|
deliverRunAttentionNotifications(snapshot.attentionEvents, input.sink);
|
|
80
|
-
deliverRunTransitionNotifications(snapshot.transitions, input.sink, input.inFlight);
|
|
81
81
|
pruneRunUiObservationState(input.state, snapshot);
|
|
82
82
|
return snapshot;
|
|
83
83
|
}
|
|
@@ -838,6 +838,8 @@ export function getRunAttentionNotificationType(event) {
|
|
|
838
838
|
return event.level;
|
|
839
839
|
}
|
|
840
840
|
export function shouldNotifyRunAttentionEvent(event) {
|
|
841
|
+
if (event.kind === "command.done")
|
|
842
|
+
return false;
|
|
841
843
|
return event.attention === "notify" || event.attention === "followup";
|
|
842
844
|
}
|
|
843
845
|
export function shouldSendRunAttentionFollowUp(event) {
|
|
@@ -3,8 +3,28 @@
|
|
|
3
3
|
* Owns: artifact path template expansion and filesystem-backed artifact metadata.
|
|
4
4
|
*/
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
|
-
import {
|
|
6
|
+
import { closeSync, fstatSync, openSync, readSync, } from "node:fs";
|
|
7
7
|
import { substituteCommandTemplateToken } from "./command-templates.js";
|
|
8
|
+
function hashArtifactFile(path) {
|
|
9
|
+
const fd = openSync(path, "r");
|
|
10
|
+
try {
|
|
11
|
+
const size = fstatSync(fd).size;
|
|
12
|
+
const hash = createHash("sha256");
|
|
13
|
+
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
14
|
+
let position = 0;
|
|
15
|
+
while (position < size) {
|
|
16
|
+
const bytesRead = readSync(fd, chunk, 0, Math.min(chunk.byteLength, size - position), position);
|
|
17
|
+
if (bytesRead === 0)
|
|
18
|
+
break;
|
|
19
|
+
hash.update(chunk.subarray(0, bytesRead));
|
|
20
|
+
position += bytesRead;
|
|
21
|
+
}
|
|
22
|
+
return { sha256: hash.digest("hex"), size: position };
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
closeSync(fd);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
8
28
|
export function resolveArtifactPaths(artifacts, values) {
|
|
9
29
|
if (!artifacts)
|
|
10
30
|
return undefined;
|
|
@@ -35,7 +55,7 @@ export function resolveArtifactManifest(artifacts) {
|
|
|
35
55
|
if (!declaration?.path)
|
|
36
56
|
continue;
|
|
37
57
|
try {
|
|
38
|
-
const
|
|
58
|
+
const hashed = hashArtifactFile(declaration.path);
|
|
39
59
|
manifest[name] = {
|
|
40
60
|
exists: true,
|
|
41
61
|
...(declaration.kind ? { kind: declaration.kind } : {}),
|
|
@@ -46,8 +66,8 @@ export function resolveArtifactManifest(artifacts) {
|
|
|
46
66
|
...(declaration.required !== undefined
|
|
47
67
|
? { required: declaration.required }
|
|
48
68
|
: {}),
|
|
49
|
-
sha256:
|
|
50
|
-
size:
|
|
69
|
+
sha256: hashed.sha256,
|
|
70
|
+
size: hashed.size,
|
|
51
71
|
};
|
|
52
72
|
}
|
|
53
73
|
catch {
|
|
@@ -105,10 +105,11 @@ function toolCalls(message, maxTextChars, maxToolCalls) {
|
|
|
105
105
|
}));
|
|
106
106
|
}
|
|
107
107
|
export function readSessionEvidence(path, options = {}) {
|
|
108
|
+
const maxBytes = Math.max(1, options.maxBytes ?? Limits.SESSION_EVIDENCE_MAX_BYTES);
|
|
108
109
|
const maxTextChars = Math.max(1, options.maxTextChars ?? Limits.SESSION_EVIDENCE_TEXT_CHARS);
|
|
109
110
|
const maxToolCalls = Math.max(1, options.maxToolCalls ?? Limits.SESSION_EVIDENCE_MAX_TOOL_CALLS);
|
|
110
111
|
const maxTurns = Math.max(1, options.maxTurns ?? Limits.SESSION_EVIDENCE_MAX_TURNS);
|
|
111
|
-
const read = readJsonlFileResilient(path);
|
|
112
|
+
const read = readJsonlFileResilient(path, { maxBytes });
|
|
112
113
|
const diagnostics = [...read.diagnostics];
|
|
113
114
|
const header = read.records.find((entry) => entry.type === "session");
|
|
114
115
|
const branch = activeBranch(read.records, path, diagnostics);
|
|
@@ -198,7 +199,7 @@ export function readSessionEvidence(path, options = {}) {
|
|
|
198
199
|
path,
|
|
199
200
|
...(header ? { session: asRecord(header) } : {}),
|
|
200
201
|
totalTurns: turns.length,
|
|
201
|
-
truncated: turns.length > visibleTurns.length,
|
|
202
|
+
truncated: read.truncated === true || turns.length > visibleTurns.length,
|
|
202
203
|
turns: visibleTurns,
|
|
203
204
|
};
|
|
204
205
|
}
|
|
@@ -15,7 +15,11 @@ export interface JsonReadResult<T> {
|
|
|
15
15
|
export interface JsonlReadResult<T> {
|
|
16
16
|
diagnostics: StateReadDiagnostic[];
|
|
17
17
|
records: T[];
|
|
18
|
+
truncated?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface JsonlReadOptions {
|
|
21
|
+
maxBytes?: number;
|
|
18
22
|
}
|
|
19
23
|
export declare function readJsonFileResilient<T>(path: string, fallback: T): JsonReadResult<T>;
|
|
20
|
-
export declare function readJsonlFileResilient<T>(path: string): JsonlReadResult<T>;
|
|
24
|
+
export declare function readJsonlFileResilient<T>(path: string, options?: JsonlReadOptions): JsonlReadResult<T>;
|
|
21
25
|
export declare function formatStateReadDiagnostics(diagnostics: StateReadDiagnostic[], limit?: number): string[];
|