@earendil-works/pi-durable 0.99.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +196 -74
- package/dist/env/index.d.ts +5 -0
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js.map +1 -1
- package/dist/env/node.d.ts +2 -0
- package/dist/env/node.d.ts.map +1 -1
- package/dist/env/node.js +2 -0
- package/dist/env/node.js.map +1 -1
- package/dist/harness/agent.d.ts +31 -0
- package/dist/harness/agent.d.ts.map +1 -0
- package/dist/harness/agent.js +209 -0
- package/dist/harness/agent.js.map +1 -0
- package/dist/harness/compaction.d.ts.map +1 -1
- package/dist/harness/compaction.js +8 -11
- package/dist/harness/compaction.js.map +1 -1
- package/dist/harness/define.d.ts +18 -0
- package/dist/harness/define.d.ts.map +1 -0
- package/dist/harness/define.js +25 -0
- package/dist/harness/define.js.map +1 -0
- package/dist/harness/events.d.ts +5 -5
- package/dist/harness/events.d.ts.map +1 -1
- package/dist/harness/events.js +6 -6
- package/dist/harness/events.js.map +1 -1
- package/dist/harness/generation.d.ts +2 -4
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +39 -43
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +68 -154
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/inbox.d.ts +4 -2
- package/dist/harness/inbox.d.ts.map +1 -1
- package/dist/harness/inbox.js +3 -5
- package/dist/harness/inbox.js.map +1 -1
- package/dist/harness/prompt.d.ts +1 -3
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +1 -11
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/registry.d.ts +2 -3
- package/dist/harness/registry.d.ts.map +1 -1
- package/dist/harness/registry.js +66 -283
- package/dist/harness/registry.js.map +1 -1
- package/dist/harness/scheduler.d.ts +7 -2
- package/dist/harness/scheduler.d.ts.map +1 -1
- package/dist/harness/scheduler.js +41 -27
- package/dist/harness/scheduler.js.map +1 -1
- package/dist/harness/submissions.d.ts +4 -4
- package/dist/harness/submissions.d.ts.map +1 -1
- package/dist/harness/submissions.js +7 -4
- package/dist/harness/submissions.js.map +1 -1
- package/dist/harness/task-graph.d.ts +49 -0
- package/dist/harness/task-graph.d.ts.map +1 -0
- package/dist/harness/task-graph.js +163 -0
- package/dist/harness/task-graph.js.map +1 -0
- package/dist/harness/tool.d.ts +1 -1
- package/dist/harness/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +9 -6
- package/dist/harness/tool.js.map +1 -1
- package/dist/harness/types.d.ts +171 -140
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/view.d.ts +1 -1
- package/dist/harness/view.d.ts.map +1 -1
- package/dist/harness/view.js +2 -7
- package/dist/harness/view.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/session/session.d.ts.map +1 -1
- package/dist/session/session.js +5 -1
- package/dist/session/session.js.map +1 -1
- package/dist/session/transaction.d.ts +2 -2
- package/dist/session/transaction.d.ts.map +1 -1
- package/dist/session/transaction.js +7 -4
- package/dist/session/transaction.js.map +1 -1
- package/dist/storage/sqlite/database.d.ts +26 -19
- package/dist/storage/sqlite/database.d.ts.map +1 -1
- package/dist/storage/sqlite/database.js.map +1 -1
- package/dist/storage/sqlite/index.d.ts +1 -1
- package/dist/storage/sqlite/index.d.ts.map +1 -1
- package/dist/storage/sqlite/index.js.map +1 -1
- package/dist/storage/sqlite/migrations.js +6 -6
- package/dist/storage/sqlite/migrations.js.map +1 -1
- package/dist/storage/sqlite/node.d.ts +23 -7
- package/dist/storage/sqlite/node.d.ts.map +1 -1
- package/dist/storage/sqlite/node.js +129 -47
- package/dist/storage/sqlite/node.js.map +1 -1
- package/dist/storage/sqlite/storage.d.ts +12 -0
- package/dist/storage/sqlite/storage.d.ts.map +1 -1
- package/dist/storage/sqlite/storage.js +121 -129
- package/dist/storage/sqlite/storage.js.map +1 -1
- package/dist/tools/bash.d.ts +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +3 -2
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +3 -3
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +5 -4
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/file-mutation-queue.d.ts +5 -1
- package/dist/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/tools/file-mutation-queue.js +39 -33
- package/dist/tools/file-mutation-queue.js.map +1 -1
- package/dist/tools/index.d.ts +18 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read.d.ts +3 -3
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +4 -3
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.d.ts +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +3 -2
- package/dist/tools/write.js.map +1 -1
- package/dist/types.d.ts +15 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +25 -15
- package/dist/harness/config.d.ts +0 -29
- package/dist/harness/config.d.ts.map +0 -1
- package/dist/harness/config.js +0 -24
- package/dist/harness/config.js.map +0 -1
- package/docs/chord-delta-findings.md +0 -358
- package/docs/pico-v5-chord-usage.md +0 -373
- package/docs/pico-v5-handoff.md +0 -861
- package/docs/pico-v5.md +0 -4174
package/CHANGELOG.md
ADDED
package/README.md
CHANGED
|
@@ -12,9 +12,13 @@ Built on [`@earendil-works/pi-ai`](../ai/README.md) for model access and `@earen
|
|
|
12
12
|
- [Quick Start](#quick-start)
|
|
13
13
|
- [Concepts](#concepts)
|
|
14
14
|
- [Persist and Resume](#persist-and-resume)
|
|
15
|
+
- [Extensions](#extensions)
|
|
15
16
|
- [Tools](#tools)
|
|
16
17
|
- [System Prompt](#system-prompt)
|
|
17
|
-
- [Conversation
|
|
18
|
+
- [Per-Conversation Agent](#per-conversation-agent)
|
|
19
|
+
- [Settings](#settings)
|
|
20
|
+
- [Environment](#environment)
|
|
21
|
+
- [Reload](#reload)
|
|
18
22
|
- [Watching a Conversation](#watching-a-conversation)
|
|
19
23
|
- [Busy Conversations](#busy-conversations)
|
|
20
24
|
- [Reset and Handoff](#reset-and-handoff)
|
|
@@ -24,6 +28,7 @@ Built on [`@earendil-works/pi-ai`](../ai/README.md) for model access and `@earen
|
|
|
24
28
|
- [More Conversations and Forks](#more-conversations-and-forks)
|
|
25
29
|
- [Abort and Subagents](#abort-and-subagents)
|
|
26
30
|
- [Child Tasks](#child-tasks)
|
|
31
|
+
- [Task Graph](#task-graph)
|
|
27
32
|
- [Your Own State](#your-own-state)
|
|
28
33
|
- [Usage and Cost](#usage-and-cost)
|
|
29
34
|
- [Storage](#storage)
|
|
@@ -50,8 +55,7 @@ const models = createModels();
|
|
|
50
55
|
models.setProvider(openaiProvider()); // reads OPENAI_API_KEY
|
|
51
56
|
|
|
52
57
|
const harness = await Harness.open(new MemoryStorage(), { models, registry: createRegistry() }, context);
|
|
53
|
-
const root = await harness.root(context);
|
|
54
|
-
await root.setModel({ provider: "openai", modelId: "gpt-6-sol" }, context);
|
|
58
|
+
const root = await harness.root(context, { agent: { model: { provider: "openai", modelId: "gpt-6-sol" } } });
|
|
55
59
|
|
|
56
60
|
const submission = await root.submit({ type: "input", content: "What is the capital of France?" }, context);
|
|
57
61
|
const settled = await submission.wait(context);
|
|
@@ -65,7 +69,7 @@ await harness.close(context);
|
|
|
65
69
|
What happened:
|
|
66
70
|
|
|
67
71
|
- `Harness.open()` opens a Session over a storage backend. `MemoryStorage` keeps everything in memory.
|
|
68
|
-
- `root()` returns the root conversation, creating it on first use. A conversation is a transcript of immutable entries.
|
|
72
|
+
- `root()` returns the root conversation, creating it on first use with the given agent choices. A conversation is a transcript of immutable entries.
|
|
69
73
|
- `submit()` durably admits your input and returns a `Submission`. A built-in generation task calls the model and appends the answer.
|
|
70
74
|
- `wait()` resolves once the input is answered (`done`) or has failed (`unanswered`, with a reason).
|
|
71
75
|
|
|
@@ -77,11 +81,13 @@ Every async call takes a Chord `Context`, which carries cancellation. `BACKGROUN
|
|
|
77
81
|
- **Conversation**: a transcript. `root()` creates the root conversation on first use; you can create more and fork them. A `Conversation` handle holds no state; compare handles by `id`.
|
|
78
82
|
- **Entry**: one immutable transcript record, such as a user message (`pi.user`), a model response (`pi.assistant`), a tool result (`pi.tool-result`), a system prompt change (`pi.system`), a reset (`pi.reset`), or your own kind. The model sees the entries from the newest reset onward.
|
|
79
83
|
- **Commit**: an atomic write. `conversation.commit((tx) => ...)` can append entries, edit documents, and create tasks together; either all of it is stored or none of it.
|
|
80
|
-
- **Document**: typed JSON state stored next to the transcript and changed in commits. Built-in ones hold each conversation's
|
|
84
|
+
- **Document**: typed JSON state stored next to the transcript and changed in commits. Built-in ones hold each conversation's agent choices (`pi.agent`), the running generation and tools (`pi.live`), queued submissions (`pi.inbox`), and spend (`pi.usage`).
|
|
81
85
|
- **Task**: a durable state machine that saves a checkpoint at every step, so a restarted process continues from the last one. Every task has an owner: its conversation, or another task. The Harness runs answers as built-in tasks: `pi.generation` calls the model and owns the `pi.tool` tasks of its tool calls, waits for them, and hands the run to the next generation.
|
|
82
86
|
- **Submission**: something you hand to a conversation, either user input or an entry to write, which you can wait for.
|
|
83
87
|
- **Turn and run**: a turn is one model response and its tool calls; a run is the turns from an input to its final answer. A conversation is busy while a run is going.
|
|
84
|
-
- **
|
|
88
|
+
- **Extension**: a named bundle of tools, system prompt sections, hooks, wrappers, and tasks.
|
|
89
|
+
- **Registry**: the extensions this process installed. It can change while the Harness runs; new work uses the new state.
|
|
90
|
+
- **Agent**: what a conversation runs with: model, thinking level, selected extensions, tools, instructions, and working directory. Stored per conversation as names in `pi.agent`, resolved against the registry at each use.
|
|
85
91
|
|
|
86
92
|
One answered input, as entries and tasks:
|
|
87
93
|
|
|
@@ -115,65 +121,140 @@ const again = await root.submit({ type: "input", content: "Hello", requestId: "g
|
|
|
115
121
|
|
|
116
122
|
`harness.submission(id)` reacquires a submission by ID, for example to wait for it after a restart.
|
|
117
123
|
|
|
118
|
-
##
|
|
124
|
+
## Extensions
|
|
119
125
|
|
|
120
|
-
|
|
126
|
+
Code the Harness runs, other than its built-in tasks, comes in named extensions installed in a registry your process owns:
|
|
121
127
|
|
|
122
128
|
```typescript
|
|
123
|
-
import {
|
|
124
|
-
import {
|
|
129
|
+
import { createRegistry, defineExtension, defineTool, hook, section, ToolTask } from "@earendil-works/pi-durable";
|
|
130
|
+
import { CodingTools } from "@earendil-works/pi-durable/tools";
|
|
131
|
+
|
|
132
|
+
const Coding = defineExtension({
|
|
133
|
+
name: "coding",
|
|
134
|
+
sections: [section("preamble", () => "You are a concise coding assistant.", { tag: false })],
|
|
135
|
+
hooks: [hook(ToolTask, { beforeTool: (call) => (isDangerous(call) ? { block: "Needs approval" } : undefined) })],
|
|
136
|
+
});
|
|
125
137
|
|
|
126
138
|
const registry = createRegistry();
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const harness = await Harness.open(storage, { models, registry, env }, context);
|
|
139
|
+
registry.install(CodingTools);
|
|
140
|
+
registry.install(Coding);
|
|
130
141
|
```
|
|
131
142
|
|
|
132
|
-
|
|
143
|
+
An extension may bring `tools`, `sections`, `hooks`, `wraps` (decorators of a tool or section by name), and `tasks`. By default every conversation selects every installed extension, in install order. Nothing in the registry is stored; conversations store extension names.
|
|
144
|
+
|
|
145
|
+
## Tools
|
|
146
|
+
|
|
147
|
+
`@earendil-works/pi-durable/tools` provides `read`, `write`, `edit`, and `bash`, and the `CodingTools` extension with all four. They touch files and processes only through the call's environment (see [Environment](#environment)). Reading images is not supported yet.
|
|
133
148
|
|
|
134
|
-
Define your own tool with a TypeBox schema. `api.output()` streams running output, which becomes the result when `execute()` returns no `content`:
|
|
149
|
+
Define your own tool with a TypeBox schema. `defineTool()` types `args` from `parameters`, which the Harness validates before `execute()`. `api.output()` streams running output, which becomes the result when `execute()` returns no `content`:
|
|
135
150
|
|
|
136
151
|
```typescript
|
|
137
152
|
import { Type } from "@earendil-works/pi-ai";
|
|
138
153
|
|
|
139
|
-
|
|
154
|
+
const count = defineTool({
|
|
140
155
|
name: "count",
|
|
141
156
|
description: "Count from 1 to n",
|
|
142
157
|
parameters: Type.Object({ n: Type.Number() }),
|
|
143
158
|
execute: async (args, api) => {
|
|
144
|
-
for (let i = 1; i <=
|
|
159
|
+
for (let i = 1; i <= args.n; i++) api.output(`${i}\n`);
|
|
145
160
|
return {};
|
|
146
161
|
},
|
|
147
162
|
});
|
|
163
|
+
registry.install(defineExtension({ name: "count", tools: [count] }));
|
|
148
164
|
```
|
|
149
165
|
|
|
150
166
|
Each call runs as its own durable task. Its intent is committed before `execute()` runs. If the process dies mid-call, the tool reruns on reopen only when it is declared `replay: "safe"`; otherwise the model gets an `interrupted` error result with the output committed so far. Throwing from `execute()` gives the model an error result. A result can also return `usage`, which is added to the conversation's [usage](#usage-and-cost). It can also return `control: { terminate: true }`: when every result of the round asks for it, the run ends without another model request.
|
|
151
167
|
|
|
168
|
+
A later extension's tool with the same name replaces an earlier one where both are selected, and `wrapTool()` decorates whichever tool won:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const Venv = defineExtension({ name: "venv", tools: [createBashTool({ commandPrefix: "source .venv/bin/activate" })] });
|
|
172
|
+
const Timing = defineExtension({
|
|
173
|
+
name: "timing",
|
|
174
|
+
wraps: [wrapTool(createBashTool(), (bash) => ({ ...bash, execute: (args, api, ctx) => timed(() => bash.execute(args, api, ctx)) }))],
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
152
178
|
## System Prompt
|
|
153
179
|
|
|
154
|
-
The system prompt is built from
|
|
180
|
+
The system prompt is built from the selected extensions' sections, rendered in order before each request. A section sees the resolved agent, the environment built for the request, and committed documents:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
section("cwd", (input) => input.env?.cwd); // rendered as <cwd>\n...\n</cwd>; undefined omits it
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
A conversation's `instructions` render last, as the section `instructions`. Sections and tool changes are stored as positional system entries in the transcript. Only what changed is sent again, which keeps provider prompt caches warm. A section that returns something different every time, such as the current time, defeats that.
|
|
187
|
+
|
|
188
|
+
## Per-Conversation Agent
|
|
189
|
+
|
|
190
|
+
Each conversation stores what it runs with in its `pi.agent` document. `configure()` changes it in one commit; unset fields follow the host:
|
|
155
191
|
|
|
156
192
|
```typescript
|
|
157
|
-
|
|
158
|
-
|
|
193
|
+
await root.configure(
|
|
194
|
+
{
|
|
195
|
+
model: { provider: "openai", modelId: "gpt-6-sol" },
|
|
196
|
+
thinkingLevel: "high",
|
|
197
|
+
extensions: { remove: [Coding] }, // edits the host default; an array selects exactly these, in order
|
|
198
|
+
tools: [readTool, bashTool], // an array offers exactly these; { remove: [...] } drops some
|
|
199
|
+
instructions: "Only read; never edit files.",
|
|
200
|
+
cwd: "/work/repo",
|
|
201
|
+
},
|
|
202
|
+
context,
|
|
203
|
+
);
|
|
204
|
+
await root.configure({ tools: null }, context); // null clears a field back to the host default
|
|
205
|
+
const agent = await root.agent(context); // resolved: model, extensions, tools, sections, cwd
|
|
159
206
|
```
|
|
160
207
|
|
|
161
|
-
|
|
208
|
+
Extensions and tools are passed as objects and stored by name, so a stored name outlives its code: after an extension is uninstalled, conversations that select it just stop getting it until it is installed again. `createConversation()`, `fork()`, and `root()` take the same change as `agent`. A task-owned conversation, such as a subagent's, starts as a copy of its owner's conversation's agent. A fork starts with the agent its parent had at the fork entry. The model, prompt, and offered tools of a request are fixed when it is prepared; a change applies from the next request. Tool calls and hooks use the agent as their task phase resolves it, and the environment is built from the current `cwd` at each use, so a `cwd` or extension change can reach calls the model already made.
|
|
162
209
|
|
|
163
|
-
##
|
|
210
|
+
## Settings
|
|
164
211
|
|
|
165
|
-
|
|
212
|
+
Run policy shared by every conversation is passed as `settings`. It is read at every use and never stored, so getters make it live, for example backed by a settings file:
|
|
166
213
|
|
|
167
214
|
```typescript
|
|
168
|
-
await
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
215
|
+
const harness = await Harness.open(storage, {
|
|
216
|
+
models,
|
|
217
|
+
registry,
|
|
218
|
+
settings: {
|
|
219
|
+
extensions: [CodingTools, Coding], // default selection; absent: every installed extension
|
|
220
|
+
stream: { timeoutMs: 120_000 },
|
|
221
|
+
retry: { maxRetries: 3 },
|
|
222
|
+
compaction: { reserveTokens: 16384 },
|
|
223
|
+
toolExecution: "parallel",
|
|
224
|
+
get followUpMode() {
|
|
225
|
+
return userSettings.followUpMode;
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
}, context);
|
|
174
229
|
```
|
|
175
230
|
|
|
176
|
-
|
|
231
|
+
## Environment
|
|
232
|
+
|
|
233
|
+
`env` builds the execution environment for each tool call, section rendering, and `runtime.env()`. It receives the conversation's ID, its agent `cwd`, and committed reads, so one function serves a directory per conversation or a container per conversation:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { NodeExecutionEnv } from "@earendil-works/pi-durable/env/node";
|
|
237
|
+
|
|
238
|
+
const harness = await Harness.open(storage, {
|
|
239
|
+
models,
|
|
240
|
+
registry,
|
|
241
|
+
env: ({ cwd }) => new NodeExecutionEnv({ cwd: cwd ?? process.cwd() }),
|
|
242
|
+
}, context);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
A throw from `env` becomes the call's error result. Without an environment, the built-in tools fail with an error result. A fresh environment object per call is fine: `edit` and `write` serialize changes to one file by the environment's `id` and path. A custom `ExecutionEnv` sets `id` so that equal ids see the same files at the same paths, for example one id per container.
|
|
246
|
+
|
|
247
|
+
## Reload
|
|
248
|
+
|
|
249
|
+
Installing an extension with an installed name replaces it in place, in one step:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
registry.install(await loadCodingExtension()); // same name "coding": replaces the installed one
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`registry.uninstall(extension)` removes the installed extension with that name, whichever object it is.
|
|
256
|
+
|
|
257
|
+
Work that already started keeps the code it took: a running tool call finishes under its old implementation, and each task phase resolves hooks and the agent once, from the registry at the phase's start. The next phase, request, or call uses the new code. After a restart, install the same extensions again; pending tasks of an extension's `tasks` resume once it is installed.
|
|
177
258
|
|
|
178
259
|
## Watching a Conversation
|
|
179
260
|
|
|
@@ -184,7 +265,7 @@ const view = await root.viewState(context);
|
|
|
184
265
|
view.subscribe((value) => {
|
|
185
266
|
// value.entries: the active transcript
|
|
186
267
|
// value.docs["pi.live"]: the running generation (streamed partial, retry, deferred) and tool calls (output, details)
|
|
187
|
-
// value.docs["pi.inbox"], value.docs["pi.usage"], value.docs["pi.
|
|
268
|
+
// value.docs["pi.inbox"], value.docs["pi.usage"], value.docs["pi.agent"]
|
|
188
269
|
render(value);
|
|
189
270
|
});
|
|
190
271
|
// later: view.dispose();
|
|
@@ -220,7 +301,7 @@ await root.submit({ type: "write", entry: { kind: "app.note", data: "user opened
|
|
|
220
301
|
- **Follow-ups** are placed when the run answers, and start the next run.
|
|
221
302
|
- **Writes** append an entry without asking the model anything.
|
|
222
303
|
- `await submission.abort(context)` withdraws a queued submission.
|
|
223
|
-
- `
|
|
304
|
+
- The [settings](#settings) `steeringMode: "all"` and `followUpMode: "all"` place every queued item at once instead of one per turn.
|
|
224
305
|
|
|
225
306
|
If a run fails, queued items stay in the inbox until the next submission places them, oldest first.
|
|
226
307
|
|
|
@@ -250,15 +331,17 @@ if (outcome.status === "completed" && outcome.result.submissionId !== undefined)
|
|
|
250
331
|
|
|
251
332
|
The conversation keeps working while the summary is made. The summary is placed at once when the conversation is idle, otherwise at the next turn boundary. Esc (`abort()`) cancels a manual compaction.
|
|
252
333
|
|
|
253
|
-
Generation also compacts on its own, controlled
|
|
334
|
+
Generation also compacts on its own, controlled by the [settings](#settings):
|
|
254
335
|
|
|
255
336
|
```typescript
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
337
|
+
settings: {
|
|
338
|
+
compaction: {
|
|
339
|
+
enabled: true, // automatic compaction; manual compact() always works
|
|
340
|
+
reserveTokens: 16384, // above contextWindow - reserveTokens, the next request waits for a compaction
|
|
341
|
+
keepRecentTokens: 20000, // roughly how much recent context stays verbatim
|
|
342
|
+
backgroundTokens: 32768, // this far below that, a compaction starts in the background; 0 disables it
|
|
343
|
+
},
|
|
344
|
+
}
|
|
262
345
|
```
|
|
263
346
|
|
|
264
347
|
When a provider rejects a request because the context is too long, generation compacts and retries once. A summary that would cut before the start of the current context settles as `stale` when it is placed, so when several are in flight, the furthest cut stays in effect. Summarization spend counts in `pi.usage`. A `beforeCompact` hook on `CompactionTask` can decline or supply its own summary.
|
|
@@ -273,7 +356,7 @@ For consumers that want coding-agent style events (`message_start`, `message_upd
|
|
|
273
356
|
import { watchEvents } from "@earendil-works/pi-durable";
|
|
274
357
|
|
|
275
358
|
const stream = await watchEvents(harness, root.id, context);
|
|
276
|
-
initialize(stream.snapshot); // entries, run, in-flight generation, tools, compactions, inbox,
|
|
359
|
+
initialize(stream.snapshot); // entries, run, in-flight generation, tools, compactions, inbox, agent, usage
|
|
277
360
|
stream.start(async (events) => {
|
|
278
361
|
for (const event of events) console.log(JSON.stringify(event));
|
|
279
362
|
});
|
|
@@ -283,23 +366,24 @@ Events are derived from commits, one batch per commit, and apply on top of the s
|
|
|
283
366
|
|
|
284
367
|
## Hooks
|
|
285
368
|
|
|
286
|
-
Hooks let extensions observe or adjust the built-in tasks:
|
|
369
|
+
Hooks let extensions observe or adjust the built-in tasks, in the conversations that select them:
|
|
287
370
|
|
|
288
371
|
```typescript
|
|
289
|
-
import { GenerationTask, ToolTask } from "@earendil-works/pi-durable";
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
372
|
+
import { GenerationTask, hook, ToolTask } from "@earendil-works/pi-durable";
|
|
373
|
+
|
|
374
|
+
const Guard = defineExtension({
|
|
375
|
+
name: "guard",
|
|
376
|
+
hooks: [
|
|
377
|
+
hook(ToolTask, { beforeTool: (call) => (call.name === "bash" ? { block: "bash is disabled here" } : undefined) }),
|
|
378
|
+
hook(GenerationTask, { onYield: (answer) => (needsMoreWork(answer) ? { continue: "Keep going." } : undefined) }),
|
|
379
|
+
],
|
|
296
380
|
});
|
|
297
381
|
```
|
|
298
382
|
|
|
299
383
|
- **Generation:** `beforeRequest` (replace the messages of one request), `afterResponse`, `onYield` (continue the run with another user message), and `afterTools` (runs once a round's tools are done).
|
|
300
384
|
- **Tools:** `beforeTool` (block or rewrite arguments) and `afterTool` (replace the result).
|
|
301
385
|
|
|
302
|
-
|
|
386
|
+
To limit a hook to some conversations, select its extension only there, for example with `configure({ extensions: { add: [Guard] } })`.
|
|
303
387
|
|
|
304
388
|
## More Conversations and Forks
|
|
305
389
|
|
|
@@ -308,7 +392,7 @@ const other = await harness.createConversation({ ownership: { kind: "ownerless"
|
|
|
308
392
|
const fork = await root.fork(entryId, { ownership: { kind: "ownerless" } }, context);
|
|
309
393
|
```
|
|
310
394
|
|
|
311
|
-
A fork sees its parent's entries up to `entryId` and continues independently. It keeps the parent's
|
|
395
|
+
A fork sees its parent's entries up to `entryId` and continues independently. It keeps the parent's agent as of that entry. Both take `agent` and `init`, applied in the creating commit.
|
|
312
396
|
|
|
313
397
|
## Abort and Subagents
|
|
314
398
|
|
|
@@ -317,25 +401,32 @@ A fork sees its parent's entries up to `entryId` and continues independently. It
|
|
|
317
401
|
A conversation can be **owned** by a task. A subagent tool creates its child inside `api.commit()` with `ownership: { kind: "task", taskId: api.taskId }`, then drives it through `api.conversation(id)`:
|
|
318
402
|
|
|
319
403
|
```typescript
|
|
320
|
-
|
|
404
|
+
const Subagent: Extension = defineExtension({
|
|
321
405
|
name: "subagent",
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
406
|
+
tools: [
|
|
407
|
+
defineTool({
|
|
408
|
+
name: "subagent",
|
|
409
|
+
description: "Delegate a self-contained task to a subagent and get its answer back.",
|
|
410
|
+
parameters: Type.Object({ task: Type.String() }),
|
|
411
|
+
replay: "safe", // a rerun after a crash finds the same child and submission
|
|
412
|
+
execute: async (args, api, context) => {
|
|
413
|
+
const child = await api.commit(async (tx) => {
|
|
414
|
+
// The ownership index remembers the child, so a rerun reuses it.
|
|
415
|
+
const existing = (await tx.scanConversations({ ownerTaskId: api.taskId }, 1)).items[0];
|
|
416
|
+
if (existing !== undefined) return existing.id;
|
|
417
|
+
// Starts as a copy of this conversation's agent: model, extensions, tools, cwd.
|
|
418
|
+
const created = await tx.createConversation({ ownership: { kind: "task", taskId: api.taskId } });
|
|
419
|
+
// A cheaper model, and no subagents of its own.
|
|
420
|
+
await configure(tx, created.id, { model: haiku, extensions: { remove: [Subagent] } });
|
|
421
|
+
return created.id;
|
|
422
|
+
}, context);
|
|
423
|
+
await api.details({ conversationId: child }, context); // lets a UI attach to the child
|
|
424
|
+
const request = { type: "input", content: args.task, requestId: `subagent:${api.taskId}` } as const;
|
|
425
|
+
const settled = await (await (await api.conversation(child, context))!.submit(request, context)).wait(context);
|
|
426
|
+
return { content: [{ type: "text", text: settled.status }] };
|
|
427
|
+
},
|
|
428
|
+
}),
|
|
429
|
+
],
|
|
339
430
|
});
|
|
340
431
|
```
|
|
341
432
|
|
|
@@ -377,6 +468,22 @@ decide: async (task, runtime, context) => {
|
|
|
377
468
|
|
|
378
469
|
[`24-child-tasks.ts`](test/examples/24-child-tasks.ts) runs a checkout with four payments: a declined card, a cancelled checkout, and a restart while the payments run.
|
|
379
470
|
|
|
471
|
+
## Task Graph
|
|
472
|
+
|
|
473
|
+
`harness.taskGraph(context)` shows every live task of the Session as one Chord state, for a task panel or debugging. Each node has its owner edge (`owner` task, or none for a task its conversation owns), its status, whether it is `background` or abort-marked, and the conversations it owns. `harness.watchTaskGraph(context)` delivers the same value as a watch, like a conversation's `watch()`.
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
const graph = await harness.taskGraph(context);
|
|
477
|
+
graph.subscribe((value) => {
|
|
478
|
+
for (const node of Object.values(value.tasks)) {
|
|
479
|
+
const status = node.state.status === "waiting" ? `waiting on ${node.state.on.join(", ")}` : node.state.status;
|
|
480
|
+
console.log(`${node.id} ${node.kind} ${status}`, node.owner ?? `conversation ${node.conversationId}`);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
A task appears with the commit that creates it and leaves with the commit that makes it terminal. Statuses are the committed ones: `pending`, `running`, `waiting` (with `on` and `policy`), and `completing` (with the held outcome's status). After a restart, tasks that were `running` show as `pending` until they run again. Whether a pending task is blocked by a missing definition is not part of the graph; `harness.inspect()` reports that. The graph lists live tasks only: once a subagent's owner task is terminal, a later task in its conversation is a top-level node, and the conversation's `ConversationRecord.owner` (also in its view's `conversation`) links it to its parent. [`24-child-tasks.ts`](test/examples/24-child-tasks.ts) prints the checkout's tree while its payments run.
|
|
486
|
+
|
|
380
487
|
## Your Own State
|
|
381
488
|
|
|
382
489
|
Documents are typed JSON objects committed together with entries. Define one, and edit it in a commit:
|
|
@@ -399,7 +506,7 @@ await root.commit(async (tx) => {
|
|
|
399
506
|
console.log(await harness.snapshot(Todos, root.id, context));
|
|
400
507
|
```
|
|
401
508
|
|
|
402
|
-
`harness.watchDoc()` and `harness.documentState()` observe one document like the view above. `
|
|
509
|
+
`harness.watchDoc()` and `harness.documentState()` observe one document like the view above. `HarnessOptions.conversationCreated(tx, conversation)` runs in every commit that creates or forks a conversation, including a tool's raw `tx.createConversation()`, so every conversation gets your documents; `init` in `createConversation()`, `fork()`, and `root()` writes per-call data in the same commit. An extension's tools, sections, and hooks read their own documents through `api` or `input.read`, and treat an absent one as its default ([`11-extension-state.ts`](test/examples/11-extension-state.ts)).
|
|
403
510
|
|
|
404
511
|
## Usage and Cost
|
|
405
512
|
|
|
@@ -417,7 +524,16 @@ const usage = await harness.usage(context); // { models: { "openai/gpt-6-sol": U
|
|
|
417
524
|
| SQLite | `openNodeSqliteStorage(file)` from `@earendil-works/pi-durable/storage/sqlite/node` | One database file. WAL mode with `synchronous = NORMAL`: commits survive process crashes; the newest may be lost on power or host failure. |
|
|
418
525
|
| JSONL | `openNodeJsonlStorage(directory, context)` from `@earendil-works/pi-durable/storage/jsonl/node` | Append-only files in one directory. Pass `{ fsync: true }` to flush before each commit marker. |
|
|
419
526
|
|
|
420
|
-
One process owns a storage at a time; there is no cross-process locking. The portable SQLite and JSONL cores (`/storage/sqlite`, `/storage/jsonl`) run without Node APIs, for example on Bun or in Cloudflare Durable Objects, given
|
|
527
|
+
One process owns a storage at a time; there is no cross-process locking. The portable SQLite and JSONL cores (`/storage/sqlite`, `/storage/jsonl`) run without Node APIs, for example on Bun or in Cloudflare Durable Objects, given an asynchronous `SqliteDatabase` facade or a `FileSystem` from `@earendil-works/pi-durable/env`.
|
|
528
|
+
|
|
529
|
+
SQLite adapters implement promise-based `exec`, `run`, `get`, `all`, `transaction`, and `close`. `run`, `get`, and `all` take SQL text plus positional bindings; adapters may cache prepared statements by SQL text. A transaction callback receives a transaction handle; all work in the transaction must use it, and the handle expires when the callback settles. Adapters must queue unrelated operations and other transactions until the transaction finishes, so calling `database` itself inside the callback never settles:
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
await database.transaction(async (transaction) => {
|
|
533
|
+
await transaction.exec("CREATE TABLE example (value TEXT)");
|
|
534
|
+
await transaction.run("INSERT INTO example (value) VALUES (?)", "stored atomically");
|
|
535
|
+
});
|
|
536
|
+
```
|
|
421
537
|
|
|
422
538
|
Custom backends can run the shared conformance suite with any Vitest- or Jest-compatible runner:
|
|
423
539
|
|
|
@@ -458,15 +574,21 @@ node --conditions=source --experimental-strip-types test/examples/14-chat.ts
|
|
|
458
574
|
| [23-subagent-background](test/examples/23-subagent-background.ts) | Persistent subagents: spawn, steer, stop, list, answers reported back, restart-safe |
|
|
459
575
|
| [24-child-tasks](test/examples/24-child-tasks.ts) | A checkout that owns and waits for four payments: failFast, abort, restart |
|
|
460
576
|
| [25-compaction](test/examples/25-compaction.ts) | A long chat compacted in the background, manually, and after a context overflow |
|
|
461
|
-
| [
|
|
577
|
+
| [26-coding-agent](test/examples/26-coding-agent.ts) | CodingTools, live settings from a settings object, an environment that follows the conversation's directory |
|
|
578
|
+
| [27-plan-mode](test/examples/27-plan-mode.ts) | A read-only plan mode as an extension with its own document, switched with `configure()` |
|
|
579
|
+
| [28-reviewer](test/examples/28-reviewer.ts) | A reviewer conversation with its own model, extensions, tools, directory, and review loop |
|
|
580
|
+
| [29-sandbox-per-conversation](test/examples/29-sandbox-per-conversation.ts) | An environment per conversation, looked up from an app document |
|
|
581
|
+
| [30-tool-override](test/examples/30-tool-override.ts) | A same-name bash for some conversations, and a wrapper that times whichever bash won |
|
|
582
|
+
| [31-reload-and-restart](test/examples/31-reload-and-restart.ts) | Reloading an extension mid-call, and stored choices surviving a restart |
|
|
583
|
+
| [00](test/examples/00-conversation.ts)–[13](test/examples/13-recovery.ts) | The layers underneath: sessions, documents, forks, watches, the Harness, agent configuration, reload, extension state, tasks, recovery |
|
|
462
584
|
|
|
463
585
|
Examples that call OpenAI need `OPENAI_API_KEY`; most use the faux provider otherwise.
|
|
464
586
|
|
|
465
587
|
## Design Documents
|
|
466
588
|
|
|
467
|
-
- [`docs/
|
|
468
|
-
- [`docs/pico-v5-handoff.md`](docs/pico-v5-handoff.md): the implementation plan
|
|
469
|
-
- [`docs/pico-v5-chord-usage.md`](docs/pico-v5-chord-usage.md): how the package uses Chord
|
|
589
|
+
- [`docs/spec.md`](https://github.com/earendil-works/pi/blob/main/packages/durable/docs/spec.md): the normative specification
|
|
590
|
+
- [`docs/pico-v5-handoff.md`](https://github.com/earendil-works/pi/blob/main/packages/durable/docs/pico-v5-handoff.md): the implementation plan
|
|
591
|
+
- [`docs/pico-v5-chord-usage.md`](https://github.com/earendil-works/pi/blob/main/packages/durable/docs/pico-v5-chord-usage.md): how the package uses Chord
|
|
470
592
|
|
|
471
593
|
Benchmarks: `npm run bench:storage`, `npm run bench:storage:memory`, and `npm run bench:tool-output`.
|
|
472
594
|
|
package/dist/env/index.d.ts
CHANGED
|
@@ -43,6 +43,11 @@ export interface TextLineReader {
|
|
|
43
43
|
}
|
|
44
44
|
/** Portable filesystem capability. Operations return failures rather than throwing. */
|
|
45
45
|
export interface FileSystem {
|
|
46
|
+
/**
|
|
47
|
+
* The file namespace: equal ids see the same files at the same paths, whatever their `cwd`. Every local Node
|
|
48
|
+
* environment shares one id; each container or remote host has its own.
|
|
49
|
+
*/
|
|
50
|
+
readonly id: string;
|
|
46
51
|
cwd: string;
|
|
47
52
|
absolutePath(path: string, context: Context): Promise<Result<string, FileError>>;
|
|
48
53
|
joinPath(parts: string[], context: Context): Promise<Result<string, FileError>>;
|
package/dist/env/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/env/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/env/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,wFAAwF;AACxF,MAAM,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhG,wBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExE;AAED,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzE;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAGjF;AAED,wBAAgB,cAAc,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAEhH;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAQ7C;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;AAExD,MAAM,MAAM,aAAa,GACtB,SAAS,GACT,WAAW,GACX,mBAAmB,GACnB,eAAe,GACf,cAAc,GACd,SAAS,GACT,eAAe,GACf,SAAS,CAAC;AAEb,qBAAa,SAAU,SAAQ,KAAK;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IAErB,YAAY,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAK7E;CACD;AAED,MAAM,MAAM,kBAAkB,GAC3B,SAAS,GACT,SAAS,GACT,mBAAmB,GACnB,aAAa,GACb,gBAAgB,GAChB,SAAS,CAAC;AAEb,qBAAa,cAAe,SAAQ,KAAK;IACjC,IAAI,EAAE,kBAAkB,CAAC;IAChC,2GAA2G;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;IAE1B,YAAY,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAInE;CACD;AAED,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,GAAG,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAC7E,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,uFAAuF;AACvF,MAAM,WAAW,UAAU;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAChF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACjF,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC;IAC/F,aAAa,CACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,EAC1C,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;IACxC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;IACvF,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAC1G,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAC3G,yDAAyD;IACzD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAC7F,yFAAyF;IACzF,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAC5E,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAC5G,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAC/E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;IAChF,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAClF,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IAC5E,SAAS,CACR,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,EAC5C,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IACpC,MAAM,CACL,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,EAC7D,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IACpC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAChG,cAAc,CACb,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,EACzD,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACtC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED,sFAAsF;AACtF,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wGAAwG;IACxG,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AAED,MAAM,WAAW,KAAK;IACrB,IAAI,CACH,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,YAAa,SAAQ,UAAU,EAAE,KAAK;CAAG"}
|
package/dist/env/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/env/index.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,EAAE,CAAiB,KAAa;IAC/C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,GAAG,CAAiB,KAAa;IAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CAAiB,MAA8B;IACxE,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACnC,OAAO,MAAM,CAAC,KAAK,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,cAAc,CAAgC,MAA8B;IAC3F,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAc;IACrC,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,CAAC;QACJ,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;AACF,CAAC;AAcD,MAAM,OAAO,SAAU,SAAQ,KAAK;IAC5B,IAAI,CAAgB;IACpB,IAAI,CAAU;IAErB,YAAY,IAAmB,EAAE,OAAe,EAAE,IAAa,EAAE,KAAa;QAC7E,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;CACD;AAUD,MAAM,OAAO,cAAe,SAAQ,KAAK;IACjC,IAAI,CAAqB;IAChC,2GAA2G;IACpG,SAAS,CAAU;IAE1B,YAAY,IAAwB,EAAE,OAAe,EAAE,KAAa;QACnE,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;CACD","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\n\n/** Result of a fallible operation. Expected failures are returned instead of thrown. */\nexport type Result<TValue, TError> = { ok: true; value: TValue } | { ok: false; error: TError };\n\nexport function ok<TValue, TError>(value: TValue): Result<TValue, TError> {\n\treturn { ok: true, value };\n}\n\nexport function err<TValue, TError>(error: TError): Result<TValue, TError> {\n\treturn { ok: false, error };\n}\n\nexport function getOrThrow<TValue, TError>(result: Result<TValue, TError>): TValue {\n\tif (!result.ok) throw result.error;\n\treturn result.value;\n}\n\nexport function getOrUndefined<TValue extends object, TError>(result: Result<TValue, TError>): TValue | undefined {\n\treturn result.ok ? result.value : undefined;\n}\n\nexport function toError(error: unknown): Error {\n\tif (error instanceof Error) return error;\n\tif (typeof error === \"string\") return new Error(error);\n\ttry {\n\t\treturn new Error(JSON.stringify(error));\n\t} catch {\n\t\treturn new Error(String(error));\n\t}\n}\n\nexport type FileKind = \"file\" | \"directory\" | \"symlink\";\n\nexport type FileErrorCode =\n\t| \"aborted\"\n\t| \"not_found\"\n\t| \"permission_denied\"\n\t| \"not_directory\"\n\t| \"is_directory\"\n\t| \"invalid\"\n\t| \"not_supported\"\n\t| \"unknown\";\n\nexport class FileError extends Error {\n\tpublic code: FileErrorCode;\n\tpublic path?: string;\n\n\tconstructor(code: FileErrorCode, message: string, path?: string, cause?: Error) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"FileError\";\n\t\tthis.code = code;\n\t\tthis.path = path;\n\t}\n}\n\nexport type ExecutionErrorCode =\n\t| \"aborted\"\n\t| \"timeout\"\n\t| \"shell_unavailable\"\n\t| \"spawn_error\"\n\t| \"callback_error\"\n\t| \"unknown\";\n\nexport class ExecutionError extends Error {\n\tpublic code: ExecutionErrorCode;\n\t/** Spill file of a command that timed out or was aborted after its output crossed the spill thresholds. */\n\tpublic spillPath?: string;\n\n\tconstructor(code: ExecutionErrorCode, message: string, cause?: Error) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"ExecutionError\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface FileInfo {\n\tname: string;\n\tpath: string;\n\tkind: FileKind;\n\tsize: number;\n\tmtimeMs: number;\n}\n\nexport interface TextLine {\n\ttext: string;\n\tterminated: boolean;\n}\n\nexport interface TextLineReader {\n\treadLine(context: Context): Promise<Result<TextLine | undefined, FileError>>;\n\tclose(context: Context): Promise<void>;\n}\n\n/** Portable filesystem capability. Operations return failures rather than throwing. */\nexport interface FileSystem {\n\tcwd: string;\n\tabsolutePath(path: string, context: Context): Promise<Result<string, FileError>>;\n\tjoinPath(parts: string[], context: Context): Promise<Result<string, FileError>>;\n\treadTextFile(path: string, context: Context): Promise<Result<string, FileError>>;\n\topenTextLineReader(path: string, context: Context): Promise<Result<TextLineReader, FileError>>;\n\treadTextLines(\n\t\tpath: string,\n\t\toptions: { maxLines?: number } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<string[], FileError>>;\n\treadBinaryFile(path: string, context: Context): Promise<Result<Uint8Array, FileError>>;\n\twriteFile(path: string, content: string | Uint8Array, context: Context): Promise<Result<void, FileError>>;\n\tappendFile(path: string, content: string | Uint8Array, context: Context): Promise<Result<void, FileError>>;\n\t/** Truncate or extend a file to exactly `size` bytes. */\n\ttruncateFile(path: string, size: number, context: Context): Promise<Result<void, FileError>>;\n\t/** Flush file contents and metadata needed to retrieve them from an open file handle. */\n\tflushFile(path: string, context: Context): Promise<Result<void, FileError>>;\n\trenameFile(sourcePath: string, destinationPath: string, context: Context): Promise<Result<void, FileError>>;\n\tfileInfo(path: string, context: Context): Promise<Result<FileInfo, FileError>>;\n\tlistDir(path: string, context: Context): Promise<Result<FileInfo[], FileError>>;\n\tcanonicalPath(path: string, context: Context): Promise<Result<string, FileError>>;\n\texists(path: string, context: Context): Promise<Result<boolean, FileError>>;\n\tcreateDir(\n\t\tpath: string,\n\t\toptions: { recursive?: boolean } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<void, FileError>>;\n\tremove(\n\t\tpath: string,\n\t\toptions: { recursive?: boolean; force?: boolean } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<void, FileError>>;\n\tcreateTempDir(prefix: string | undefined, context: Context): Promise<Result<string, FileError>>;\n\tcreateTempFile(\n\t\toptions: { prefix?: string; suffix?: string } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<string, FileError>>;\n\tcleanup(context: Context): Promise<void>;\n}\n\n/** Spill the complete output to a temporary file once it exceeds either threshold. */\nexport interface ShellSpillOptions {\n\tafterBytes: number;\n\t/** Complete or partial lines. */\n\tafterLines: number;\n}\n\nexport interface ShellExecResult {\n\texitCode: number;\n\t/** Temporary file holding the complete raw output, when the spill thresholds were exceeded. */\n\tspillPath?: string;\n}\n\nexport interface ShellExecOptions {\n\tcwd?: string;\n\tenv?: Record<string, string>;\n\tinheritEnv?: boolean;\n\ttimeout?: number;\n\t/** Every decoded chunk of combined stdout and stderr as it arrives: raw, unbounded, and unthrottled. */\n\tonOutput?: (text: string, context: Context) => void;\n\tspill?: ShellSpillOptions;\n}\n\nexport interface Shell {\n\texec(\n\t\tcommand: string,\n\t\toptions: ShellExecOptions | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<ShellExecResult, ExecutionError>>;\n\tcleanup(context: Context): Promise<void>;\n}\n\nexport interface ExecutionEnv extends FileSystem, Shell {}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/env/index.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,EAAE,CAAiB,KAAa;IAC/C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,GAAG,CAAiB,KAAa;IAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CAAiB,MAA8B;IACxE,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACnC,OAAO,MAAM,CAAC,KAAK,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,cAAc,CAAgC,MAA8B;IAC3F,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAc;IACrC,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,CAAC;QACJ,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;AACF,CAAC;AAcD,MAAM,OAAO,SAAU,SAAQ,KAAK;IAC5B,IAAI,CAAgB;IACpB,IAAI,CAAU;IAErB,YAAY,IAAmB,EAAE,OAAe,EAAE,IAAa,EAAE,KAAa;QAC7E,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;CACD;AAUD,MAAM,OAAO,cAAe,SAAQ,KAAK;IACjC,IAAI,CAAqB;IAChC,2GAA2G;IACpG,SAAS,CAAU;IAE1B,YAAY,IAAwB,EAAE,OAAe,EAAE,KAAa;QACnE,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;CACD","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\n\n/** Result of a fallible operation. Expected failures are returned instead of thrown. */\nexport type Result<TValue, TError> = { ok: true; value: TValue } | { ok: false; error: TError };\n\nexport function ok<TValue, TError>(value: TValue): Result<TValue, TError> {\n\treturn { ok: true, value };\n}\n\nexport function err<TValue, TError>(error: TError): Result<TValue, TError> {\n\treturn { ok: false, error };\n}\n\nexport function getOrThrow<TValue, TError>(result: Result<TValue, TError>): TValue {\n\tif (!result.ok) throw result.error;\n\treturn result.value;\n}\n\nexport function getOrUndefined<TValue extends object, TError>(result: Result<TValue, TError>): TValue | undefined {\n\treturn result.ok ? result.value : undefined;\n}\n\nexport function toError(error: unknown): Error {\n\tif (error instanceof Error) return error;\n\tif (typeof error === \"string\") return new Error(error);\n\ttry {\n\t\treturn new Error(JSON.stringify(error));\n\t} catch {\n\t\treturn new Error(String(error));\n\t}\n}\n\nexport type FileKind = \"file\" | \"directory\" | \"symlink\";\n\nexport type FileErrorCode =\n\t| \"aborted\"\n\t| \"not_found\"\n\t| \"permission_denied\"\n\t| \"not_directory\"\n\t| \"is_directory\"\n\t| \"invalid\"\n\t| \"not_supported\"\n\t| \"unknown\";\n\nexport class FileError extends Error {\n\tpublic code: FileErrorCode;\n\tpublic path?: string;\n\n\tconstructor(code: FileErrorCode, message: string, path?: string, cause?: Error) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"FileError\";\n\t\tthis.code = code;\n\t\tthis.path = path;\n\t}\n}\n\nexport type ExecutionErrorCode =\n\t| \"aborted\"\n\t| \"timeout\"\n\t| \"shell_unavailable\"\n\t| \"spawn_error\"\n\t| \"callback_error\"\n\t| \"unknown\";\n\nexport class ExecutionError extends Error {\n\tpublic code: ExecutionErrorCode;\n\t/** Spill file of a command that timed out or was aborted after its output crossed the spill thresholds. */\n\tpublic spillPath?: string;\n\n\tconstructor(code: ExecutionErrorCode, message: string, cause?: Error) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"ExecutionError\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface FileInfo {\n\tname: string;\n\tpath: string;\n\tkind: FileKind;\n\tsize: number;\n\tmtimeMs: number;\n}\n\nexport interface TextLine {\n\ttext: string;\n\tterminated: boolean;\n}\n\nexport interface TextLineReader {\n\treadLine(context: Context): Promise<Result<TextLine | undefined, FileError>>;\n\tclose(context: Context): Promise<void>;\n}\n\n/** Portable filesystem capability. Operations return failures rather than throwing. */\nexport interface FileSystem {\n\t/**\n\t * The file namespace: equal ids see the same files at the same paths, whatever their `cwd`. Every local Node\n\t * environment shares one id; each container or remote host has its own.\n\t */\n\treadonly id: string;\n\tcwd: string;\n\tabsolutePath(path: string, context: Context): Promise<Result<string, FileError>>;\n\tjoinPath(parts: string[], context: Context): Promise<Result<string, FileError>>;\n\treadTextFile(path: string, context: Context): Promise<Result<string, FileError>>;\n\topenTextLineReader(path: string, context: Context): Promise<Result<TextLineReader, FileError>>;\n\treadTextLines(\n\t\tpath: string,\n\t\toptions: { maxLines?: number } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<string[], FileError>>;\n\treadBinaryFile(path: string, context: Context): Promise<Result<Uint8Array, FileError>>;\n\twriteFile(path: string, content: string | Uint8Array, context: Context): Promise<Result<void, FileError>>;\n\tappendFile(path: string, content: string | Uint8Array, context: Context): Promise<Result<void, FileError>>;\n\t/** Truncate or extend a file to exactly `size` bytes. */\n\ttruncateFile(path: string, size: number, context: Context): Promise<Result<void, FileError>>;\n\t/** Flush file contents and metadata needed to retrieve them from an open file handle. */\n\tflushFile(path: string, context: Context): Promise<Result<void, FileError>>;\n\trenameFile(sourcePath: string, destinationPath: string, context: Context): Promise<Result<void, FileError>>;\n\tfileInfo(path: string, context: Context): Promise<Result<FileInfo, FileError>>;\n\tlistDir(path: string, context: Context): Promise<Result<FileInfo[], FileError>>;\n\tcanonicalPath(path: string, context: Context): Promise<Result<string, FileError>>;\n\texists(path: string, context: Context): Promise<Result<boolean, FileError>>;\n\tcreateDir(\n\t\tpath: string,\n\t\toptions: { recursive?: boolean } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<void, FileError>>;\n\tremove(\n\t\tpath: string,\n\t\toptions: { recursive?: boolean; force?: boolean } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<void, FileError>>;\n\tcreateTempDir(prefix: string | undefined, context: Context): Promise<Result<string, FileError>>;\n\tcreateTempFile(\n\t\toptions: { prefix?: string; suffix?: string } | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<string, FileError>>;\n\tcleanup(context: Context): Promise<void>;\n}\n\n/** Spill the complete output to a temporary file once it exceeds either threshold. */\nexport interface ShellSpillOptions {\n\tafterBytes: number;\n\t/** Complete or partial lines. */\n\tafterLines: number;\n}\n\nexport interface ShellExecResult {\n\texitCode: number;\n\t/** Temporary file holding the complete raw output, when the spill thresholds were exceeded. */\n\tspillPath?: string;\n}\n\nexport interface ShellExecOptions {\n\tcwd?: string;\n\tenv?: Record<string, string>;\n\tinheritEnv?: boolean;\n\ttimeout?: number;\n\t/** Every decoded chunk of combined stdout and stderr as it arrives: raw, unbounded, and unthrottled. */\n\tonOutput?: (text: string, context: Context) => void;\n\tspill?: ShellSpillOptions;\n}\n\nexport interface Shell {\n\texec(\n\t\tcommand: string,\n\t\toptions: ShellExecOptions | undefined,\n\t\tcontext: Context,\n\t): Promise<Result<ShellExecResult, ExecutionError>>;\n\tcleanup(context: Context): Promise<void>;\n}\n\nexport interface ExecutionEnv extends FileSystem, Shell {}\n"]}
|
package/dist/env/node.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Context } from "@earendil-works/chord";
|
|
2
2
|
import { type ExecutionEnv, ExecutionError, FileError, type FileInfo, type Result, type ShellExecOptions, type ShellExecResult, type TextLineReader } from "./index.ts";
|
|
3
3
|
export declare class NodeExecutionEnv implements ExecutionEnv {
|
|
4
|
+
/** Every local environment sees the same files. */
|
|
5
|
+
readonly id: string;
|
|
4
6
|
cwd: string;
|
|
5
7
|
private shellPath?;
|
|
6
8
|
private shellEnv?;
|
package/dist/env/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/env/node.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/env/node.ts"],"names":[],"mappings":"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"}
|