@earendil-works/pi-durable 0.99.1 → 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 +557 -46
- package/dist/entries.d.ts +20 -2
- package/dist/entries.d.ts.map +1 -1
- package/dist/entries.js +14 -1
- package/dist/entries.js.map +1 -1
- package/dist/env/index.d.ts +18 -38
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js +2 -0
- 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 +53 -58
- 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 +56 -0
- package/dist/harness/compaction.d.ts.map +1 -0
- package/dist/harness/compaction.js +382 -0
- package/dist/harness/compaction.js.map +1 -0
- package/dist/harness/context.d.ts +8 -0
- package/dist/harness/context.d.ts.map +1 -1
- package/dist/harness/context.js +32 -21
- package/dist/harness/context.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 +166 -0
- package/dist/harness/events.d.ts.map +1 -0
- package/dist/harness/events.js +319 -0
- package/dist/harness/events.js.map +1 -0
- package/dist/harness/generation.d.ts +36 -7
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +356 -82
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +141 -106
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/inbox.d.ts +59 -0
- package/dist/harness/inbox.d.ts.map +1 -0
- package/dist/harness/inbox.js +97 -0
- package/dist/harness/inbox.js.map +1 -0
- package/dist/harness/json.d.ts +10 -0
- package/dist/harness/json.d.ts.map +1 -0
- package/dist/harness/json.js +33 -0
- package/dist/harness/json.js.map +1 -0
- package/dist/harness/live.d.ts +66 -7
- package/dist/harness/live.d.ts.map +1 -1
- package/dist/harness/live.js +71 -7
- package/dist/harness/live.js.map +1 -1
- package/dist/harness/output.d.ts +62 -0
- package/dist/harness/output.d.ts.map +1 -0
- package/dist/harness/output.js +261 -0
- package/dist/harness/output.js.map +1 -0
- package/dist/harness/prompt.d.ts +9 -6
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +57 -14
- 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 +69 -277
- package/dist/harness/registry.js.map +1 -1
- package/dist/harness/scheduler.d.ts +42 -12
- package/dist/harness/scheduler.d.ts.map +1 -1
- package/dist/harness/scheduler.js +649 -75
- package/dist/harness/scheduler.js.map +1 -1
- package/dist/harness/submissions.d.ts +14 -9
- package/dist/harness/submissions.d.ts.map +1 -1
- package/dist/harness/submissions.js +76 -34
- 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 +36 -0
- package/dist/harness/tool.d.ts.map +1 -0
- package/dist/harness/tool.js +415 -0
- package/dist/harness/tool.js.map +1 -0
- package/dist/harness/types.d.ts +330 -125
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage.d.ts +18 -0
- package/dist/harness/usage.d.ts.map +1 -0
- package/dist/harness/usage.js +57 -0
- package/dist/harness/usage.js.map +1 -0
- package/dist/harness/view.d.ts +43 -0
- package/dist/harness/view.d.ts.map +1 -0
- package/dist/harness/view.js +189 -0
- package/dist/harness/view.js.map +1 -0
- package/dist/index.d.ts +13 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/session/observation.d.ts +18 -11
- package/dist/session/observation.d.ts.map +1 -1
- package/dist/session/observation.js +24 -13
- package/dist/session/observation.js.map +1 -1
- package/dist/session/session.d.ts +10 -1
- package/dist/session/session.d.ts.map +1 -1
- package/dist/session/session.js +23 -5
- package/dist/session/session.js.map +1 -1
- package/dist/session/transaction.d.ts +12 -3
- package/dist/session/transaction.d.ts.map +1 -1
- package/dist/session/transaction.js +90 -31
- package/dist/session/transaction.js.map +1 -1
- package/dist/storage/jsonl/storage.d.ts +22 -2
- package/dist/storage/jsonl/storage.d.ts.map +1 -1
- package/dist/storage/jsonl/storage.js +1 -1
- package/dist/storage/jsonl/storage.js.map +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/memory.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 +7 -7
- 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/testing/storage-benchmark.d.ts.map +1 -1
- package/dist/testing/storage-benchmark.js +0 -1
- package/dist/testing/storage-benchmark.js.map +1 -1
- package/dist/testing/storage-conformance.d.ts.map +1 -1
- package/dist/testing/storage-conformance.js +34 -2
- package/dist/testing/storage-conformance.js.map +1 -1
- package/dist/tools/bash.d.ts +28 -0
- package/dist/tools/bash.d.ts.map +1 -0
- package/dist/tools/bash.js +70 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/edit-diff.d.ts +89 -0
- package/dist/tools/edit-diff.d.ts.map +1 -0
- package/dist/tools/edit-diff.js +386 -0
- package/dist/tools/edit-diff.js.map +1 -0
- package/dist/tools/edit.d.ts +18 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +117 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/env.d.ts +5 -0
- package/dist/tools/env.d.ts.map +1 -0
- package/dist/tools/env.js +7 -0
- package/dist/tools/env.js.map +1 -0
- package/dist/tools/file-mutation-queue.d.ts +9 -0
- package/dist/tools/file-mutation-queue.d.ts.map +1 -0
- package/dist/tools/file-mutation-queue.js +52 -0
- package/dist/tools/file-mutation-queue.js.map +1 -0
- package/dist/tools/image.d.ts +2 -0
- package/dist/tools/image.d.ts.map +1 -0
- package/dist/tools/image.js +92 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/index.d.ts +23 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/path-utils.d.ts +5 -0
- package/dist/tools/path-utils.d.ts.map +1 -0
- package/dist/tools/path-utils.js +26 -0
- package/dist/tools/path-utils.js.map +1 -0
- package/dist/tools/read.d.ts +17 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +101 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/write.d.ts +10 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +31 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/{env/utils/truncate.d.ts → truncate.d.ts} +1 -17
- package/dist/truncate.d.ts.map +1 -0
- package/dist/truncate.js +146 -0
- package/dist/truncate.js.map +1 -0
- package/dist/types.d.ts +97 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +32 -14
- package/dist/env/utils/adaptive-publisher.d.ts +0 -24
- package/dist/env/utils/adaptive-publisher.d.ts.map +0 -1
- package/dist/env/utils/adaptive-publisher.js +0 -79
- package/dist/env/utils/adaptive-publisher.js.map +0 -1
- package/dist/env/utils/output-capture.d.ts +0 -31
- package/dist/env/utils/output-capture.d.ts.map +0 -1
- package/dist/env/utils/output-capture.js +0 -238
- package/dist/env/utils/output-capture.js.map +0 -1
- package/dist/env/utils/truncate.d.ts.map +0 -1
- package/dist/env/utils/truncate.js +0 -294
- package/dist/env/utils/truncate.js.map +0 -1
- package/dist/harness/config.d.ts +0 -20
- package/dist/harness/config.d.ts.map +0 -1
- package/dist/harness/config.js +0 -18
- 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 -581
- package/docs/pico-v5.md +0 -3084
package/dist/entries.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { JsonValue } from "@earendil-works/chord";
|
|
2
|
+
import type { CompactionReason, ToolDiagnostic } from "./harness/types.ts";
|
|
2
3
|
import type { Entry } from "./types.ts";
|
|
3
4
|
/** Define a typed entry kind whose `is()` guard narrows by `EntryRecord.kind`. */
|
|
4
5
|
export declare function defineEntry<D extends JsonValue = never>(kind: string): Entry<D>;
|
|
@@ -8,6 +9,23 @@ export declare const UserEntry: Entry<never>;
|
|
|
8
9
|
export declare const AssistantEntry: Entry<never>;
|
|
9
10
|
/** Positional prompt and tool change: `model` is `[SystemMessage]` with empty `content`. */
|
|
10
11
|
export declare const SystemEntry: Entry<never>;
|
|
11
|
-
/**
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Tool result: `model` is `[ToolResultMessage]`, whose content ends with the rendered diagnostics block; `data` holds
|
|
14
|
+
* the structured diagnostics, possibly none. Written by tool tasks, and by generation for calls it did not offer.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ToolResultEntry: Entry<{
|
|
17
|
+
diagnostics: ToolDiagnostic[];
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Start of a new context: always `head: "self"`, with `model` absent for a plain reset or `[UserMessage]` carrying the
|
|
21
|
+
* handoff text. Written by `Conversation.reset()` and the `handoff` tool control.
|
|
22
|
+
*/
|
|
23
|
+
export declare const ResetEntry: Entry<never>;
|
|
24
|
+
/**
|
|
25
|
+
* Compaction summary: `model` is `[UserMessage]` with the wrapped summary, `head` the first kept entry. Written by
|
|
26
|
+
* compaction tasks, directly or through a write submission.
|
|
27
|
+
*/
|
|
28
|
+
export declare const CompactionEntry: Entry<{
|
|
29
|
+
reason: CompactionReason;
|
|
30
|
+
}>;
|
|
13
31
|
//# sourceMappingURL=entries.d.ts.map
|
package/dist/entries.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../src/entries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAA2B,MAAM,YAAY,CAAC;AAEjE,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,CAAC,SAAS,SAAS,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAM/E;AAED,sEAAsE;AACtE,eAAO,MAAM,SAAS,cAAyB,CAAC;AAChD,oGAAoG;AACpG,eAAO,MAAM,cAAc,cAA8B,CAAC;AAC1D,4FAA4F;AAC5F,eAAO,MAAM,WAAW,cAA2B,CAAC;AACpD,
|
|
1
|
+
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../src/entries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,KAAK,EAAE,KAAK,EAA2B,MAAM,YAAY,CAAC;AAEjE,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,CAAC,SAAS,SAAS,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAM/E;AAED,sEAAsE;AACtE,eAAO,MAAM,SAAS,cAAyB,CAAC;AAChD,oGAAoG;AACpG,eAAO,MAAM,cAAc,cAA8B,CAAC;AAC1D,4FAA4F;AAC5F,eAAO,MAAM,WAAW,cAA2B,CAAC;AACpD;;;GAGG;AACH,eAAO,MAAM,eAAe;iBAA8B,cAAc,EAAE;EAAqB,CAAC;AAChG;;;GAGG;AACH,eAAO,MAAM,UAAU,cAA0B,CAAC;AAClD;;;GAGG;AACH,eAAO,MAAM,eAAe;YAAyB,gBAAgB;EAAoB,CAAC"}
|
package/dist/entries.js
CHANGED
|
@@ -13,6 +13,19 @@ export const UserEntry = defineEntry("pi.user");
|
|
|
13
13
|
export const AssistantEntry = defineEntry("pi.assistant");
|
|
14
14
|
/** Positional prompt and tool change: `model` is `[SystemMessage]` with empty `content`. */
|
|
15
15
|
export const SystemEntry = defineEntry("pi.system");
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Tool result: `model` is `[ToolResultMessage]`, whose content ends with the rendered diagnostics block; `data` holds
|
|
18
|
+
* the structured diagnostics, possibly none. Written by tool tasks, and by generation for calls it did not offer.
|
|
19
|
+
*/
|
|
17
20
|
export const ToolResultEntry = defineEntry("pi.tool-result");
|
|
21
|
+
/**
|
|
22
|
+
* Start of a new context: always `head: "self"`, with `model` absent for a plain reset or `[UserMessage]` carrying the
|
|
23
|
+
* handoff text. Written by `Conversation.reset()` and the `handoff` tool control.
|
|
24
|
+
*/
|
|
25
|
+
export const ResetEntry = defineEntry("pi.reset");
|
|
26
|
+
/**
|
|
27
|
+
* Compaction summary: `model` is `[UserMessage]` with the wrapped summary, `head` the first kept entry. Written by
|
|
28
|
+
* compaction tasks, directly or through a write submission.
|
|
29
|
+
*/
|
|
30
|
+
export const CompactionEntry = defineEntry("pi.compaction");
|
|
18
31
|
//# sourceMappingURL=entries.js.map
|
package/dist/entries.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.js","sourceRoot":"","sources":["../src/entries.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entries.js","sourceRoot":"","sources":["../src/entries.ts"],"names":[],"mappings":"AAIA,kFAAkF;AAClF,MAAM,UAAU,WAAW,CAA8B,IAAY;IACpE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAChH,OAAO;QACN,IAAI;QACJ,EAAE,EAAE,CAAC,KAA8B,EAA0B,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI;KAC1G,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;AAChD,oGAAoG;AACpG,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;AAC1D,4FAA4F;AAC5F,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;AACpD;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAoC,gBAAgB,CAAC,CAAC;AAChG;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;AAClD;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAA+B,eAAe,CAAC,CAAC","sourcesContent":["import type { JsonValue } from \"@earendil-works/chord\";\nimport type { CompactionReason, ToolDiagnostic } from \"./harness/types.ts\";\nimport type { Entry, EntryRecord, TypedEntry } from \"./types.ts\";\n\n/** Define a typed entry kind whose `is()` guard narrows by `EntryRecord.kind`. */\nexport function defineEntry<D extends JsonValue = never>(kind: string): Entry<D> {\n\tif (typeof kind !== \"string\" || kind.length === 0) throw new TypeError(\"Entry kind must be a non-empty string\");\n\treturn {\n\t\tkind,\n\t\tis: (entry: EntryRecord | undefined): entry is TypedEntry<D> => entry !== undefined && entry.kind === kind,\n\t};\n}\n\n/** User input: `model` is `[UserMessage]`. Written by submissions. */\nexport const UserEntry = defineEntry(\"pi.user\");\n/** Provider result with any stop reason: `model` is `[AssistantMessage]`. Written by generation. */\nexport const AssistantEntry = defineEntry(\"pi.assistant\");\n/** Positional prompt and tool change: `model` is `[SystemMessage]` with empty `content`. */\nexport const SystemEntry = defineEntry(\"pi.system\");\n/**\n * Tool result: `model` is `[ToolResultMessage]`, whose content ends with the rendered diagnostics block; `data` holds\n * the structured diagnostics, possibly none. Written by tool tasks, and by generation for calls it did not offer.\n */\nexport const ToolResultEntry = defineEntry<{ diagnostics: ToolDiagnostic[] }>(\"pi.tool-result\");\n/**\n * Start of a new context: always `head: \"self\"`, with `model` absent for a plain reset or `[UserMessage]` carrying the\n * handoff text. Written by `Conversation.reset()` and the `handoff` tool control.\n */\nexport const ResetEntry = defineEntry(\"pi.reset\");\n/**\n * Compaction summary: `model` is `[UserMessage]` with the wrapped summary, `head` the first kept entry. Written by\n * compaction tasks, directly or through a write submission.\n */\nexport const CompactionEntry = defineEntry<{ reason: CompactionReason }>(\"pi.compaction\");\n"]}
|
package/dist/env/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Context } from "@earendil-works/chord";
|
|
2
|
-
import type { TruncationResult } from "./utils/truncate.ts";
|
|
3
2
|
/** Result of a fallible operation. Expected failures are returned instead of thrown. */
|
|
4
3
|
export type Result<TValue, TError> = {
|
|
5
4
|
ok: true;
|
|
@@ -23,6 +22,8 @@ export declare class FileError extends Error {
|
|
|
23
22
|
export type ExecutionErrorCode = "aborted" | "timeout" | "shell_unavailable" | "spawn_error" | "callback_error" | "unknown";
|
|
24
23
|
export declare class ExecutionError extends Error {
|
|
25
24
|
code: ExecutionErrorCode;
|
|
25
|
+
/** Spill file of a command that timed out or was aborted after its output crossed the spill thresholds. */
|
|
26
|
+
spillPath?: string;
|
|
26
27
|
constructor(code: ExecutionErrorCode, message: string, cause?: Error);
|
|
27
28
|
}
|
|
28
29
|
export interface FileInfo {
|
|
@@ -42,6 +43,11 @@ export interface TextLineReader {
|
|
|
42
43
|
}
|
|
43
44
|
/** Portable filesystem capability. Operations return failures rather than throwing. */
|
|
44
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;
|
|
45
51
|
cwd: string;
|
|
46
52
|
absolutePath(path: string, context: Context): Promise<Result<string, FileError>>;
|
|
47
53
|
joinPath(parts: string[], context: Context): Promise<Result<string, FileError>>;
|
|
@@ -76,51 +82,25 @@ export interface FileSystem {
|
|
|
76
82
|
} | undefined, context: Context): Promise<Result<string, FileError>>;
|
|
77
83
|
cleanup(context: Context): Promise<void>;
|
|
78
84
|
}
|
|
79
|
-
|
|
80
|
-
export interface
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
export interface ShellOutputCaptureOptions {
|
|
86
|
-
limits: ShellOutputLimits;
|
|
87
|
-
spill?: boolean;
|
|
88
|
-
}
|
|
89
|
-
export type ShellOutputTruncation = Omit<TruncationResult, "content">;
|
|
90
|
-
export interface ShellOutputMetadata {
|
|
91
|
-
truncation: ShellOutputTruncation;
|
|
92
|
-
spillPath?: string;
|
|
93
|
-
lastLineBytes?: number;
|
|
85
|
+
/** Spill the complete output to a temporary file once it exceeds either threshold. */
|
|
86
|
+
export interface ShellSpillOptions {
|
|
87
|
+
afterBytes: number;
|
|
88
|
+
/** Complete or partial lines. */
|
|
89
|
+
afterLines: number;
|
|
94
90
|
}
|
|
95
|
-
export interface
|
|
96
|
-
text: string;
|
|
97
|
-
}
|
|
98
|
-
export type ShellOutputUpdate = {
|
|
99
|
-
kind: "replace";
|
|
100
|
-
output: ShellOutputView;
|
|
101
|
-
} | {
|
|
102
|
-
kind: "append";
|
|
103
|
-
text: string;
|
|
104
|
-
metadata: ShellOutputMetadata;
|
|
105
|
-
} | {
|
|
106
|
-
kind: "slide";
|
|
107
|
-
drop: number;
|
|
108
|
-
text: string;
|
|
109
|
-
metadata: ShellOutputMetadata;
|
|
110
|
-
} | {
|
|
111
|
-
kind: "metadata";
|
|
112
|
-
metadata: ShellOutputMetadata;
|
|
113
|
-
};
|
|
114
|
-
export interface ShellExecResult extends ShellOutputMetadata {
|
|
91
|
+
export interface ShellExecResult {
|
|
115
92
|
exitCode: number;
|
|
93
|
+
/** Temporary file holding the complete raw output, when the spill thresholds were exceeded. */
|
|
94
|
+
spillPath?: string;
|
|
116
95
|
}
|
|
117
96
|
export interface ShellExecOptions {
|
|
118
97
|
cwd?: string;
|
|
119
98
|
env?: Record<string, string>;
|
|
120
99
|
inheritEnv?: boolean;
|
|
121
100
|
timeout?: number;
|
|
122
|
-
|
|
123
|
-
|
|
101
|
+
/** Every decoded chunk of combined stdout and stderr as it arrives: raw, unbounded, and unthrottled. */
|
|
102
|
+
onOutput?: (text: string, context: Context) => void;
|
|
103
|
+
spill?: ShellSpillOptions;
|
|
124
104
|
}
|
|
125
105
|
export interface Shell {
|
|
126
106
|
exec(command: string, options: ShellExecOptions | undefined, context: Context): Promise<Result<ShellExecResult, ExecutionError>>;
|
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":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;
|
|
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
CHANGED
|
@@ -36,6 +36,8 @@ export class FileError extends Error {
|
|
|
36
36
|
}
|
|
37
37
|
export class ExecutionError extends Error {
|
|
38
38
|
code;
|
|
39
|
+
/** Spill file of a command that timed out or was aborted after its output crossed the spill thresholds. */
|
|
40
|
+
spillPath;
|
|
39
41
|
constructor(code, message, cause) {
|
|
40
42
|
super(message, cause === undefined ? undefined : { cause });
|
|
41
43
|
this.name = "ExecutionError";
|
package/dist/env/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/env/index.ts"],"names":[],"mappings":"
|
|
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":"AAoBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EACN,KAAK,YAAY,EACjB,cAAc,EAEd,SAAS,EACT,KAAK,QAAQ,EAGb,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,eAAe,EAEpB,KAAK,cAAc,EAEnB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/env/node.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EACN,KAAK,YAAY,EACjB,cAAc,EAEd,SAAS,EACT,KAAK,QAAQ,EAGb,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,eAAe,EAEpB,KAAK,cAAc,EAEnB,MAAM,YAAY,CAAC;AAiZpB,qBAAa,gBAAiB,YAAW,YAAY;IACpD,mDAAmD;IACnD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAgB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,CAAoB;IACrC,OAAO,CAAC,eAAe,CAAqB;IAE5C,YAAY,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;KAAE,EAIrF;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAEtF;IAEK,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAErF;IAEK,IAAI,CACT,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,CAoOlD;IAEK,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAenG;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAUrF;IAEK,aAAa,CAClB,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,CAgBtC;IAEK,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAU3F;IAEK,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,CAc9G;IAEK,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,CAe/G;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAmBjG;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAgBhF;IAEK,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAWhH;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CASnF;IAEK,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,CAuBpF;IAEK,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAStF;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAKhF;IAEK,SAAS,CACd,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,CAUlC;IAEK,MAAM,CACX,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,CAUlC;IAEK,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CASpG;IAEK,cAAc,CACnB,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,CAUpC;IAEK,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9C;CACD"}
|
package/dist/env/node.js
CHANGED
|
@@ -6,11 +6,10 @@ import { homedir, constants as osConstants, tmpdir } from "node:os";
|
|
|
6
6
|
import { basename, isAbsolute, join, resolve } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { ExecutionError, err, FileError, ok, toError, } from "./index.js";
|
|
9
|
-
import { OutputCapture } from "./utils/output-capture.js";
|
|
10
9
|
const MAX_TIMEOUT_MS = 2_147_483_647;
|
|
11
10
|
const MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;
|
|
12
11
|
const EXIT_STDIO_GRACE_MS = 100;
|
|
13
|
-
const SPILL_HIGH_WATER_MARK =
|
|
12
|
+
const SPILL_HIGH_WATER_MARK = 1024 * 1024;
|
|
14
13
|
function resolveTimeoutMs(timeout) {
|
|
15
14
|
if (timeout === undefined)
|
|
16
15
|
return ok(undefined);
|
|
@@ -379,6 +378,8 @@ class NodeTextLineReader {
|
|
|
379
378
|
}
|
|
380
379
|
}
|
|
381
380
|
export class NodeExecutionEnv {
|
|
381
|
+
/** Every local environment sees the same files. */
|
|
382
|
+
id = "node:local";
|
|
382
383
|
cwd;
|
|
383
384
|
shellPath;
|
|
384
385
|
shellEnv;
|
|
@@ -437,18 +438,23 @@ export class NodeExecutionEnv {
|
|
|
437
438
|
callbackError = new ExecutionError("callback_error", cause.message, cause);
|
|
438
439
|
onAbort();
|
|
439
440
|
};
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
441
|
+
// One decoder per stream, so a character split across chunks of one stream survives interleaving.
|
|
442
|
+
const stdoutDecoder = new TextDecoder();
|
|
443
|
+
const stderrDecoder = new TextDecoder();
|
|
444
|
+
// No output reaches the caller after exec() settled, for example from a descendant holding stdio open.
|
|
445
|
+
const emit = (text) => {
|
|
446
|
+
if (settled || text === "" || options?.onOutput === undefined || callbackError !== undefined)
|
|
447
|
+
return;
|
|
448
|
+
try {
|
|
449
|
+
options.onOutput(text, context);
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
failCallback(error);
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
// Output seen before the spill starts: counted against the thresholds and kept for the spill's prefix.
|
|
456
|
+
let seenBytes = 0;
|
|
457
|
+
let seenNewlines = 0;
|
|
452
458
|
const settle = (result) => {
|
|
453
459
|
if (settled)
|
|
454
460
|
return;
|
|
@@ -459,7 +465,6 @@ export class NodeExecutionEnv {
|
|
|
459
465
|
signal.removeEventListener("abort", onAbort);
|
|
460
466
|
if (child?.pid)
|
|
461
467
|
this.activeChildPids.delete(child.pid);
|
|
462
|
-
capture.dispose();
|
|
463
468
|
resolvePromise(result);
|
|
464
469
|
};
|
|
465
470
|
const pauseOutput = () => {
|
|
@@ -506,7 +511,6 @@ export class NodeExecutionEnv {
|
|
|
506
511
|
if (!created.ok)
|
|
507
512
|
throw created.error;
|
|
508
513
|
spillPath = created.value;
|
|
509
|
-
capture.setSpillPath(spillPath);
|
|
510
514
|
spillStream = createWriteStream(spillPath, { flags: "a", highWaterMark: SPILL_HIGH_WATER_MARK });
|
|
511
515
|
spillStream.on("error", failSpill);
|
|
512
516
|
for (const queued of spillQueue)
|
|
@@ -561,69 +565,60 @@ export class NodeExecutionEnv {
|
|
|
561
565
|
else
|
|
562
566
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
563
567
|
}
|
|
564
|
-
const feed = (chunk) => {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}
|
|
573
|
-
else if (capture.truncated) {
|
|
574
|
-
for (const prefix of spillPrefix)
|
|
575
|
-
startSpill(prefix);
|
|
576
|
-
spillPrefix.length = 0;
|
|
577
|
-
startSpill(chunk);
|
|
578
|
-
}
|
|
579
|
-
else {
|
|
580
|
-
spillPrefix.push(chunk);
|
|
581
|
-
}
|
|
568
|
+
const feed = (decoder) => (chunk) => {
|
|
569
|
+
emit(decoder.decode(chunk, { stream: true }));
|
|
570
|
+
const spill = options?.spill;
|
|
571
|
+
if (spill === undefined || chunk.length === 0)
|
|
572
|
+
return;
|
|
573
|
+
if (spillStart !== undefined) {
|
|
574
|
+
startSpill(chunk);
|
|
575
|
+
return;
|
|
582
576
|
}
|
|
583
|
-
|
|
584
|
-
|
|
577
|
+
seenBytes += chunk.length;
|
|
578
|
+
for (let index = chunk.indexOf(0x0a); index !== -1; index = chunk.indexOf(0x0a, index + 1))
|
|
579
|
+
seenNewlines++;
|
|
580
|
+
const lines = seenNewlines + (chunk[chunk.length - 1] === 0x0a ? 0 : 1);
|
|
581
|
+
if (seenBytes <= spill.afterBytes && lines <= spill.afterLines) {
|
|
582
|
+
spillPrefix.push(chunk);
|
|
583
|
+
return;
|
|
585
584
|
}
|
|
585
|
+
for (const prefix of spillPrefix)
|
|
586
|
+
startSpill(prefix);
|
|
587
|
+
spillPrefix.length = 0;
|
|
588
|
+
startSpill(chunk);
|
|
586
589
|
};
|
|
587
|
-
child.stdout?.on("data", feed);
|
|
588
|
-
child.stderr?.on("data", feed);
|
|
590
|
+
child.stdout?.on("data", feed(stdoutDecoder));
|
|
591
|
+
child.stderr?.on("data", feed(stderrDecoder));
|
|
589
592
|
void waitForChildProcess(child, () => spillError === undefined &&
|
|
590
593
|
spillStart !== undefined &&
|
|
591
594
|
(spillStream === undefined || spillBackpressured)).then(async ({ code, signal: exitSignal }) => {
|
|
592
595
|
await finishSpill();
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
capture.flush();
|
|
596
|
-
}
|
|
597
|
-
catch (error) {
|
|
598
|
-
failCallback(error);
|
|
599
|
-
}
|
|
596
|
+
emit(stdoutDecoder.decode());
|
|
597
|
+
emit(stderrDecoder.decode());
|
|
600
598
|
if (callbackError) {
|
|
601
599
|
settle(err(callbackError));
|
|
602
600
|
return;
|
|
603
601
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
602
|
+
const interrupted = timedOut
|
|
603
|
+
? new ExecutionError("timeout", `timeout:${options?.timeout}`)
|
|
604
|
+
: signal?.aborted
|
|
605
|
+
? new ExecutionError("aborted", "aborted")
|
|
606
|
+
: undefined;
|
|
607
|
+
if (interrupted !== undefined) {
|
|
608
|
+
if (spillPath !== undefined)
|
|
609
|
+
interrupted.spillPath = spillPath;
|
|
610
|
+
settle(err(interrupted));
|
|
610
611
|
return;
|
|
611
612
|
}
|
|
612
613
|
if (spillError) {
|
|
613
614
|
settle(err(spillError));
|
|
614
615
|
return;
|
|
615
616
|
}
|
|
616
|
-
const output = capture.snapshot();
|
|
617
617
|
// A process killed by a signal (e.g. OOM killer) has no exit code; map it
|
|
618
618
|
// to the conventional 128 + signal number so callers do not mistake it
|
|
619
619
|
// for a successful exit.
|
|
620
620
|
const exitCode = code ?? (exitSignal ? 128 + (osConstants.signals[exitSignal] ?? 0) : 1);
|
|
621
|
-
settle(ok({
|
|
622
|
-
exitCode,
|
|
623
|
-
truncation: output.truncation,
|
|
624
|
-
...(output.spillPath === undefined ? {} : { spillPath: output.spillPath }),
|
|
625
|
-
...(output.lastLineBytes === undefined ? {} : { lastLineBytes: output.lastLineBytes }),
|
|
626
|
-
}));
|
|
621
|
+
settle(ok({ exitCode, ...(spillPath === undefined ? {} : { spillPath }) }));
|
|
627
622
|
}, (error) => settle(err(new ExecutionError("spawn_error", error.message, error))));
|
|
628
623
|
});
|
|
629
624
|
}
|