@codeworksh/plugin 0.1.0-canary.23.1.gdb705390 → 0.1.0-canary.24.1.g001b9423
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/{event-6sTQ_4bq.d.mts → event-mKxToqmh.d.mts} +33 -33
- package/event.d.mts +1 -1
- package/{filesystem-BFCKzgND.mjs → filesystem-B9bz-Lsa.mjs} +36 -2
- package/filesystem-B9bz-Lsa.mjs.map +1 -0
- package/{filesystem-BYaEdL14.d.mts → filesystem-CuGE9poU.d.mts} +19 -3
- package/index.d.mts +2 -2
- package/{io-RvZvG-4N.mjs → io-CnEW_rHm.mjs} +2 -2
- package/{io-RvZvG-4N.mjs.map → io-CnEW_rHm.mjs.map} +1 -1
- package/{io-CXi2Sjg9.d.mts → io-nhvNKC33.d.mts} +2 -2
- package/package.json +2 -2
- package/plugin/tool.d.mts +1 -1
- package/{plugin-Bh6xA5Wm.d.mts → plugin-C2ZADu75.d.mts} +4 -4
- package/plugin.d.mts +2 -2
- package/sandbox/driver.d.mts +1 -1
- package/sandbox/driver.mjs +1 -1
- package/sandbox/errors.d.mts +1 -1
- package/sandbox/filesystem.d.mts +2 -2
- package/sandbox/filesystem.mjs +2 -2
- package/sandbox/instance.d.mts +1 -1
- package/sandbox/io.d.mts +1 -1
- package/sandbox/io.mjs +1 -1
- package/sandbox.d.mts +2 -2
- package/sandbox.mjs +2 -2
- package/tool/progress.d.mts +1 -1
- package/{tool-D-AvN_qK.d.mts → tool-B7sWVmBt.d.mts} +8 -1
- package/{tool-CaKCqyEz.d.mts → tool-hXy4__zc.d.mts} +2 -2
- package/tool.d.mts +1 -1
- package/tool.mjs.map +1 -1
- package/filesystem-BFCKzgND.mjs.map +0 -1
|
@@ -156,19 +156,14 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
156
156
|
type: "image";
|
|
157
157
|
data: string;
|
|
158
158
|
mimeType: string;
|
|
159
|
-
} | {
|
|
160
|
-
type: "thinking";
|
|
161
|
-
thinking: string;
|
|
162
|
-
thinkingSignature?: string;
|
|
163
|
-
redacted?: boolean;
|
|
164
159
|
} | {
|
|
165
160
|
addedToolNames?: string[];
|
|
166
161
|
arguments: Record<string, any>;
|
|
167
162
|
callID: string;
|
|
168
163
|
name: string;
|
|
169
164
|
namespace?: string;
|
|
170
|
-
|
|
171
|
-
content
|
|
165
|
+
result: {
|
|
166
|
+
content: ({
|
|
172
167
|
type: "text";
|
|
173
168
|
text: string;
|
|
174
169
|
textSignature?: string;
|
|
@@ -178,8 +173,9 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
178
173
|
mimeType: string;
|
|
179
174
|
})[];
|
|
180
175
|
details?: any;
|
|
176
|
+
isError: false;
|
|
181
177
|
};
|
|
182
|
-
status: "
|
|
178
|
+
status: "completed";
|
|
183
179
|
thoughtSignature?: string;
|
|
184
180
|
time: {
|
|
185
181
|
start: number;
|
|
@@ -203,9 +199,9 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
203
199
|
mimeType: string;
|
|
204
200
|
})[];
|
|
205
201
|
details?: any;
|
|
206
|
-
isError:
|
|
202
|
+
isError: true;
|
|
207
203
|
};
|
|
208
|
-
status: "
|
|
204
|
+
status: "error";
|
|
209
205
|
thoughtSignature?: string;
|
|
210
206
|
time: {
|
|
211
207
|
start: number;
|
|
@@ -231,7 +227,7 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
231
227
|
details?: any;
|
|
232
228
|
isError: true;
|
|
233
229
|
};
|
|
234
|
-
status: "
|
|
230
|
+
status: "skipped";
|
|
235
231
|
thoughtSignature?: string;
|
|
236
232
|
time: {
|
|
237
233
|
start: number;
|
|
@@ -257,21 +253,26 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
257
253
|
details?: any;
|
|
258
254
|
isError: true;
|
|
259
255
|
};
|
|
260
|
-
status: "
|
|
256
|
+
status: "aborted";
|
|
261
257
|
thoughtSignature?: string;
|
|
262
258
|
time: {
|
|
263
259
|
start: number;
|
|
264
260
|
end: number;
|
|
265
261
|
};
|
|
266
262
|
type: "toolCall";
|
|
263
|
+
} | {
|
|
264
|
+
type: "thinking";
|
|
265
|
+
thinking: string;
|
|
266
|
+
thinkingSignature?: string;
|
|
267
|
+
redacted?: boolean;
|
|
267
268
|
} | {
|
|
268
269
|
addedToolNames?: string[];
|
|
269
270
|
arguments: Record<string, any>;
|
|
270
271
|
callID: string;
|
|
271
272
|
name: string;
|
|
272
273
|
namespace?: string;
|
|
273
|
-
|
|
274
|
-
content
|
|
274
|
+
partial?: {
|
|
275
|
+
content?: ({
|
|
275
276
|
type: "text";
|
|
276
277
|
text: string;
|
|
277
278
|
textSignature?: string;
|
|
@@ -281,9 +282,8 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
281
282
|
mimeType: string;
|
|
282
283
|
})[];
|
|
283
284
|
details?: any;
|
|
284
|
-
isError: true;
|
|
285
285
|
};
|
|
286
|
-
status: "
|
|
286
|
+
status: "running";
|
|
287
287
|
thoughtSignature?: string;
|
|
288
288
|
time: {
|
|
289
289
|
start: number;
|
|
@@ -458,19 +458,14 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
458
458
|
type: "image";
|
|
459
459
|
data: string;
|
|
460
460
|
mimeType: string;
|
|
461
|
-
} | {
|
|
462
|
-
type: "thinking";
|
|
463
|
-
thinking: string;
|
|
464
|
-
thinkingSignature?: string;
|
|
465
|
-
redacted?: boolean;
|
|
466
461
|
} | {
|
|
467
462
|
addedToolNames?: string[];
|
|
468
463
|
arguments: Record<string, any>;
|
|
469
464
|
callID: string;
|
|
470
465
|
name: string;
|
|
471
466
|
namespace?: string;
|
|
472
|
-
|
|
473
|
-
content
|
|
467
|
+
result: {
|
|
468
|
+
content: ({
|
|
474
469
|
type: "text";
|
|
475
470
|
text: string;
|
|
476
471
|
textSignature?: string;
|
|
@@ -480,8 +475,9 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
480
475
|
mimeType: string;
|
|
481
476
|
})[];
|
|
482
477
|
details?: any;
|
|
478
|
+
isError: false;
|
|
483
479
|
};
|
|
484
|
-
status: "
|
|
480
|
+
status: "completed";
|
|
485
481
|
thoughtSignature?: string;
|
|
486
482
|
time: {
|
|
487
483
|
start: number;
|
|
@@ -505,9 +501,9 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
505
501
|
mimeType: string;
|
|
506
502
|
})[];
|
|
507
503
|
details?: any;
|
|
508
|
-
isError:
|
|
504
|
+
isError: true;
|
|
509
505
|
};
|
|
510
|
-
status: "
|
|
506
|
+
status: "error";
|
|
511
507
|
thoughtSignature?: string;
|
|
512
508
|
time: {
|
|
513
509
|
start: number;
|
|
@@ -533,7 +529,7 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
533
529
|
details?: any;
|
|
534
530
|
isError: true;
|
|
535
531
|
};
|
|
536
|
-
status: "
|
|
532
|
+
status: "skipped";
|
|
537
533
|
thoughtSignature?: string;
|
|
538
534
|
time: {
|
|
539
535
|
start: number;
|
|
@@ -559,21 +555,26 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
559
555
|
details?: any;
|
|
560
556
|
isError: true;
|
|
561
557
|
};
|
|
562
|
-
status: "
|
|
558
|
+
status: "aborted";
|
|
563
559
|
thoughtSignature?: string;
|
|
564
560
|
time: {
|
|
565
561
|
start: number;
|
|
566
562
|
end: number;
|
|
567
563
|
};
|
|
568
564
|
type: "toolCall";
|
|
565
|
+
} | {
|
|
566
|
+
type: "thinking";
|
|
567
|
+
thinking: string;
|
|
568
|
+
thinkingSignature?: string;
|
|
569
|
+
redacted?: boolean;
|
|
569
570
|
} | {
|
|
570
571
|
addedToolNames?: string[];
|
|
571
572
|
arguments: Record<string, any>;
|
|
572
573
|
callID: string;
|
|
573
574
|
name: string;
|
|
574
575
|
namespace?: string;
|
|
575
|
-
|
|
576
|
-
content
|
|
576
|
+
partial?: {
|
|
577
|
+
content?: ({
|
|
577
578
|
type: "text";
|
|
578
579
|
text: string;
|
|
579
580
|
textSignature?: string;
|
|
@@ -583,9 +584,8 @@ declare const AikitAssistantMessage: Schema.decodeTo<Schema.declare<{
|
|
|
583
584
|
mimeType: string;
|
|
584
585
|
})[];
|
|
585
586
|
details?: any;
|
|
586
|
-
isError: true;
|
|
587
587
|
};
|
|
588
|
-
status: "
|
|
588
|
+
status: "running";
|
|
589
589
|
thoughtSignature?: string;
|
|
590
590
|
time: {
|
|
591
591
|
start: number;
|
|
@@ -896,4 +896,4 @@ declare function durable<const Definitions extends ReadonlyArray<Definition>>(de
|
|
|
896
896
|
declare function latest(definitions: ReadonlyArray<Definition>): ReadonlyMap<string, Definition<string, Schema.Codec<unknown, unknown, never, never>>>;
|
|
897
897
|
//#endregion
|
|
898
898
|
export { ID as a, define as c, inventory as d, latest as f, Definition as i, durable as l, AikitToolCallTerminalPart as n, Payload as o, versionedType as p, Data as r, PublishOptions as s, AikitAssistantMessage as t, event_d_exports as u };
|
|
899
|
-
//# sourceMappingURL=event-
|
|
899
|
+
//# sourceMappingURL=event-mKxToqmh.d.mts.map
|
package/event.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ID, c as define, d as inventory, f as latest, i as Definition, l as durable, n as AikitToolCallTerminalPart, o as Payload, p as versionedType, r as Data, s as PublishOptions, t as AikitAssistantMessage, u as event_d_exports } from "./event-
|
|
1
|
+
import { a as ID, c as define, d as inventory, f as latest, i as Definition, l as durable, n as AikitToolCallTerminalPart, o as Payload, p as versionedType, r as Data, s as PublishOptions, t as AikitAssistantMessage, u as event_d_exports } from "./event-mKxToqmh.mjs";
|
|
2
2
|
export { AikitAssistantMessage, AikitToolCallTerminalPart, Data, Definition, event_d_exports as EventSchema, ID, Payload, PublishOptions, define, durable, inventory, latest, versionedType };
|
|
@@ -206,6 +206,8 @@ var filesystem_exports = /* @__PURE__ */ __exportAll({
|
|
|
206
206
|
Service: () => Service,
|
|
207
207
|
fromProvider: () => fromProvider,
|
|
208
208
|
isNotFoundError: () => isNotFoundError,
|
|
209
|
+
readBytesScript: () => readBytesScript,
|
|
210
|
+
readBytesViaShell: () => readBytesViaShell,
|
|
209
211
|
realpathScripts: () => realpathScripts,
|
|
210
212
|
validateRmOptions: () => validateRmOptions,
|
|
211
213
|
withCwd: () => withCwd
|
|
@@ -267,6 +269,36 @@ const realpathScripts = [
|
|
|
267
269
|
"cd -- \"$1\" && pwd -P",
|
|
268
270
|
"cd -- \"$(dirname -- \"$1\")\" && printf '%s/%s' \"$(pwd -P)\" \"$(basename -- \"$1\")\""
|
|
269
271
|
];
|
|
272
|
+
/**
|
|
273
|
+
* Shell form of `readBytes` for backends that only expose a process API. Run as
|
|
274
|
+
* `sh -c <script> _ <path> <offset + 1> <length>`; prints the bytes as base64,
|
|
275
|
+
* so binary content survives a transport that decodes stdout as text. Exits 2
|
|
276
|
+
* when the path does not exist, 3 when it cannot be opened.
|
|
277
|
+
*/
|
|
278
|
+
const readBytesScript = [
|
|
279
|
+
"[ -e \"$1\" ] || exit 2",
|
|
280
|
+
"{ : < \"$1\"; } 2>/dev/null || exit 3",
|
|
281
|
+
"tail -c +\"$2\" -- \"$1\" | head -c \"$3\" | base64"
|
|
282
|
+
].join("\n");
|
|
283
|
+
/**
|
|
284
|
+
* `Provider.readBytes` for a backend that runs an argument vector and collects
|
|
285
|
+
* its output. A missing path rejects with `ENOENT`, the shape `isNotFoundError` recognises.
|
|
286
|
+
*/
|
|
287
|
+
const readBytesViaShell = (run) => async (path, offset, length) => {
|
|
288
|
+
const result = await run([
|
|
289
|
+
"sh",
|
|
290
|
+
"-c",
|
|
291
|
+
readBytesScript,
|
|
292
|
+
"_",
|
|
293
|
+
path,
|
|
294
|
+
String(offset + 1),
|
|
295
|
+
String(length)
|
|
296
|
+
]);
|
|
297
|
+
if (result.exitCode === 2) throw Object.assign(/* @__PURE__ */ new Error(`ENOENT: no such file or directory, readBytes '${path}'`), { code: "ENOENT" });
|
|
298
|
+
if (result.exitCode === 3) throw new Error(`readBytes: cannot open '${path}'`);
|
|
299
|
+
if (result.exitCode !== 0) throw new Error(`readBytes failed (exit ${result.exitCode}): ${(result.stderr ?? result.stdout).trim()}`);
|
|
300
|
+
return new Uint8Array(Buffer.from(result.stdout.replace(/\s/g, ""), "base64"));
|
|
301
|
+
};
|
|
270
302
|
/** The runtime filesystem service — the live {@link Interface} for the active sandbox. */
|
|
271
303
|
var Service = class extends Context.Service()("@codeworksh/plugin/sandbox/filesystem/Service") {};
|
|
272
304
|
/**
|
|
@@ -306,6 +338,7 @@ const fromProvider = (provider) => {
|
|
|
306
338
|
return {
|
|
307
339
|
readFile: Effect.fn("SandboxFileSystem.readFile")((path) => attempt("readFile", path, () => provider.readFile(path))),
|
|
308
340
|
readFileBuffer: Effect.fn("SandboxFileSystem.readFileBuffer")((path) => attempt("readFileBuffer", path, () => provider.readFileBuffer(path))),
|
|
341
|
+
readBytes: Effect.fn("SandboxFileSystem.readBytes")((path, offset, length) => attempt("readBytes", path, () => provider.readBytes(path, offset, length))),
|
|
309
342
|
writeFile: Effect.fn("SandboxFileSystem.writeFile")(writeCreatingParents),
|
|
310
343
|
stat: Effect.fn("SandboxFileSystem.stat")((path) => attempt("stat", path, () => provider.stat(path))),
|
|
311
344
|
...provider.lstat === void 0 ? {} : { lstat: Effect.fn("SandboxFileSystem.lstat")((path) => attempt("lstat", path, () => provider.lstat(path))) },
|
|
@@ -330,6 +363,7 @@ const withCwd = (fs, cwd) => {
|
|
|
330
363
|
return {
|
|
331
364
|
readFile: (path) => fs.readFile(at(path)),
|
|
332
365
|
readFileBuffer: (path) => fs.readFileBuffer(at(path)),
|
|
366
|
+
readBytes: (path, offset, length) => fs.readBytes(at(path), offset, length),
|
|
333
367
|
writeFile: (path, content) => fs.writeFile(at(path), content),
|
|
334
368
|
stat: (path) => fs.stat(at(path)),
|
|
335
369
|
readdir: (path) => fs.readdir(at(path)),
|
|
@@ -342,6 +376,6 @@ const withCwd = (fs, cwd) => {
|
|
|
342
376
|
};
|
|
343
377
|
};
|
|
344
378
|
//#endregion
|
|
345
|
-
export { fromProvider as a,
|
|
379
|
+
export { fromProvider as a, readBytesViaShell as c, withCwd as d, scan_exports as f, filesystem_exports as i, realpathScripts as l, OperationUnsupportedError as n, isNotFoundError as o, Service as r, readBytesScript as s, FileSystemError as t, validateRmOptions as u };
|
|
346
380
|
|
|
347
|
-
//# sourceMappingURL=filesystem-
|
|
381
|
+
//# sourceMappingURL=filesystem-B9bz-Lsa.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem-B9bz-Lsa.mjs","names":["validateScan"],"sources":["../../src/sandbox/scan.ts","../../src/sandbox/filesystem.ts"],"sourcesContent":["/**\n * Bounded line reads: one pass over a file that returns a window of its lines\n * without ever holding more than that window.\n *\n * Lines are the file split on `\\n`, where a trailing newline ends the last line\n * rather than starting an empty one: `\"\"` has 0 lines, `\"a\"` and `\"a\\n\"` have 1,\n * `\"a\\n\\n\"` has 2. A UTF-8 byte-order mark at the start of the file is not part\n * of the first line. Line lengths are in bytes.\n *\n * Two implementations share these rules, and a backend uses whichever fits:\n * {@link LineScanner} over a byte stream, or {@link script} run inside the\n * sandbox so only the window crosses the network.\n */\n\nexport interface LineScanOptions {\n\t/** First selected line, 0-based. */\n\treadonly startLine: number;\n\t/** End of the selection, exclusive; absent selects to the end of the file. */\n\treadonly endLine?: number;\n\t/** Most UTF-8 bytes of selected text to return; selection stops at the last whole line that fits. */\n\treadonly maxBytes: number;\n}\n\nexport interface LineScan {\n\t/**\n\t * The selected whole lines that fit `maxBytes`, joined with `\\n`. Invalid\n\t * UTF-8 becomes U+FFFD; how many per bad sequence depends on the decoder of\n\t * the backend's transport.\n\t */\n\treadonly text: string;\n\t/** Lines in {@link text}. */\n\treadonly lines: number;\n\t/** Lines in the whole file. */\n\treadonly totalLines: number;\n\t/** Bytes in the whole file, byte-order mark included. */\n\treadonly totalBytes: number;\n\t/**\n\t * Bytes of the first selected line, 0 when nothing is selected. Larger than\n\t * `maxBytes` exactly when that line alone does not fit, and `text` is empty.\n\t */\n\treadonly firstLineBytes: number;\n}\n\n/** A defect, not a file error: callers derive these from already-validated input. */\nexport const validate = (options: LineScanOptions): void => {\n\tconst { startLine, endLine, maxBytes } = options;\n\tif (!Number.isSafeInteger(startLine) || startLine < 0) throw new RangeError(`Invalid startLine: ${startLine}`);\n\tif (endLine !== undefined && (!Number.isSafeInteger(endLine) || endLine <= startLine))\n\t\tthrow new RangeError(`Invalid endLine: ${endLine}`);\n\tif (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) throw new RangeError(`Invalid maxBytes: ${maxBytes}`);\n};\n\nconst NEWLINE = 0x0a;\nconst BOM = [0xef, 0xbb, 0xbf] as const;\n\n/**\n * Computes a {@link LineScan} from a file's bytes fed in order, in memory\n * bounded by `maxBytes`. Feed at most the file size observed when the read\n * started, so a file that keeps growing cannot keep the scan going.\n */\nexport class LineScanner {\n\tprivate readonly start: number;\n\tprivate readonly end: number;\n\tprivate readonly maxBytes: number;\n\t// Only a mark at the very start of the file is dropped, and that happens on\n\t// the bytes; one starting a later line is text.\n\tprivate readonly decoder = new TextDecoder(\"utf-8\", { ignoreBOM: true });\n\n\t/** The first bytes, held until it is known whether they are a byte-order mark. */\n\tprivate head: Array<number> | undefined = [];\n\tprivate totalBytes = 0;\n\tprivate line = 0;\n\tprivate lineLength = 0;\n\tprivate lineOpen = false;\n\t/** The current line's bytes, kept only while it is selected and could still fit. */\n\tprivate pieces: Array<Uint8Array> = [];\n\tprivate selected: Array<Uint8Array> = [];\n\tprivate selectedBytes = 0;\n\tprivate firstLineBytes = 0;\n\tprivate full = false;\n\n\tconstructor(options: LineScanOptions) {\n\t\tvalidate(options);\n\t\tthis.start = options.startLine;\n\t\tthis.end = options.endLine ?? Number.POSITIVE_INFINITY;\n\t\tthis.maxBytes = options.maxBytes;\n\t}\n\n\tpush(chunk: Uint8Array): void {\n\t\tthis.totalBytes += chunk.length;\n\t\tif (this.head !== undefined) {\n\t\t\tconst take = Math.min(BOM.length - this.head.length, chunk.length);\n\t\t\tthis.head.push(...chunk.subarray(0, take));\n\t\t\tif (this.head.length < BOM.length) return;\n\t\t\tthis.releaseHead();\n\t\t\tchunk = chunk.subarray(take);\n\t\t}\n\t\tthis.scan(chunk);\n\t}\n\n\tfinish(): LineScan {\n\t\tif (this.head !== undefined) this.releaseHead();\n\t\tif (this.lineOpen) this.endLine();\n\t\tconst text = this.selected.map((line) => this.decoder.decode(line)).join(\"\\n\");\n\t\treturn {\n\t\t\ttext,\n\t\t\tlines: this.selected.length,\n\t\t\ttotalLines: this.line,\n\t\t\ttotalBytes: this.totalBytes,\n\t\t\tfirstLineBytes: this.firstLineBytes,\n\t\t};\n\t}\n\n\tprivate releaseHead(): void {\n\t\tconst head = Uint8Array.from(this.head ?? []);\n\t\tthis.head = undefined;\n\t\tconst bom = head.length === BOM.length && BOM.every((byte, index) => head[index] === byte);\n\t\tif (!bom) this.scan(head);\n\t}\n\n\tprivate scan(chunk: Uint8Array): void {\n\t\tlet from = 0;\n\t\twhile (from < chunk.length) {\n\t\t\tconst newline = chunk.indexOf(NEWLINE, from);\n\t\t\tconst to = newline === -1 ? chunk.length : newline;\n\t\t\tthis.append(chunk.subarray(from, to));\n\t\t\tif (newline === -1) return;\n\t\t\tthis.endLine();\n\t\t\tfrom = newline + 1;\n\t\t}\n\t}\n\n\tprivate isSelected(): boolean {\n\t\treturn !this.full && this.line >= this.start && this.line < this.end;\n\t}\n\n\tprivate append(bytes: Uint8Array): void {\n\t\tif (bytes.length === 0) {\n\t\t\tthis.lineOpen = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.lineOpen = true;\n\t\t// Past `maxBytes` the line cannot fit, so its bytes are only counted. Copied,\n\t\t// not sliced: a Node `Buffer` slice is a view the reader may overwrite.\n\t\tif (this.isSelected() && this.lineLength + bytes.length <= this.maxBytes) this.pieces.push(new Uint8Array(bytes));\n\t\tthis.lineLength += bytes.length;\n\t}\n\n\tprivate endLine(): void {\n\t\tif (this.isSelected()) {\n\t\t\tconst first = this.selected.length === 0;\n\t\t\tif (first) this.firstLineBytes = this.lineLength;\n\t\t\tconst added = first ? this.lineLength : this.lineLength + 1;\n\t\t\tif (this.selectedBytes + added > this.maxBytes) this.full = true;\n\t\t\telse {\n\t\t\t\tthis.selected.push(concat(this.pieces, this.lineLength));\n\t\t\t\tthis.selectedBytes += added;\n\t\t\t}\n\t\t}\n\t\tthis.pieces = [];\n\t\tthis.lineLength = 0;\n\t\tthis.lineOpen = false;\n\t\tthis.line++;\n\t}\n}\n\nconst concat = (pieces: ReadonlyArray<Uint8Array>, length: number): Uint8Array => {\n\tif (pieces.length === 1) return pieces[0]!;\n\tconst out = new Uint8Array(length);\n\tlet offset = 0;\n\tfor (const piece of pieces) {\n\t\tout.set(piece, offset);\n\t\toffset += piece.length;\n\t}\n\treturn out;\n};\n\n/**\n * {@link LineScanner} as a POSIX shell script, for backends that only expose a\n * process API. Run as `sh -c <script> _ <path> <startLine> <endLine|-1> <maxBytes>`.\n * The whole file is read inside the sandbox; only the window is printed, after a\n * header line `<lines> <totalLines> <totalBytes> <firstLineBytes>` and before a\n * closing `|` — see {@link parse}.\n * Exits 2 when the path does not exist.\n */\nexport const script = [\n\t'[ -e \"$1\" ] || exit 2',\n\t// Arithmetic expansion drops the padding some `wc` builds print.\n\t'size=$(($(wc -c < \"$1\"))) || exit 1',\n\t// `C` makes awk's `length` count bytes; `head -c` bounds a file that is still growing.\n\t'head -c \"$size\" -- \"$1\" | LC_ALL=C awk -v s=\"$2\" -v e=\"$3\" -v m=\"$4\" -v size=\"$size\" \\'',\n\t// A file that is only a byte-order mark has no lines; anything after one keeps its own.\n\t'NR == 1 && $0 == \"\\\\357\\\\273\\\\277\" && size == 3 { exit }',\n\t'NR == 1 && substr($0, 1, 3) == \"\\\\357\\\\273\\\\277\" { $0 = substr($0, 4) }',\n\t\"{ total = NR }\",\n\t\"NR > s && (e < 0 || NR <= e) && !full {\",\n\t\" len = length($0)\",\n\t\" added = lines == 0 ? len : len + 1\",\n\t\" if (lines == 0 && !seen) { seen = 1; first = len }\",\n\t\" if (bytes + added > m) { full = 1; next }\",\n\t' out = lines == 0 ? $0 : out \"\\\\n\" $0',\n\t\" bytes += added; lines++\",\n\t\"}\",\n\t// The trailing `|` survives a transport that trims trailing whitespace off stdout.\n\t// `%.0f`, not `%d`: some mawk builds clamp `%d` to a 32-bit integer.\n\t'END { printf \"%.0f %.0f %.0f %.0f\\\\n%s|\", lines, total, size, first, out }',\n\t\"'\",\n].join(\"\\n\");\n\n/** Arguments for {@link script} after the path. */\nexport const scriptArgs = (options: LineScanOptions): Array<string> => {\n\tvalidate(options);\n\treturn [String(options.startLine), String(options.endLine ?? -1), String(options.maxBytes)];\n};\n\n/** Read {@link script}'s output. */\nexport const parse = (stdout: string): LineScan => {\n\tconst body = stdout.trimEnd();\n\tconst newline = body.indexOf(\"\\n\");\n\tconst header = (newline === -1 ? \"\" : body.slice(0, newline)).trim().split(/\\s+/).map(Number);\n\tconst [lines, totalLines, totalBytes, firstLineBytes] = header;\n\tif (!body.endsWith(\"|\") || header.length !== 4 || header.some((value) => !Number.isSafeInteger(value)))\n\t\tthrow new Error(`Unexpected scanLines output: ${stdout.slice(0, 200)}`);\n\treturn {\n\t\ttext: body.slice(newline + 1, -1),\n\t\tlines: lines!,\n\t\ttotalLines: totalLines!,\n\t\ttotalBytes: totalBytes!,\n\t\tfirstLineBytes: firstLineBytes!,\n\t};\n};\n\nexport interface ShellRun {\n\treadonly exitCode: number;\n\treadonly stdout: string;\n\treadonly stderr?: string;\n}\n\n/**\n * `Provider.scanLines` for a backend that runs an argument vector and collects\n * its output: runs {@link script} in the sandbox and reads the result. A missing\n * path rejects with `ENOENT`, the shape `isNotFoundError` recognises.\n */\nexport const viaShell =\n\t(run: (argv: ReadonlyArray<string>) => Promise<ShellRun>) =>\n\t// oxlint-disable-next-line effecttsgo/async-function -- the Provider contract is Promise-based\n\tasync (path: string, options: LineScanOptions): Promise<LineScan> => {\n\t\tconst result = await run([\"sh\", \"-c\", script, \"_\", path, ...scriptArgs(options)]);\n\t\tif (result.exitCode === 2)\n\t\t\tthrow Object.assign(new Error(`ENOENT: no such file or directory, scanLines '${path}'`), { code: \"ENOENT\" });\n\t\tif (result.exitCode !== 0)\n\t\t\tthrow new Error(`scanLines failed (exit ${result.exitCode}): ${(result.stderr ?? result.stdout).trim()}`);\n\t\treturn parse(result.stdout);\n\t};\n","import { Context, Effect, Schema } from \"effect\";\nimport { posix } from \"../posix.ts\";\nimport { type LineScan, type LineScanOptions, type ShellRun, validate as validateScan } from \"./scan.ts\";\n\nexport type { LineScan, LineScanOptions } from \"./scan.ts\";\n/** The shared line-scan rules: `LineScanner` for byte streams, `script` for shell-only backends. */\nexport * as Scan from \"./scan.ts\";\n\n/**\n * The runtime filesystem contract, independent of any backend.\n *\n * Two surfaces, deliberately:\n * - {@link Provider} is what a backend implements — plain promises that reject,\n * matching every SDK we wrap.\n * - {@link Interface} is what the harness consumes — Effect with a typed error\n * channel and tracing spans. {@link fromProvider} bridges the two exactly\n * once, so no consumer ever writes `Effect.tryPromise` against a filesystem.\n *\n * Implementations:\n * - Local:\n * implement it over a VFS (`./local`);\n * local filesystem use OS primitives; hence have broader filesytem capabilities.\n *\n * - Remote:\n * implement it over a provider (`./remote`).\n * remote filesytems depends on the interface provided by the remote provider; hence can have limited filesytem capabilities.\n *\n * `isFile`/`isDirectory` are required booleans; size, mtime, and isSymbolicLink are omitted when the\n * backend cannot report them — never fabricated.\n *\n * **Paths are POSIX, and the harness is Unix-only (for now!).** Every path uses `/`\n * separators on both the host and inside a sandbox — Windows is not supported,\n * so no translation layer exists. Consumers must use the shared Effect POSIX\n * path implementation, never the platform default, or a host running the harness would\n * impose its own flavour on a remote sandbox's paths. Relative paths resolve\n * against the backend's configured `cwd`.\n */\n\nexport class OperationUnsupportedError extends Schema.TaggedError<OperationUnsupportedError>()(\n\t\"OperationUnsupportedError\",\n\t{\n\t\toperation: Schema.String,\n\t\tmessage: Schema.String,\n\t},\n) {}\n\n/** A backend operation failed. `cause` carries the provider's own rejection. */\nexport class FileSystemError extends Schema.TaggedError<FileSystemError>()(\"SandboxFileSystemError\", {\n\tmethod: Schema.String,\n\tpath: Schema.String,\n\tcause: Schema.optional(Schema.Defect()),\n}) {}\n\nexport interface FileStat {\n\treadonly isFile: boolean;\n\treadonly isDirectory: boolean;\n\treadonly isSymbolicLink?: boolean;\n\treadonly size?: number;\n\treadonly mtime?: Date;\n}\n\nexport interface RmOptions {\n\treadonly recursive?: boolean;\n\treadonly force?: boolean;\n}\n\n/** Whether a provider failure means the path itself is definitively absent. */\nexport const isNotFoundError = (cause: unknown) => {\n\tconst code = (cause as NodeJS.ErrnoException | undefined)?.code;\n\treturn code === \"ENOENT\" || code === \"ENOTDIR\";\n};\n\n/**\n * Shell forms of `realpath` for backends that only expose a process API. Run as\n * `sh -c <script> _ <path>`, trying each in turn. `realpath -e` (coreutils)\n * resolves every component, a symlinked file included, and fails on a missing\n * path. Where it is absent, `pwd -P` is the portable primitive: directories\n * resolve directly, anything else resolves its parent and keeps the final name\n * as given — so a symlinked *file* stays unresolved there.\n */\nexport const realpathScripts = [\n\t'realpath -e -- \"$1\"',\n\t'cd -- \"$1\" && pwd -P',\n\t'cd -- \"$(dirname -- \"$1\")\" && printf \\'%s/%s\\' \"$(pwd -P)\" \"$(basename -- \"$1\")\"',\n] as const;\n\n/**\n * Shell form of `readBytes` for backends that only expose a process API. Run as\n * `sh -c <script> _ <path> <offset + 1> <length>`; prints the bytes as base64,\n * so binary content survives a transport that decodes stdout as text. Exits 2\n * when the path does not exist, 3 when it cannot be opened.\n */\nexport const readBytesScript = [\n\t'[ -e \"$1\" ] || exit 2',\n\t// A pipeline exits with its last command's status, and `head` closing early is\n\t// normal, so `tail` cannot report a file it cannot open; opening it first does.\n\t'{ : < \"$1\"; } 2>/dev/null || exit 3',\n\t'tail -c +\"$2\" -- \"$1\" | head -c \"$3\" | base64',\n].join(\"\\n\");\n\n/**\n * `Provider.readBytes` for a backend that runs an argument vector and collects\n * its output. A missing path rejects with `ENOENT`, the shape `isNotFoundError` recognises.\n */\nexport const readBytesViaShell =\n\t(run: (argv: ReadonlyArray<string>) => Promise<ShellRun>) =>\n\t// oxlint-disable-next-line effecttsgo/async-function -- the Provider contract is Promise-based\n\tasync (path: string, offset: number, length: number): Promise<Uint8Array> => {\n\t\tconst result = await run([\"sh\", \"-c\", readBytesScript, \"_\", path, String(offset + 1), String(length)]);\n\t\tif (result.exitCode === 2)\n\t\t\tthrow Object.assign(new Error(`ENOENT: no such file or directory, readBytes '${path}'`), { code: \"ENOENT\" });\n\t\tif (result.exitCode === 3) throw new Error(`readBytes: cannot open '${path}'`);\n\t\tif (result.exitCode !== 0)\n\t\t\tthrow new Error(`readBytes failed (exit ${result.exitCode}): ${(result.stderr ?? result.stdout).trim()}`);\n\t\treturn new Uint8Array(Buffer.from(result.stdout.replace(/\\s/g, \"\"), \"base64\"));\n\t};\n\n/**\n * The backend-facing contract. Backends author plain promises and let them\n * reject; {@link fromProvider} turns rejections into typed failures.\n */\nexport interface Provider {\n\treadonly readFile: (path: string) => Promise<string>;\n\treadonly readFileBuffer: (path: string) => Promise<Uint8Array>;\n\t/** Up to `length` bytes from `offset`; fewer at the end of the file. */\n\treadonly readBytes: (path: string, offset: number, length: number) => Promise<Uint8Array>;\n\t/**\n\t * Write the file. Parents may be missing — do not create them here;\n\t * {@link fromProvider} owns that guarantee for every backend.\n\t */\n\treadonly writeFile: (path: string, content: string | Uint8Array) => Promise<void>;\n\treadonly stat: (path: string) => Promise<FileStat>;\n\treadonly readdir: (path: string) => Promise<string[]>;\n\treadonly exists: (path: string) => Promise<boolean>;\n\treadonly mkdir: (path: string, options?: { recursive?: boolean }) => Promise<void>;\n\treadonly rm: (path: string, options?: RmOptions) => Promise<void>;\n\t/** Canonical absolute path with symlinks resolved; rejects when the path does not exist. */\n\treadonly realpath: (path: string) => Promise<string>;\n\t/**\n\t * A window of the file's lines, by the rules in `Scan`. Bounded: never\n\t * returns, or holds, more than the window. A remote backend runs the scan\n\t * inside the sandbox (`Scan.script`) so only the window crosses the network.\n\t */\n\treadonly scanLines: (path: string, options: LineScanOptions) => Promise<LineScan>;\n\t/**\n\t * Metadata for the directory entry itself rather than a symlink's target.\n\t * Optional: a backend whose `stat` has mixed symlink semantics implements it\n\t * so symlink identity is asked for explicitly, never inferred.\n\t */\n\treadonly lstat?: (path: string) => Promise<FileStat>;\n}\n\n/**\n * The consumer-facing contract. `exists` distinguishes \"absent\" from \"could not\n * tell\": a backend failure is a typed failure, not `false`, so a caller acting\n * on absence never acts on a network blip. Use `SandboxFs.existsOrFalse` where\n * a best-effort answer really is wanted.\n */\nexport interface Interface {\n\treadonly readFile: (path: string) => Effect.Effect<string, FileSystemError>;\n\treadonly readFileBuffer: (path: string) => Effect.Effect<Uint8Array, FileSystemError>;\n\t/** Up to `length` bytes from `offset`; fewer at the end of the file. */\n\treadonly readBytes: (path: string, offset: number, length: number) => Effect.Effect<Uint8Array, FileSystemError>;\n\t/** Creates missing parent directories, on every backend. */\n\treadonly writeFile: (path: string, content: string | Uint8Array) => Effect.Effect<void, FileSystemError>;\n\treadonly stat: (path: string) => Effect.Effect<FileStat, FileSystemError>;\n\treadonly readdir: (path: string) => Effect.Effect<string[], FileSystemError>;\n\treadonly exists: (path: string) => Effect.Effect<boolean, FileSystemError>;\n\treadonly mkdir: (path: string, options?: { recursive?: boolean }) => Effect.Effect<void, FileSystemError>;\n\treadonly rm: (path: string, options?: RmOptions) => Effect.Effect<void, FileSystemError | OperationUnsupportedError>;\n\t/** Canonical absolute path with symlinks resolved; fails when the path does not exist. */\n\treadonly realpath: (path: string) => Effect.Effect<string, FileSystemError>;\n\t/** A bounded window of the file's lines; see `Scan`. Invalid options are a defect. */\n\treadonly scanLines: (path: string, options: LineScanOptions) => Effect.Effect<LineScan, FileSystemError>;\n\t// `lstat` is present only when the backend supports it; check before calling.\n\treadonly lstat?: (path: string) => Effect.Effect<FileStat, FileSystemError>;\n}\n\n/** The runtime filesystem service — the live {@link Interface} for the active sandbox. */\nexport class Service extends Context.Service<Service, Interface>()(\"@codeworksh/plugin/sandbox/filesystem/Service\") {}\n\n/**\n * Reject `rm` options a provider does not implement, before any mutation. Only\n * `recursive` and `force` are part of the contract; anything else is refused\n * loudly rather than silently ignored.\n */\nexport const validateRmOptions = (\n\toptions: RmOptions | undefined,\n\toperation = \"rm\",\n): Effect.Effect<void, OperationUnsupportedError> =>\n\tEffect.suspend(() => {\n\t\tfor (const option of Object.keys((options ?? {}) as Record<string, unknown>)) {\n\t\t\tif (option === \"recursive\" || option === \"force\") continue;\n\t\t\treturn Effect.fail(new OperationUnsupportedError({ operation, message: `Unsupported rm option: ${option}` }));\n\t\t}\n\t\treturn Effect.void;\n\t});\n\n/**\n * Lift a {@link Provider} into the runtime {@link Interface}: one place that\n * converts rejections into {@link FileSystemError}, validates `rm` options,\n * creates missing parents on write, and names a tracing span per operation.\n */\nexport const fromProvider = (provider: Provider): Interface => {\n\tconst attempt = <A>(method: string, path: string, run: () => Promise<A>) =>\n\t\tEffect.tryPromise({ try: run, catch: (cause) => new FileSystemError({ method, path, cause }) });\n\n\t// The parent-creation guarantee, installed once for every backend instead of\n\t// re-implemented per provider: anything that reaches `Interface` reaches it\n\t// through here, so a backend cannot forget it.\n\t//\n\t// Lazy by design — try the write first, so the happy path stays a single call\n\t// and no remote backend pays a round-trip per write. A failure is usually a\n\t// missing parent, so create it and retry once. The mkdir's own error is\n\t// dropped on purpose: when the write failed for some other reason (EACCES,\n\t// EROFS, a dropped connection), the retry reproduces it, and *that* is the\n\t// failure the caller must see rather than a misleading mkdir error standing\n\t// in for it.\n\tconst writeCreatingParents = (path: string, content: string | Uint8Array) => {\n\t\tconst write = attempt(\"writeFile\", path, () => provider.writeFile(path, content));\n\t\tconst parent = posix.dirname(path);\n\t\treturn write.pipe(\n\t\t\tEffect.catch(() =>\n\t\t\t\tattempt(\"mkdir\", parent, () => provider.mkdir(parent, { recursive: true })).pipe(\n\t\t\t\t\tEffect.ignore,\n\t\t\t\t\tEffect.andThen(write),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t};\n\n\treturn {\n\t\treadFile: Effect.fn(\"SandboxFileSystem.readFile\")((path: string) =>\n\t\t\tattempt(\"readFile\", path, () => provider.readFile(path)),\n\t\t),\n\t\treadFileBuffer: Effect.fn(\"SandboxFileSystem.readFileBuffer\")((path: string) =>\n\t\t\tattempt(\"readFileBuffer\", path, () => provider.readFileBuffer(path)),\n\t\t),\n\t\treadBytes: Effect.fn(\"SandboxFileSystem.readBytes\")((path: string, offset: number, length: number) =>\n\t\t\tattempt(\"readBytes\", path, () => provider.readBytes(path, offset, length)),\n\t\t),\n\t\twriteFile: Effect.fn(\"SandboxFileSystem.writeFile\")(writeCreatingParents),\n\t\tstat: Effect.fn(\"SandboxFileSystem.stat\")((path: string) => attempt(\"stat\", path, () => provider.stat(path))),\n\t\t// carried through only when the backend actually implements it\n\t\t...(provider.lstat === undefined\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tlstat: Effect.fn(\"SandboxFileSystem.lstat\")((path: string) =>\n\t\t\t\t\t\tattempt(\"lstat\", path, () => provider.lstat!(path)),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\treaddir: Effect.fn(\"SandboxFileSystem.readdir\")((path: string) =>\n\t\t\tattempt(\"readdir\", path, () => provider.readdir(path)),\n\t\t),\n\t\t// A backend that cannot answer fails; it does not report \"absent\". A\n\t\t// caller acting on absence — deleting a record, say — must not be told\n\t\t// the path is gone because a token expired or a request timed out.\n\t\texists: Effect.fn(\"SandboxFileSystem.exists\")((path: string) =>\n\t\t\tattempt(\"exists\", path, () => provider.exists(path)),\n\t\t),\n\t\tmkdir: Effect.fn(\"SandboxFileSystem.mkdir\")((path: string, options?: { recursive?: boolean }) =>\n\t\t\tattempt(\"mkdir\", path, () => provider.mkdir(path, options)),\n\t\t),\n\t\trm: Effect.fn(\"SandboxFileSystem.rm\")((path: string, options?: RmOptions) =>\n\t\t\tvalidateRmOptions(options).pipe(Effect.andThen(attempt(\"rm\", path, () => provider.rm(path, options)))),\n\t\t),\n\t\trealpath: Effect.fn(\"SandboxFileSystem.realpath\")((path: string) =>\n\t\t\tattempt(\"realpath\", path, () => provider.realpath(path)),\n\t\t),\n\t\tscanLines: Effect.fn(\"SandboxFileSystem.scanLines\")((path: string, options: LineScanOptions) =>\n\t\t\tEffect.sync(() => validateScan(options)).pipe(\n\t\t\t\tEffect.andThen(attempt(\"scanLines\", path, () => provider.scanLines(path, options))),\n\t\t\t),\n\t\t),\n\t};\n};\n\n/**\n * Bind a cwd-neutral filesystem to one mount's working directory.\n *\n * The counterpart of `Shell.withCwd`, and the reason relative paths mean the\n * same thing to both: a shared transport stays rooted at the namespace root, so\n * resolution happens here, per mount, rather than inside a VFS whose `chdir` is\n * global state two mounts would fight over.\n */\nexport const withCwd = (fs: Interface, cwd: string): Interface => {\n\tconst at = (path: string) => posix.resolve(cwd, path);\n\treturn {\n\t\treadFile: (path) => fs.readFile(at(path)),\n\t\treadFileBuffer: (path) => fs.readFileBuffer(at(path)),\n\t\treadBytes: (path, offset, length) => fs.readBytes(at(path), offset, length),\n\t\twriteFile: (path, content) => fs.writeFile(at(path), content),\n\t\tstat: (path) => fs.stat(at(path)),\n\t\treaddir: (path) => fs.readdir(at(path)),\n\t\texists: (path) => fs.exists(at(path)),\n\t\tmkdir: (path, options) => fs.mkdir(at(path), options),\n\t\trm: (path, options) => fs.rm(at(path), options),\n\t\trealpath: (path) => fs.realpath(at(path)),\n\t\tscanLines: (path, options) => fs.scanLines(at(path), options),\n\t\t// carried through only when the backend implements it, so a caller can\n\t\t// still detect absence by checking the property\n\t\t...(fs.lstat === undefined ? {} : { lstat: (path: string) => fs.lstat!(at(path)) }),\n\t};\n};\n\nexport * as SandboxFileSystem from \"./filesystem.ts\";\n"],"mappings":";;;;;;;;;;;;;AA4CA,MAAa,YAAY,YAAmC;CAC3D,MAAM,EAAE,WAAW,SAAS,aAAa;CACzC,IAAI,CAAC,OAAO,cAAc,SAAS,KAAK,YAAY,GAAG,MAAM,IAAI,WAAW,sBAAsB,WAAW;CAC7G,IAAI,YAAY,KAAA,MAAc,CAAC,OAAO,cAAc,OAAO,KAAK,WAAW,YAC1E,MAAM,IAAI,WAAW,oBAAoB,SAAS;CACnD,IAAI,CAAC,OAAO,cAAc,QAAQ,KAAK,YAAY,GAAG,MAAM,IAAI,WAAW,qBAAqB,UAAU;AAC3G;AAEA,MAAM,UAAU;AAChB,MAAM,MAAM;CAAC;CAAM;CAAM;AAAI;;;;;;AAO7B,IAAa,cAAb,MAAyB;CACxB;CACA;CACA;CAGA,UAA2B,IAAI,YAAY,SAAS,EAAE,WAAW,KAAK,CAAC;;CAGvE,OAA0C,CAAC;CAC3C,aAAqB;CACrB,OAAe;CACf,aAAqB;CACrB,WAAmB;;CAEnB,SAAoC,CAAC;CACrC,WAAsC,CAAC;CACvC,gBAAwB;CACxB,iBAAyB;CACzB,OAAe;CAEf,YAAY,SAA0B;EACrC,SAAS,OAAO;EAChB,KAAK,QAAQ,QAAQ;EACrB,KAAK,MAAM,QAAQ,WAAW,OAAO;EACrC,KAAK,WAAW,QAAQ;CACzB;CAEA,KAAK,OAAyB;EAC7B,KAAK,cAAc,MAAM;EACzB,IAAI,KAAK,SAAS,KAAA,GAAW;GAC5B,MAAM,OAAO,KAAK,IAAI,IAAI,SAAS,KAAK,KAAK,QAAQ,MAAM,MAAM;GACjE,KAAK,KAAK,KAAK,GAAG,MAAM,SAAS,GAAG,IAAI,CAAC;GACzC,IAAI,KAAK,KAAK,SAAS,IAAI,QAAQ;GACnC,KAAK,YAAY;GACjB,QAAQ,MAAM,SAAS,IAAI;EAC5B;EACA,KAAK,KAAK,KAAK;CAChB;CAEA,SAAmB;EAClB,IAAI,KAAK,SAAS,KAAA,GAAW,KAAK,YAAY;EAC9C,IAAI,KAAK,UAAU,KAAK,QAAQ;EAEhC,OAAO;GACN,MAFY,KAAK,SAAS,KAAK,SAAS,KAAK,QAAQ,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,IAErE;GACH,OAAO,KAAK,SAAS;GACrB,YAAY,KAAK;GACjB,YAAY,KAAK;GACjB,gBAAgB,KAAK;EACtB;CACD;CAEA,cAA4B;EAC3B,MAAM,OAAO,WAAW,KAAK,KAAK,QAAQ,CAAC,CAAC;EAC5C,KAAK,OAAO,KAAA;EAEZ,IAAI,EADQ,KAAK,WAAW,IAAI,UAAU,IAAI,OAAO,MAAM,UAAU,KAAK,WAAW,IAAI,IAC/E,KAAK,KAAK,IAAI;CACzB;CAEA,KAAa,OAAyB;EACrC,IAAI,OAAO;EACX,OAAO,OAAO,MAAM,QAAQ;GAC3B,MAAM,UAAU,MAAM,QAAQ,SAAS,IAAI;GAC3C,MAAM,KAAK,YAAY,KAAK,MAAM,SAAS;GAC3C,KAAK,OAAO,MAAM,SAAS,MAAM,EAAE,CAAC;GACpC,IAAI,YAAY,IAAI;GACpB,KAAK,QAAQ;GACb,OAAO,UAAU;EAClB;CACD;CAEA,aAA8B;EAC7B,OAAO,CAAC,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,KAAK;CAClE;CAEA,OAAe,OAAyB;EACvC,IAAI,MAAM,WAAW,GAAG;GACvB,KAAK,WAAW;GAChB;EACD;EACA,KAAK,WAAW;EAGhB,IAAI,KAAK,WAAW,KAAK,KAAK,aAAa,MAAM,UAAU,KAAK,UAAU,KAAK,OAAO,KAAK,IAAI,WAAW,KAAK,CAAC;EAChH,KAAK,cAAc,MAAM;CAC1B;CAEA,UAAwB;EACvB,IAAI,KAAK,WAAW,GAAG;GACtB,MAAM,QAAQ,KAAK,SAAS,WAAW;GACvC,IAAI,OAAO,KAAK,iBAAiB,KAAK;GACtC,MAAM,QAAQ,QAAQ,KAAK,aAAa,KAAK,aAAa;GAC1D,IAAI,KAAK,gBAAgB,QAAQ,KAAK,UAAU,KAAK,OAAO;QACvD;IACJ,KAAK,SAAS,KAAK,OAAO,KAAK,QAAQ,KAAK,UAAU,CAAC;IACvD,KAAK,iBAAiB;GACvB;EACD;EACA,KAAK,SAAS,CAAC;EACf,KAAK,aAAa;EAClB,KAAK,WAAW;EAChB,KAAK;CACN;AACD;AAEA,MAAM,UAAU,QAAmC,WAA+B;CACjF,IAAI,OAAO,WAAW,GAAG,OAAO,OAAO;CACvC,MAAM,MAAM,IAAI,WAAW,MAAM;CACjC,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,QAAQ;EAC3B,IAAI,IAAI,OAAO,MAAM;EACrB,UAAU,MAAM;CACjB;CACA,OAAO;AACR;;;;;;;;;AAUA,MAAa,SAAS;CACrB;CAEA;CAEA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;AACD,CAAC,CAAC,KAAK,IAAI;;AAGX,MAAa,cAAc,YAA4C;CACtE,SAAS,OAAO;CAChB,OAAO;EAAC,OAAO,QAAQ,SAAS;EAAG,OAAO,QAAQ,WAAW,EAAE;EAAG,OAAO,QAAQ,QAAQ;CAAC;AAC3F;;AAGA,MAAa,SAAS,WAA6B;CAClD,MAAM,OAAO,OAAO,QAAQ;CAC5B,MAAM,UAAU,KAAK,QAAQ,IAAI;CACjC,MAAM,UAAU,YAAY,KAAK,KAAK,KAAK,MAAM,GAAG,OAAO,EAAA,CAAG,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,MAAM;CAC5F,MAAM,CAAC,OAAO,YAAY,YAAY,kBAAkB;CACxD,IAAI,CAAC,KAAK,SAAS,GAAG,KAAK,OAAO,WAAW,KAAK,OAAO,MAAM,UAAU,CAAC,OAAO,cAAc,KAAK,CAAC,GACpG,MAAM,IAAI,MAAM,gCAAgC,OAAO,MAAM,GAAG,GAAG,GAAG;CACvE,OAAO;EACN,MAAM,KAAK,MAAM,UAAU,GAAG,EAAE;EACzB;EACK;EACA;EACI;CACjB;AACD;;;;;;AAaA,MAAa,YACX,QAED,OAAO,MAAc,YAAgD;CACpE,MAAM,SAAS,MAAM,IAAI;EAAC;EAAM;EAAM;EAAQ;EAAK;EAAM,GAAG,WAAW,OAAO;CAAC,CAAC;CAChF,IAAI,OAAO,aAAa,GACvB,MAAM,OAAO,uBAAO,IAAI,MAAM,iDAAiD,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;CAC5G,IAAI,OAAO,aAAa,GACvB,MAAM,IAAI,MAAM,0BAA0B,OAAO,SAAS,MAAM,OAAO,UAAU,OAAO,OAAA,CAAQ,KAAK,GAAG;CACzG,OAAO,MAAM,OAAO,MAAM;AAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvND,IAAa,4BAAb,cAA+C,OAAO,YAAuC,CAAC,CAC7F,6BACA;CACC,WAAW,OAAO;CAClB,SAAS,OAAO;AACjB,CACD,CAAC,CAAC,CAAC;;AAGH,IAAa,kBAAb,cAAqC,OAAO,YAA6B,CAAC,CAAC,0BAA0B;CACpG,QAAQ,OAAO;CACf,MAAM,OAAO;CACb,OAAO,OAAO,SAAS,OAAO,OAAO,CAAC;AACvC,CAAC,CAAC,CAAC,CAAC;;AAgBJ,MAAa,mBAAmB,UAAmB;CAClD,MAAM,OAAQ,OAA6C;CAC3D,OAAO,SAAS,YAAY,SAAS;AACtC;;;;;;;;;AAUA,MAAa,kBAAkB;CAC9B;CACA;CACA;AACD;;;;;;;AAQA,MAAa,kBAAkB;CAC9B;CAGA;CACA;AACD,CAAC,CAAC,KAAK,IAAI;;;;;AAMX,MAAa,qBACX,QAED,OAAO,MAAc,QAAgB,WAAwC;CAC5E,MAAM,SAAS,MAAM,IAAI;EAAC;EAAM;EAAM;EAAiB;EAAK;EAAM,OAAO,SAAS,CAAC;EAAG,OAAO,MAAM;CAAC,CAAC;CACrG,IAAI,OAAO,aAAa,GACvB,MAAM,OAAO,uBAAO,IAAI,MAAM,iDAAiD,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;CAC5G,IAAI,OAAO,aAAa,GAAG,MAAM,IAAI,MAAM,2BAA2B,KAAK,EAAE;CAC7E,IAAI,OAAO,aAAa,GACvB,MAAM,IAAI,MAAM,0BAA0B,OAAO,SAAS,MAAM,OAAO,UAAU,OAAO,OAAA,CAAQ,KAAK,GAAG;CACzG,OAAO,IAAI,WAAW,OAAO,KAAK,OAAO,OAAO,QAAQ,OAAO,EAAE,GAAG,QAAQ,CAAC;AAC9E;;AAgED,IAAa,UAAb,cAA6B,QAAQ,QAA4B,CAAC,CAAC,+CAA+C,CAAC,CAAC,CAAC;;;;;;AAOrH,MAAa,qBACZ,SACA,YAAY,SAEZ,OAAO,cAAc;CACpB,KAAK,MAAM,UAAU,OAAO,KAAM,WAAW,CAAC,CAA6B,GAAG;EAC7E,IAAI,WAAW,eAAe,WAAW,SAAS;EAClD,OAAO,OAAO,KAAK,IAAI,0BAA0B;GAAE;GAAW,SAAS,0BAA0B;EAAS,CAAC,CAAC;CAC7G;CACA,OAAO,OAAO;AACf,CAAC;;;;;;AAOF,MAAa,gBAAgB,aAAkC;CAC9D,MAAM,WAAc,QAAgB,MAAc,QACjD,OAAO,WAAW;EAAE,KAAK;EAAK,QAAQ,UAAU,IAAI,gBAAgB;GAAE;GAAQ;GAAM;EAAM,CAAC;CAAE,CAAC;CAa/F,MAAM,wBAAwB,MAAc,YAAiC;EAC5E,MAAM,QAAQ,QAAQ,aAAa,YAAY,SAAS,UAAU,MAAM,OAAO,CAAC;EAChF,MAAM,SAAS,MAAM,QAAQ,IAAI;EACjC,OAAO,MAAM,KACZ,OAAO,YACN,QAAQ,SAAS,cAAc,SAAS,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,KAC3E,OAAO,QACP,OAAO,QAAQ,KAAK,CACrB,CACD,CACD;CACD;CAEA,OAAO;EACN,UAAU,OAAO,GAAG,4BAA4B,CAAC,EAAE,SAClD,QAAQ,YAAY,YAAY,SAAS,SAAS,IAAI,CAAC,CACxD;EACA,gBAAgB,OAAO,GAAG,kCAAkC,CAAC,EAAE,SAC9D,QAAQ,kBAAkB,YAAY,SAAS,eAAe,IAAI,CAAC,CACpE;EACA,WAAW,OAAO,GAAG,6BAA6B,CAAC,EAAE,MAAc,QAAgB,WAClF,QAAQ,aAAa,YAAY,SAAS,UAAU,MAAM,QAAQ,MAAM,CAAC,CAC1E;EACA,WAAW,OAAO,GAAG,6BAA6B,CAAC,CAAC,oBAAoB;EACxE,MAAM,OAAO,GAAG,wBAAwB,CAAC,EAAE,SAAiB,QAAQ,QAAQ,YAAY,SAAS,KAAK,IAAI,CAAC,CAAC;EAE5G,GAAI,SAAS,UAAU,KAAA,IACpB,CAAC,IACD,EACA,OAAO,OAAO,GAAG,yBAAyB,CAAC,EAAE,SAC5C,QAAQ,SAAS,YAAY,SAAS,MAAO,IAAI,CAAC,CACnD,EACD;EACF,SAAS,OAAO,GAAG,2BAA2B,CAAC,EAAE,SAChD,QAAQ,WAAW,YAAY,SAAS,QAAQ,IAAI,CAAC,CACtD;EAIA,QAAQ,OAAO,GAAG,0BAA0B,CAAC,EAAE,SAC9C,QAAQ,UAAU,YAAY,SAAS,OAAO,IAAI,CAAC,CACpD;EACA,OAAO,OAAO,GAAG,yBAAyB,CAAC,EAAE,MAAc,YAC1D,QAAQ,SAAS,YAAY,SAAS,MAAM,MAAM,OAAO,CAAC,CAC3D;EACA,IAAI,OAAO,GAAG,sBAAsB,CAAC,EAAE,MAAc,YACpD,kBAAkB,OAAO,CAAC,CAAC,KAAK,OAAO,QAAQ,QAAQ,MAAM,YAAY,SAAS,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CACtG;EACA,UAAU,OAAO,GAAG,4BAA4B,CAAC,EAAE,SAClD,QAAQ,YAAY,YAAY,SAAS,SAAS,IAAI,CAAC,CACxD;EACA,WAAW,OAAO,GAAG,6BAA6B,CAAC,EAAE,MAAc,YAClE,OAAO,WAAWA,SAAa,OAAO,CAAC,CAAC,CAAC,KACxC,OAAO,QAAQ,QAAQ,aAAa,YAAY,SAAS,UAAU,MAAM,OAAO,CAAC,CAAC,CACnF,CACD;CACD;AACD;;;;;;;;;AAUA,MAAa,WAAW,IAAe,QAA2B;CACjE,MAAM,MAAM,SAAiB,MAAM,QAAQ,KAAK,IAAI;CACpD,OAAO;EACN,WAAW,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC;EACxC,iBAAiB,SAAS,GAAG,eAAe,GAAG,IAAI,CAAC;EACpD,YAAY,MAAM,QAAQ,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,QAAQ,MAAM;EAC1E,YAAY,MAAM,YAAY,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO;EAC5D,OAAO,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;EAChC,UAAU,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC;EACtC,SAAS,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC;EACpC,QAAQ,MAAM,YAAY,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO;EACpD,KAAK,MAAM,YAAY,GAAG,GAAG,GAAG,IAAI,GAAG,OAAO;EAC9C,WAAW,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC;EACxC,YAAY,MAAM,YAAY,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO;EAG5D,GAAI,GAAG,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,SAAiB,GAAG,MAAO,GAAG,IAAI,CAAC,EAAE;CAClF;AACD"}
|
|
@@ -100,7 +100,7 @@ interface ShellRun {
|
|
|
100
100
|
*/
|
|
101
101
|
declare const viaShell: (run: (argv: ReadonlyArray<string>) => Promise<ShellRun>) => (path: string, options: LineScanOptions) => Promise<LineScan>;
|
|
102
102
|
declare namespace filesystem_d_exports {
|
|
103
|
-
export { FileStat, FileSystemError, Interface, LineScan, LineScanOptions, OperationUnsupportedError, Provider, RmOptions, filesystem_d_exports as SandboxFileSystem, scan_d_exports as Scan, Service, fromProvider, isNotFoundError, realpathScripts, validateRmOptions, withCwd };
|
|
103
|
+
export { FileStat, FileSystemError, Interface, LineScan, LineScanOptions, OperationUnsupportedError, Provider, RmOptions, filesystem_d_exports as SandboxFileSystem, scan_d_exports as Scan, Service, fromProvider, isNotFoundError, readBytesScript, readBytesViaShell, realpathScripts, validateRmOptions, withCwd };
|
|
104
104
|
}
|
|
105
105
|
declare const OperationUnsupportedError_base: Schema.Class<OperationUnsupportedError, Schema.TaggedStruct<"OperationUnsupportedError", {
|
|
106
106
|
readonly operation: Schema.String;
|
|
@@ -165,6 +165,18 @@ declare const isNotFoundError: (cause: unknown) => boolean;
|
|
|
165
165
|
* as given — so a symlinked *file* stays unresolved there.
|
|
166
166
|
*/
|
|
167
167
|
declare const realpathScripts: readonly ['realpath -e -- "$1"', 'cd -- "$1" && pwd -P', 'cd -- "$(dirname -- "$1")" && printf \'%s/%s\' "$(pwd -P)" "$(basename -- "$1")"'];
|
|
168
|
+
/**
|
|
169
|
+
* Shell form of `readBytes` for backends that only expose a process API. Run as
|
|
170
|
+
* `sh -c <script> _ <path> <offset + 1> <length>`; prints the bytes as base64,
|
|
171
|
+
* so binary content survives a transport that decodes stdout as text. Exits 2
|
|
172
|
+
* when the path does not exist, 3 when it cannot be opened.
|
|
173
|
+
*/
|
|
174
|
+
declare const readBytesScript: string;
|
|
175
|
+
/**
|
|
176
|
+
* `Provider.readBytes` for a backend that runs an argument vector and collects
|
|
177
|
+
* its output. A missing path rejects with `ENOENT`, the shape `isNotFoundError` recognises.
|
|
178
|
+
*/
|
|
179
|
+
declare const readBytesViaShell: (run: (argv: ReadonlyArray<string>) => Promise<ShellRun>) => (path: string, offset: number, length: number) => Promise<Uint8Array>;
|
|
168
180
|
/**
|
|
169
181
|
* The backend-facing contract. Backends author plain promises and let them
|
|
170
182
|
* reject; {@link fromProvider} turns rejections into typed failures.
|
|
@@ -172,6 +184,8 @@ declare const realpathScripts: readonly ['realpath -e -- "$1"', 'cd -- "$1" && p
|
|
|
172
184
|
interface Provider {
|
|
173
185
|
readonly readFile: (path: string) => Promise<string>;
|
|
174
186
|
readonly readFileBuffer: (path: string) => Promise<Uint8Array>;
|
|
187
|
+
/** Up to `length` bytes from `offset`; fewer at the end of the file. */
|
|
188
|
+
readonly readBytes: (path: string, offset: number, length: number) => Promise<Uint8Array>;
|
|
175
189
|
/**
|
|
176
190
|
* Write the file. Parents may be missing — do not create them here;
|
|
177
191
|
* {@link fromProvider} owns that guarantee for every backend.
|
|
@@ -208,6 +222,8 @@ interface Provider {
|
|
|
208
222
|
interface Interface {
|
|
209
223
|
readonly readFile: (path: string) => Effect.Effect<string, FileSystemError>;
|
|
210
224
|
readonly readFileBuffer: (path: string) => Effect.Effect<Uint8Array, FileSystemError>;
|
|
225
|
+
/** Up to `length` bytes from `offset`; fewer at the end of the file. */
|
|
226
|
+
readonly readBytes: (path: string, offset: number, length: number) => Effect.Effect<Uint8Array, FileSystemError>;
|
|
211
227
|
/** Creates missing parent directories, on every backend. */
|
|
212
228
|
readonly writeFile: (path: string, content: string | Uint8Array) => Effect.Effect<void, FileSystemError>;
|
|
213
229
|
readonly stat: (path: string) => Effect.Effect<FileStat, FileSystemError>;
|
|
@@ -248,5 +264,5 @@ declare const fromProvider: (provider: Provider) => Interface;
|
|
|
248
264
|
*/
|
|
249
265
|
declare const withCwd: (fs: Interface, cwd: string) => Interface;
|
|
250
266
|
//#endregion
|
|
251
|
-
export { Provider as a, filesystem_d_exports as c,
|
|
252
|
-
//# sourceMappingURL=filesystem-
|
|
267
|
+
export { LineScanOptions as _, Provider as a, filesystem_d_exports as c, readBytesScript as d, readBytesViaShell as f, LineScan as g, withCwd as h, OperationUnsupportedError as i, fromProvider as l, validateRmOptions as m, FileSystemError as n, RmOptions as o, realpathScripts as p, Interface as r, Service as s, FileStat as t, isNotFoundError as u, scan_d_exports as v };
|
|
268
|
+
//# sourceMappingURL=filesystem-CuGE9poU.d.mts.map
|
package/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { t as section_d_exports } from "./plugin/section.mjs";
|
|
2
|
-
import { g as tool_d_exports } from "./tool-
|
|
3
|
-
import { t as plugin_d_exports } from "./plugin-
|
|
2
|
+
import { g as tool_d_exports } from "./tool-B7sWVmBt.mjs";
|
|
3
|
+
import { t as plugin_d_exports } from "./plugin-C2ZADu75.mjs";
|
|
4
4
|
export { plugin_d_exports as Plugin, section_d_exports as Section, tool_d_exports as Tool };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { ID } from "./sandbox/instance.mjs";
|
|
3
3
|
import { posix } from "./posix.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { d as withCwd, o as isNotFoundError, r as Service$1 } from "./filesystem-B9bz-Lsa.mjs";
|
|
5
5
|
import { Shell as Shell$1, withCwd as withCwd$1 } from "./sandbox/shell.mjs";
|
|
6
6
|
import { Context, Deferred, Effect, Layer } from "effect";
|
|
7
7
|
//#region src/sandbox/mutation.ts
|
|
@@ -185,4 +185,4 @@ const remote = (input) => ({
|
|
|
185
185
|
//#endregion
|
|
186
186
|
export { Shell as a, identityLayer as c, remote as d, resolveMountCwd as f, Mutation as i, io_exports as l, withMutation as m, DEFAULT_SPILL_PATH as n, host as o, virtual as p, FileSystem as r, hostLayer as s, Current as t, mount as u };
|
|
187
187
|
|
|
188
|
-
//# sourceMappingURL=io-
|
|
188
|
+
//# sourceMappingURL=io-CnEW_rHm.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io-RvZvG-4N.mjs","names":["SandboxFileSystem.Service","ShellTag","SandboxMutation.Service","EffectLayer","SandboxMutation.make","SandboxFileSystem.withCwd","shellWithCwd"],"sources":["../../src/sandbox/mutation.ts","../../src/sandbox/io.ts"],"sourcesContent":["import { Context, Deferred, Effect } from \"effect\";\nimport { posix } from \"../posix.ts\";\nimport { type FileSystemError, type Interface as FileSystem, isNotFoundError } from \"./filesystem.ts\";\nimport type { SandboxInstance } from \"./instance.ts\";\n\n/**\n * Serializes mutations of one file.\n *\n * Tool calls may run in parallel, and a file-mutating tool does read → modify →\n * write. Two of those on one file interleave and the first write is lost, so a\n * tool holds the file for its whole read-modify-write.\n *\n * A file is its sandbox instance plus its canonical path: two mounts of one\n * instance share files, and a symlinked spelling of a path is the same file.\n * Other files never wait. This orders the harness's own tools within this\n * process only; it is not a lock against `bash` or other processes.\n */\nexport interface Interface {\n\t/**\n\t * Run `effect` as the only mutation of `path` in flight. Calls queue in the\n\t * order their paths resolve, which for one spelling is the order they were made.\n\t */\n\treadonly withFile: <A, E, R>(\n\t\tpath: string,\n\t\teffect: Effect.Effect<A, E, R>,\n\t) => Effect.Effect<A, E | FileSystemError, R>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\"@codeworksh/plugin/sandbox/mutation/Service\") {}\n\ninterface Lock {\n\treadonly waiters: Array<Deferred.Deferred<void>>;\n}\n\n// Process-wide on purpose: every mount of one instance must meet in the same\n// queue, whichever layer built it. A key is present exactly while its file is held.\nconst locks = new Map<string, Lock>();\n\n/** Hand the file to the next waiter, or free it. Ownership moves directly, so no newcomer can barge in. */\nconst release = (key: string, lock: Lock): void => {\n\tconst next = lock.waiters.shift();\n\tif (next === undefined) locks.delete(key);\n\telse Deferred.doneUnsafe(next, Effect.void);\n};\n\n/** Take the file, waiting interruptibly; must run uninterruptibly so taking and releasing pair up. */\nconst acquire = (key: string, restore: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>) =>\n\tEffect.suspend(() => {\n\t\tconst lock = locks.get(key);\n\t\tif (lock === undefined) {\n\t\t\tlocks.set(key, { waiters: [] });\n\t\t\treturn Effect.void;\n\t\t}\n\t\tconst turn = Deferred.makeUnsafe<void>();\n\t\tlock.waiters.push(turn);\n\t\treturn restore(Deferred.await(turn)).pipe(\n\t\t\tEffect.onInterrupt(() =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tconst index = lock.waiters.indexOf(turn);\n\t\t\t\t\t// Still queued: leave. Already handed the file: pass it on.\n\t\t\t\t\tif (index !== -1) lock.waiters.splice(index, 1);\n\t\t\t\t\telse release(key, lock);\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t});\n\n/**\n * The canonical path. A file that does not exist yet takes its canonical\n * parent joined with its name, walking up as far as needed, so a write that\n * creates a file (and its directories) shares a key with later mutations of it.\n */\nconst canonical = (fs: FileSystem, path: string): Effect.Effect<string, FileSystemError> =>\n\tfs.realpath(path).pipe(\n\t\tEffect.catchIf(\n\t\t\t(error) => isNotFoundError(error.cause),\n\t\t\t(error) => {\n\t\t\t\tconst parent = posix.dirname(path);\n\t\t\t\tif (parent === path) return Effect.fail(error);\n\t\t\t\treturn Effect.map(canonical(fs, parent), (resolved) => posix.join(resolved, posix.basename(path)));\n\t\t\t},\n\t\t),\n\t);\n\nexport const make = (instance: SandboxInstance.ID, cwd: string, fs: FileSystem): Interface => ({\n\twithFile: (path, effect) =>\n\t\tEffect.flatMap(canonical(fs, posix.resolve(cwd, path)), (resolved) => {\n\t\t\tconst key = `${instance}\\0${resolved}`;\n\t\t\t// Held from the moment `acquire` returns: nothing can interrupt between\n\t\t\t// taking the file and installing its release.\n\t\t\treturn Effect.uninterruptibleMask((restore) =>\n\t\t\t\tEffect.andThen(\n\t\t\t\t\tacquire(key, restore),\n\t\t\t\t\trestore(effect).pipe(\n\t\t\t\t\t\tEffect.ensuring(\n\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\tconst lock = locks.get(key);\n\t\t\t\t\t\t\t\tif (lock !== undefined) release(key, lock);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}),\n});\n\nexport * as SandboxMutation from \"./mutation.ts\";\n","import { Context, Effect, Layer as EffectLayer } from \"effect\";\nimport { posix } from \"../posix.ts\";\nimport type { SandboxDriver } from \"./driver.ts\";\nimport { SandboxFileSystem } from \"./filesystem.ts\";\nimport { SandboxInstance } from \"./instance.ts\";\nimport { SandboxMutation } from \"./mutation.ts\";\nimport { type ISandboxExe, Shell as ShellTag, withCwd as shellWithCwd } from \"./shell.ts\";\n\n/**\n * `SandboxIO` is a **mount**: a filesystem, a shell, and the identity and\n * working directory they act on.\n *\n * It is the whole vocabulary a consumer needs. Project, Git, Copy, Location, and\n * every tool ask for `SandboxIO.FileSystem`, `SandboxIO.Shell`, and\n * `SandboxIO.Current` — never for a driver, an address, or a provider SDK — so\n * a host directory, an in-memory VFS, and a remote microVM are interchangeable\n * behind one contract.\n *\n * The mount neither creates nor destroys infrastructure. `SandboxInstance` is\n * the durable namespace it acts on — a device, which exists whether or not\n * anything has it mounted — and `Sandbox.Controller` is the only path that\n * creates, stops, or destroys one.\n */\n\n/**\n * The filesystem tag. Re-exported here so consumers import one namespace —\n * Project, Git, Copy, and the runner ask for `SandboxIO.FileSystem`, never for\n * the module that happens to define it. Code *inside* `sandbox/` keeps importing\n * the tag directly, since `io.ts` is built on top of it.\n */\nexport const FileSystem = SandboxFileSystem.Service;\nexport type FileSystem = SandboxFileSystem.Service;\n\n/** The shell tag. Re-exported here so consumers import one namespace. */\nexport const Shell = ShellTag;\nexport type Shell = ShellTag;\n\n/** Per-file mutation ordering for this mount's instance. Re-exported here so consumers import one namespace. */\nexport const Mutation = SandboxMutation.Service;\nexport type Mutation = SandboxMutation.Service;\n\n/**\n * What a mount sees: immutable identity, plus the working directory resolved for\n * *this* mount.\n *\n * Nothing mutable belongs here. `status`, `usage`, and reference counts all\n * change while a mount is open, so a mount-time snapshot of them would be wrong\n * by construction — runtime code that needs live management state asks the\n * control plane. The driver's own resource locator is likewise absent: consumers\n * never parse a Vercel name or a Daytona id.\n */\nexport interface Identity {\n\treadonly id: SandboxInstance.ID;\n\treadonly driver: SandboxDriver.Name;\n\treadonly kind: SandboxInstance.Kind;\n\t/** Absolute, and always a path in *this* namespace. */\n\treadonly cwd: string;\n\t/** Directory, in this namespace, that oversized tool output is written to. */\n\treadonly spillPath: string;\n}\n\n/** Spill directory for a driver that configures none. */\nexport const DEFAULT_SPILL_PATH = \"/tmp\";\n\n/** Identity and working directory of the current mount. */\nexport class Current extends Context.Service<Current, Identity>()(\"@codeworksh/plugin/sandbox/io/Current\") {}\n\n/** Everything a mount provides. */\nexport type Provides = Current | SandboxFileSystem.Service | ShellTag | SandboxMutation.Service;\n\n/** A built mount. */\nexport type Layer<E = never, RIn = never> = EffectLayer.Layer<Provides, E, RIn>;\n\n/**\n * Resolve a mount's cwd without consulting ambient process state.\n *\n * The default is supplied by the namespace adapter:\n * provider metadata remotely, `/` for a virtual filesystem, and `process.cwd()` for the host adapter.\n * An explicit absolute cwd replaces it; a relative cwd is resolved inside it. The\n * result is therefore always the one concrete absolute path `Current` requires.\n *\n * A non-absolute default throws rather than failing typed. It is the one\n * defect-level guard in this module, and deliberately so:\n * Adapters reading a value from a provider call this inside their own error channel,\n * where the throw becomes their typed failure (see `EnvDaytona.mountCwd`).\n */\nexport const resolveMountCwd = (defaultCwd: string, cwd?: string): string => {\n\tif (!posix.isAbsolute(defaultCwd)) {\n\t\tthrow new TypeError(`Sandbox default cwd must be absolute: ${defaultCwd}`);\n\t}\n\t// `resolve`, not `normalize`: normalize keeps a trailing slash, and `cwd` is\n\t// persisted — `space.location` and its id hash would read\n\t// `/workspace/` and `/workspace` as two directories and keep a row for each.\n\t//\n\t// A provider-reported default (`getWorkDir()`) or a config value is free to\n\t// carry one, so it is stripped here rather than at every reader.\n\tif (cwd === undefined) return posix.resolve(defaultCwd);\n\treturn posix.isAbsolute(cwd) ? posix.resolve(cwd) : posix.resolve(defaultCwd, cwd);\n};\n\n/**\n * Complete a mount with its {@link Mutation} queue, derived from the mount's own\n * identity and filesystem. Every layer that provides a mount goes through here,\n * so mounts of one instance always meet in the same queue.\n */\nexport const withMutation = <E, R>(\n\tlayer: EffectLayer.Layer<Current | SandboxFileSystem.Service | ShellTag, E, R>,\n): EffectLayer.Layer<Provides, E, R> =>\n\tEffectLayer.provideMerge(\n\t\tEffectLayer.effect(\n\t\t\tMutation,\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst current = yield* Current;\n\t\t\t\treturn SandboxMutation.make(current.id, current.cwd, yield* SandboxFileSystem.Service);\n\t\t\t}),\n\t\t),\n\t\tlayer,\n\t);\n\n/**\n * Bind a cwd-neutral transport to one mount.\n *\n * The transport underneath is shared between\n * mounts and stays rooted at the namespace root, and everything directory-shaped\n * happens here, once per mount. Two mounts of one namespace at different working\n * directories therefore coexist without seeing or moving each other's.\n *\n * It consumes the same two tags it provides — the transport is supplied by the\n * layer this is composed over, not by itself.\n */\nexport const mount = (identity: Identity): EffectLayer.Layer<Provides, never, SandboxFileSystem.Service | ShellTag> =>\n\tEffectLayer.mergeAll(\n\t\tEffectLayer.succeed(Current, identity),\n\t\tEffectLayer.effect(\n\t\t\tSandboxFileSystem.Service,\n\t\t\tEffect.map(SandboxFileSystem.Service, (fs) => SandboxFileSystem.withCwd(fs, identity.cwd)),\n\t\t),\n\t\tEffectLayer.effect(\n\t\t\tShellTag,\n\t\t\tEffect.map(ShellTag, (shell: ISandboxExe) => shellWithCwd(shell, identity.cwd)),\n\t\t),\n\t).pipe(withMutation);\n\n/**\n * Just the identity tag, with no filesystem or shell beneath it. For consumers\n * assembled from stubs — a test that runs `Project` over a fake filesystem still\n * needs to know which namespace it is in.\n */\nexport const identityLayer = (identity: Identity) => EffectLayer.succeed(Current, identity);\n\n/** The host identity alone. See {@link identityLayer}. */\nexport const hostLayer = (cwd: string) => identityLayer(host(cwd));\n\n/**\n * The host, rooted at `cwd`. Always `SandboxInstance.ID.local`: the working\n * directory selects where relative paths resolve, it does not make a second host\n * namespace — two mounts rooted at different directories still agree on absolute\n * paths.\n *\n * The host coordinate is explicit so a caller cannot accidentally substitute ambient process\n * state for the application or session directory it owns.\n */\nexport const host = (cwd: string): Identity => ({\n\tid: SandboxInstance.ID.local,\n\tdriver: \"local\" as SandboxDriver.Name,\n\tkind: \"local\",\n\tcwd: resolveMountCwd(cwd),\n\tspillPath: DEFAULT_SPILL_PATH,\n});\n\n/**\n * A VFS-backed namespace. The id is minted per call unless one is named, because\n * building one of these builds a fresh VFS: N unnamed calls are N distinct\n * namespaces, none of which outlives the process. A file-backed store is the\n * exception — its file is the state, so whoever knows the file supplies the id\n * it was registered under.\n */\nexport const virtual = (input: {\n\treadonly driver: string;\n\treadonly id?: SandboxInstance.ID;\n\treadonly defaultCwd?: string;\n\treadonly cwd?: string;\n\treadonly spillPath?: string;\n}): Identity => ({\n\tid: input.id ?? SandboxInstance.ID.create(),\n\tdriver: input.driver as SandboxDriver.Name,\n\tkind: \"virtual\",\n\tcwd: resolveMountCwd(input.defaultCwd ?? \"/\", input.cwd),\n\tspillPath: input.spillPath ?? DEFAULT_SPILL_PATH,\n});\n\n/**\n * A provider-hosted namespace. The id is always supplied: a remote resource's\n * durable identity is minted and recorded by whoever provisioned it, never\n * derived here from the provider's own locator.\n */\nexport const remote = (input: {\n\treadonly driver: string;\n\treadonly id: SandboxInstance.ID;\n\t/** Namespace-intrinsic default supplied or discovered by the driver. */\n\treadonly defaultCwd: string;\n\treadonly cwd?: string;\n\t/** Namespace-intrinsic spill directory configured by the driver. */\n\treadonly spillPath?: string;\n}): Identity => ({\n\tid: input.id,\n\tdriver: input.driver as SandboxDriver.Name,\n\tkind: \"remote\",\n\tcwd: resolveMountCwd(input.defaultCwd, input.cwd),\n\tspillPath: input.spillPath ?? DEFAULT_SPILL_PATH,\n});\n\nexport * as SandboxIO from \"./io.ts\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"io-CnEW_rHm.mjs","names":["SandboxFileSystem.Service","ShellTag","SandboxMutation.Service","EffectLayer","SandboxMutation.make","SandboxFileSystem.withCwd","shellWithCwd"],"sources":["../../src/sandbox/mutation.ts","../../src/sandbox/io.ts"],"sourcesContent":["import { Context, Deferred, Effect } from \"effect\";\nimport { posix } from \"../posix.ts\";\nimport { type FileSystemError, type Interface as FileSystem, isNotFoundError } from \"./filesystem.ts\";\nimport type { SandboxInstance } from \"./instance.ts\";\n\n/**\n * Serializes mutations of one file.\n *\n * Tool calls may run in parallel, and a file-mutating tool does read → modify →\n * write. Two of those on one file interleave and the first write is lost, so a\n * tool holds the file for its whole read-modify-write.\n *\n * A file is its sandbox instance plus its canonical path: two mounts of one\n * instance share files, and a symlinked spelling of a path is the same file.\n * Other files never wait. This orders the harness's own tools within this\n * process only; it is not a lock against `bash` or other processes.\n */\nexport interface Interface {\n\t/**\n\t * Run `effect` as the only mutation of `path` in flight. Calls queue in the\n\t * order their paths resolve, which for one spelling is the order they were made.\n\t */\n\treadonly withFile: <A, E, R>(\n\t\tpath: string,\n\t\teffect: Effect.Effect<A, E, R>,\n\t) => Effect.Effect<A, E | FileSystemError, R>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\"@codeworksh/plugin/sandbox/mutation/Service\") {}\n\ninterface Lock {\n\treadonly waiters: Array<Deferred.Deferred<void>>;\n}\n\n// Process-wide on purpose: every mount of one instance must meet in the same\n// queue, whichever layer built it. A key is present exactly while its file is held.\nconst locks = new Map<string, Lock>();\n\n/** Hand the file to the next waiter, or free it. Ownership moves directly, so no newcomer can barge in. */\nconst release = (key: string, lock: Lock): void => {\n\tconst next = lock.waiters.shift();\n\tif (next === undefined) locks.delete(key);\n\telse Deferred.doneUnsafe(next, Effect.void);\n};\n\n/** Take the file, waiting interruptibly; must run uninterruptibly so taking and releasing pair up. */\nconst acquire = (key: string, restore: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>) =>\n\tEffect.suspend(() => {\n\t\tconst lock = locks.get(key);\n\t\tif (lock === undefined) {\n\t\t\tlocks.set(key, { waiters: [] });\n\t\t\treturn Effect.void;\n\t\t}\n\t\tconst turn = Deferred.makeUnsafe<void>();\n\t\tlock.waiters.push(turn);\n\t\treturn restore(Deferred.await(turn)).pipe(\n\t\t\tEffect.onInterrupt(() =>\n\t\t\t\tEffect.sync(() => {\n\t\t\t\t\tconst index = lock.waiters.indexOf(turn);\n\t\t\t\t\t// Still queued: leave. Already handed the file: pass it on.\n\t\t\t\t\tif (index !== -1) lock.waiters.splice(index, 1);\n\t\t\t\t\telse release(key, lock);\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t});\n\n/**\n * The canonical path. A file that does not exist yet takes its canonical\n * parent joined with its name, walking up as far as needed, so a write that\n * creates a file (and its directories) shares a key with later mutations of it.\n */\nconst canonical = (fs: FileSystem, path: string): Effect.Effect<string, FileSystemError> =>\n\tfs.realpath(path).pipe(\n\t\tEffect.catchIf(\n\t\t\t(error) => isNotFoundError(error.cause),\n\t\t\t(error) => {\n\t\t\t\tconst parent = posix.dirname(path);\n\t\t\t\tif (parent === path) return Effect.fail(error);\n\t\t\t\treturn Effect.map(canonical(fs, parent), (resolved) => posix.join(resolved, posix.basename(path)));\n\t\t\t},\n\t\t),\n\t);\n\nexport const make = (instance: SandboxInstance.ID, cwd: string, fs: FileSystem): Interface => ({\n\twithFile: (path, effect) =>\n\t\tEffect.flatMap(canonical(fs, posix.resolve(cwd, path)), (resolved) => {\n\t\t\tconst key = `${instance}\\0${resolved}`;\n\t\t\t// Held from the moment `acquire` returns: nothing can interrupt between\n\t\t\t// taking the file and installing its release.\n\t\t\treturn Effect.uninterruptibleMask((restore) =>\n\t\t\t\tEffect.andThen(\n\t\t\t\t\tacquire(key, restore),\n\t\t\t\t\trestore(effect).pipe(\n\t\t\t\t\t\tEffect.ensuring(\n\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\tconst lock = locks.get(key);\n\t\t\t\t\t\t\t\tif (lock !== undefined) release(key, lock);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}),\n});\n\nexport * as SandboxMutation from \"./mutation.ts\";\n","import { Context, Effect, Layer as EffectLayer } from \"effect\";\nimport { posix } from \"../posix.ts\";\nimport type { SandboxDriver } from \"./driver.ts\";\nimport { SandboxFileSystem } from \"./filesystem.ts\";\nimport { SandboxInstance } from \"./instance.ts\";\nimport { SandboxMutation } from \"./mutation.ts\";\nimport { type ISandboxExe, Shell as ShellTag, withCwd as shellWithCwd } from \"./shell.ts\";\n\n/**\n * `SandboxIO` is a **mount**: a filesystem, a shell, and the identity and\n * working directory they act on.\n *\n * It is the whole vocabulary a consumer needs. Project, Git, Copy, Location, and\n * every tool ask for `SandboxIO.FileSystem`, `SandboxIO.Shell`, and\n * `SandboxIO.Current` — never for a driver, an address, or a provider SDK — so\n * a host directory, an in-memory VFS, and a remote microVM are interchangeable\n * behind one contract.\n *\n * The mount neither creates nor destroys infrastructure. `SandboxInstance` is\n * the durable namespace it acts on — a device, which exists whether or not\n * anything has it mounted — and `Sandbox.Controller` is the only path that\n * creates, stops, or destroys one.\n */\n\n/**\n * The filesystem tag. Re-exported here so consumers import one namespace —\n * Project, Git, Copy, and the runner ask for `SandboxIO.FileSystem`, never for\n * the module that happens to define it. Code *inside* `sandbox/` keeps importing\n * the tag directly, since `io.ts` is built on top of it.\n */\nexport const FileSystem = SandboxFileSystem.Service;\nexport type FileSystem = SandboxFileSystem.Service;\n\n/** The shell tag. Re-exported here so consumers import one namespace. */\nexport const Shell = ShellTag;\nexport type Shell = ShellTag;\n\n/** Per-file mutation ordering for this mount's instance. Re-exported here so consumers import one namespace. */\nexport const Mutation = SandboxMutation.Service;\nexport type Mutation = SandboxMutation.Service;\n\n/**\n * What a mount sees: immutable identity, plus the working directory resolved for\n * *this* mount.\n *\n * Nothing mutable belongs here. `status`, `usage`, and reference counts all\n * change while a mount is open, so a mount-time snapshot of them would be wrong\n * by construction — runtime code that needs live management state asks the\n * control plane. The driver's own resource locator is likewise absent: consumers\n * never parse a Vercel name or a Daytona id.\n */\nexport interface Identity {\n\treadonly id: SandboxInstance.ID;\n\treadonly driver: SandboxDriver.Name;\n\treadonly kind: SandboxInstance.Kind;\n\t/** Absolute, and always a path in *this* namespace. */\n\treadonly cwd: string;\n\t/** Directory, in this namespace, that oversized tool output is written to. */\n\treadonly spillPath: string;\n}\n\n/** Spill directory for a driver that configures none. */\nexport const DEFAULT_SPILL_PATH = \"/tmp\";\n\n/** Identity and working directory of the current mount. */\nexport class Current extends Context.Service<Current, Identity>()(\"@codeworksh/plugin/sandbox/io/Current\") {}\n\n/** Everything a mount provides. */\nexport type Provides = Current | SandboxFileSystem.Service | ShellTag | SandboxMutation.Service;\n\n/** A built mount. */\nexport type Layer<E = never, RIn = never> = EffectLayer.Layer<Provides, E, RIn>;\n\n/**\n * Resolve a mount's cwd without consulting ambient process state.\n *\n * The default is supplied by the namespace adapter:\n * provider metadata remotely, `/` for a virtual filesystem, and `process.cwd()` for the host adapter.\n * An explicit absolute cwd replaces it; a relative cwd is resolved inside it. The\n * result is therefore always the one concrete absolute path `Current` requires.\n *\n * A non-absolute default throws rather than failing typed. It is the one\n * defect-level guard in this module, and deliberately so:\n * Adapters reading a value from a provider call this inside their own error channel,\n * where the throw becomes their typed failure (see `EnvDaytona.mountCwd`).\n */\nexport const resolveMountCwd = (defaultCwd: string, cwd?: string): string => {\n\tif (!posix.isAbsolute(defaultCwd)) {\n\t\tthrow new TypeError(`Sandbox default cwd must be absolute: ${defaultCwd}`);\n\t}\n\t// `resolve`, not `normalize`: normalize keeps a trailing slash, and `cwd` is\n\t// persisted — `space.location` and its id hash would read\n\t// `/workspace/` and `/workspace` as two directories and keep a row for each.\n\t//\n\t// A provider-reported default (`getWorkDir()`) or a config value is free to\n\t// carry one, so it is stripped here rather than at every reader.\n\tif (cwd === undefined) return posix.resolve(defaultCwd);\n\treturn posix.isAbsolute(cwd) ? posix.resolve(cwd) : posix.resolve(defaultCwd, cwd);\n};\n\n/**\n * Complete a mount with its {@link Mutation} queue, derived from the mount's own\n * identity and filesystem. Every layer that provides a mount goes through here,\n * so mounts of one instance always meet in the same queue.\n */\nexport const withMutation = <E, R>(\n\tlayer: EffectLayer.Layer<Current | SandboxFileSystem.Service | ShellTag, E, R>,\n): EffectLayer.Layer<Provides, E, R> =>\n\tEffectLayer.provideMerge(\n\t\tEffectLayer.effect(\n\t\t\tMutation,\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst current = yield* Current;\n\t\t\t\treturn SandboxMutation.make(current.id, current.cwd, yield* SandboxFileSystem.Service);\n\t\t\t}),\n\t\t),\n\t\tlayer,\n\t);\n\n/**\n * Bind a cwd-neutral transport to one mount.\n *\n * The transport underneath is shared between\n * mounts and stays rooted at the namespace root, and everything directory-shaped\n * happens here, once per mount. Two mounts of one namespace at different working\n * directories therefore coexist without seeing or moving each other's.\n *\n * It consumes the same two tags it provides — the transport is supplied by the\n * layer this is composed over, not by itself.\n */\nexport const mount = (identity: Identity): EffectLayer.Layer<Provides, never, SandboxFileSystem.Service | ShellTag> =>\n\tEffectLayer.mergeAll(\n\t\tEffectLayer.succeed(Current, identity),\n\t\tEffectLayer.effect(\n\t\t\tSandboxFileSystem.Service,\n\t\t\tEffect.map(SandboxFileSystem.Service, (fs) => SandboxFileSystem.withCwd(fs, identity.cwd)),\n\t\t),\n\t\tEffectLayer.effect(\n\t\t\tShellTag,\n\t\t\tEffect.map(ShellTag, (shell: ISandboxExe) => shellWithCwd(shell, identity.cwd)),\n\t\t),\n\t).pipe(withMutation);\n\n/**\n * Just the identity tag, with no filesystem or shell beneath it. For consumers\n * assembled from stubs — a test that runs `Project` over a fake filesystem still\n * needs to know which namespace it is in.\n */\nexport const identityLayer = (identity: Identity) => EffectLayer.succeed(Current, identity);\n\n/** The host identity alone. See {@link identityLayer}. */\nexport const hostLayer = (cwd: string) => identityLayer(host(cwd));\n\n/**\n * The host, rooted at `cwd`. Always `SandboxInstance.ID.local`: the working\n * directory selects where relative paths resolve, it does not make a second host\n * namespace — two mounts rooted at different directories still agree on absolute\n * paths.\n *\n * The host coordinate is explicit so a caller cannot accidentally substitute ambient process\n * state for the application or session directory it owns.\n */\nexport const host = (cwd: string): Identity => ({\n\tid: SandboxInstance.ID.local,\n\tdriver: \"local\" as SandboxDriver.Name,\n\tkind: \"local\",\n\tcwd: resolveMountCwd(cwd),\n\tspillPath: DEFAULT_SPILL_PATH,\n});\n\n/**\n * A VFS-backed namespace. The id is minted per call unless one is named, because\n * building one of these builds a fresh VFS: N unnamed calls are N distinct\n * namespaces, none of which outlives the process. A file-backed store is the\n * exception — its file is the state, so whoever knows the file supplies the id\n * it was registered under.\n */\nexport const virtual = (input: {\n\treadonly driver: string;\n\treadonly id?: SandboxInstance.ID;\n\treadonly defaultCwd?: string;\n\treadonly cwd?: string;\n\treadonly spillPath?: string;\n}): Identity => ({\n\tid: input.id ?? SandboxInstance.ID.create(),\n\tdriver: input.driver as SandboxDriver.Name,\n\tkind: \"virtual\",\n\tcwd: resolveMountCwd(input.defaultCwd ?? \"/\", input.cwd),\n\tspillPath: input.spillPath ?? DEFAULT_SPILL_PATH,\n});\n\n/**\n * A provider-hosted namespace. The id is always supplied: a remote resource's\n * durable identity is minted and recorded by whoever provisioned it, never\n * derived here from the provider's own locator.\n */\nexport const remote = (input: {\n\treadonly driver: string;\n\treadonly id: SandboxInstance.ID;\n\t/** Namespace-intrinsic default supplied or discovered by the driver. */\n\treadonly defaultCwd: string;\n\treadonly cwd?: string;\n\t/** Namespace-intrinsic spill directory configured by the driver. */\n\treadonly spillPath?: string;\n}): Identity => ({\n\tid: input.id,\n\tdriver: input.driver as SandboxDriver.Name,\n\tkind: \"remote\",\n\tcwd: resolveMountCwd(input.defaultCwd, input.cwd),\n\tspillPath: input.spillPath ?? DEFAULT_SPILL_PATH,\n});\n\nexport * as SandboxIO from \"./io.ts\";\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as filesystem_d_exports, n as FileSystemError, r as Interface$1, s as Service$1 } from "./filesystem-
|
|
1
|
+
import { c as filesystem_d_exports, n as FileSystemError, r as Interface$1, s as Service$1 } from "./filesystem-CuGE9poU.mjs";
|
|
2
2
|
import { i as Shell$1 } from "./shell-CZ6Y4lNU.mjs";
|
|
3
3
|
import { Context, Effect, Layer, Option, Schema } from "effect";
|
|
4
4
|
declare namespace instance_d_exports {
|
|
@@ -537,4 +537,4 @@ declare const remote: (input: {
|
|
|
537
537
|
}) => Identity;
|
|
538
538
|
//#endregion
|
|
539
539
|
export { SandboxRegisterError as $, RuntimeConfigBase as A, SandboxBusyError as B, Module as C, mountable as Ct, Provisioned as D, Observed as E, driver as F, SandboxDriverNotRegisteredError as G, SandboxDestroyError as H, driver_d_exports as I, SandboxMustBeStoppedError as J, SandboxDriverRegistrationError as K, erase as L, Source as M, apiVersion as N, Registered as O, defineModule as P, SandboxRefreshError as Q, withSource as R, Driver as S, isMountable as St, Name as T, toField as Tt, SandboxDriverLoadError as U, SandboxCreateError as V, SandboxDriverLoadPhase as W, SandboxProviderError as X, SandboxNotFoundError as Y, SandboxReadError as Z, withMutation as _, Status as _t, Layer$1 as a, SandboxWakeError as at, Capabilities as b, fromField as bt, Shell as c, providerError as ct, identityLayer as d, sanitizeError as dt, SandboxRemovedError as et, io_d_exports as f, ID as ft, virtual as g, PersistedError as gt, resolveMountCwd as h, Ownership as ht, Identity as i, SandboxUnsupportedError as it, RuntimeInput as j, Registration as k, host as l, providerErrorCause as lt, remote as m, Kind as mt, DEFAULT_SPILL_PATH as n, SandboxTransitionConflictError as nt, Mutation as o, errors_d_exports as ot, mount as p, Info as pt, SandboxMountError as q, FileSystem as r, SandboxUnavailError as rt, Provides as s, makeRedactor as st, Current as t, SandboxStopError as tt, hostLayer as u, providerErrorIsNotFound as ut, AbsolutePath as v, Usage as vt, ModuleDefinition as w, toColumn as wt, Definition as x, instance_d_exports as xt, ApiVersion as y, fromColumn as yt, Redactor as z };
|
|
540
|
-
//# sourceMappingURL=io-
|
|
540
|
+
//# sourceMappingURL=io-nhvNKC33.d.mts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeworksh/plugin",
|
|
3
|
-
"version": "0.1.0-canary.
|
|
3
|
+
"version": "0.1.0-canary.24.1.g001b9423",
|
|
4
4
|
"description": "SDK for building CodeWork plugins — the plugin, tool, and sandbox contracts shared with @codeworksh/harness.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"uuidv7": "^1.2.1"
|
|
169
169
|
},
|
|
170
170
|
"peerDependencies": {
|
|
171
|
-
"@codeworksh/aikit": "0.10.0-canary.
|
|
171
|
+
"@codeworksh/aikit": "0.10.0-canary.24.1.g001b9423",
|
|
172
172
|
"effect": "4.0.1"
|
|
173
173
|
}
|
|
174
174
|
}
|
package/plugin/tool.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ToolAfterResult, c as ToolBeforeResult, d as ToolRegistry, f as ToolResultContent, i as ToolAfterFn, l as ToolDefPatch, n as ToolAddOptions, o as ToolBefore, r as ToolAfter, s as ToolBeforeFn, t as HookReturn, u as ToolRegistration } from "../tool-
|
|
1
|
+
import { a as ToolAfterResult, c as ToolBeforeResult, d as ToolRegistry, f as ToolResultContent, i as ToolAfterFn, l as ToolDefPatch, n as ToolAddOptions, o as ToolBefore, r as ToolAfter, s as ToolBeforeFn, t as HookReturn, u as ToolRegistration } from "../tool-hXy4__zc.mjs";
|
|
2
2
|
export { HookReturn, ToolAddOptions, ToolAfter, ToolAfterFn, ToolAfterResult, ToolBefore, ToolBeforeFn, ToolBeforeResult, ToolDefPatch, ToolRegistration, ToolRegistry, ToolResultContent };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { i as Definition, o as Payload, r as Data, s as PublishOptions } from "./event-
|
|
1
|
+
import { i as Definition, o as Payload, r as Data, s as PublishOptions } from "./event-mKxToqmh.mjs";
|
|
2
2
|
import { n as SessionID } from "./ids-CHjmAdTc.mjs";
|
|
3
3
|
import { o as Service, r as Info } from "./location-Q39els63.mjs";
|
|
4
|
-
import { f as io_d_exports, i as Identity, s as Provides } from "./io-
|
|
4
|
+
import { f as io_d_exports, i as Identity, s as Provides } from "./io-nhvNKC33.mjs";
|
|
5
5
|
import { i as Info$1 } from "./settings-B6-grSTA.mjs";
|
|
6
6
|
import { t as section_d_exports } from "./plugin/section.mjs";
|
|
7
7
|
import { n as prompt_d_exports, t as PromptRegistry } from "./prompt-DWaA5ZXj.mjs";
|
|
8
|
-
import { d as ToolRegistry, p as tool_d_exports } from "./tool-
|
|
8
|
+
import { d as ToolRegistry, p as tool_d_exports } from "./tool-hXy4__zc.mjs";
|
|
9
9
|
import { Model } from "@codeworksh/aikit";
|
|
10
10
|
import { Effect } from "effect";
|
|
11
11
|
//#region src/plugin/registry.d.ts
|
|
@@ -138,4 +138,4 @@ declare namespace plugin_d_exports {
|
|
|
138
138
|
}
|
|
139
139
|
//#endregion
|
|
140
140
|
export { define as a, PluginOptions as c, PluginSpec as d, Config as f, PluginRegistry as g, SharedPluginContext as h, PluginKind as i, PluginPatch as l, PromptResolver as m, Mount as n, domains as o, Events as p, Plugin as r, rank as s, plugin_d_exports as t, PluginRef as u };
|
|
141
|
-
//# sourceMappingURL=plugin-
|
|
141
|
+
//# sourceMappingURL=plugin-C2ZADu75.d.mts.map
|
package/plugin.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as section_d_exports } from "./plugin/section.mjs";
|
|
2
2
|
import { n as prompt_d_exports } from "./prompt-DWaA5ZXj.mjs";
|
|
3
|
-
import { p as tool_d_exports } from "./tool-
|
|
4
|
-
import { a as define, c as PluginOptions, d as PluginSpec, f as Config, g as PluginRegistry, h as SharedPluginContext, i as PluginKind, l as PluginPatch, m as PromptResolver, n as Mount, o as domains, p as Events, r as Plugin, s as rank, u as PluginRef } from "./plugin-
|
|
3
|
+
import { p as tool_d_exports } from "./tool-hXy4__zc.mjs";
|
|
4
|
+
import { a as define, c as PluginOptions, d as PluginSpec, f as Config, g as PluginRegistry, h as SharedPluginContext, i as PluginKind, l as PluginPatch, m as PromptResolver, n as Mount, o as domains, p as Events, r as Plugin, s as rank, u as PluginRef } from "./plugin-C2ZADu75.mjs";
|
|
5
5
|
export { type Config, type Events, type Mount, type Plugin, type PluginKind, type PluginOptions, type PluginPatch, type PluginRef, type PluginRegistry, type PluginSpec, prompt_d_exports as Prompt, type PromptResolver, section_d_exports as Section, type SharedPluginContext, tool_d_exports as Tool, define, domains, rank };
|
package/sandbox/driver.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as RuntimeConfigBase, C as Module, D as Provisioned, E as Observed, F as driver, I as driver_d_exports, L as erase, M as Source, N as apiVersion, O as Registered, P as defineModule, R as withSource, S as Driver, T as Name, b as Capabilities, j as RuntimeInput, k as Registration, v as AbsolutePath, w as ModuleDefinition, x as Definition, y as ApiVersion } from "../io-
|
|
1
|
+
import { A as RuntimeConfigBase, C as Module, D as Provisioned, E as Observed, F as driver, I as driver_d_exports, L as erase, M as Source, N as apiVersion, O as Registered, P as defineModule, R as withSource, S as Driver, T as Name, b as Capabilities, j as RuntimeInput, k as Registration, v as AbsolutePath, w as ModuleDefinition, x as Definition, y as ApiVersion } from "../io-nhvNKC33.mjs";
|
|
2
2
|
export { AbsolutePath, ApiVersion, Capabilities, Definition, Driver, Module, ModuleDefinition, Name, Observed, Provisioned, Registered, Registration, RuntimeConfigBase, RuntimeInput, driver_d_exports as SandboxDriver, Source, apiVersion, driver, erase, defineModule as module, withSource };
|
package/sandbox/driver.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import "./instance.mjs";
|
|
3
|
-
import "../io-
|
|
3
|
+
import "../io-CnEW_rHm.mjs";
|
|
4
4
|
import { Schema } from "effect";
|
|
5
5
|
//#region src/sandbox/driver.ts
|
|
6
6
|
var driver_exports = /* @__PURE__ */ __exportAll({
|
package/sandbox/errors.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as SandboxRegisterError, B as SandboxBusyError, G as SandboxDriverNotRegisteredError, H as SandboxDestroyError, J as SandboxMustBeStoppedError, K as SandboxDriverRegistrationError, Q as SandboxRefreshError, U as SandboxDriverLoadError, V as SandboxCreateError, W as SandboxDriverLoadPhase, X as SandboxProviderError, Y as SandboxNotFoundError, Z as SandboxReadError, at as SandboxWakeError, ct as providerError, dt as sanitizeError, et as SandboxRemovedError, it as SandboxUnsupportedError, lt as providerErrorCause, nt as SandboxTransitionConflictError, ot as errors_d_exports, q as SandboxMountError, rt as SandboxUnavailError, st as makeRedactor, tt as SandboxStopError, ut as providerErrorIsNotFound, z as Redactor } from "../io-
|
|
1
|
+
import { $ as SandboxRegisterError, B as SandboxBusyError, G as SandboxDriverNotRegisteredError, H as SandboxDestroyError, J as SandboxMustBeStoppedError, K as SandboxDriverRegistrationError, Q as SandboxRefreshError, U as SandboxDriverLoadError, V as SandboxCreateError, W as SandboxDriverLoadPhase, X as SandboxProviderError, Y as SandboxNotFoundError, Z as SandboxReadError, at as SandboxWakeError, ct as providerError, dt as sanitizeError, et as SandboxRemovedError, it as SandboxUnsupportedError, lt as providerErrorCause, nt as SandboxTransitionConflictError, ot as errors_d_exports, q as SandboxMountError, rt as SandboxUnavailError, st as makeRedactor, tt as SandboxStopError, ut as providerErrorIsNotFound, z as Redactor } from "../io-nhvNKC33.mjs";
|
|
2
2
|
export { Redactor, SandboxBusyError, SandboxCreateError, SandboxDestroyError, SandboxDriverLoadError, SandboxDriverLoadPhase, SandboxDriverNotRegisteredError, SandboxDriverRegistrationError, errors_d_exports as SandboxError, SandboxMountError, SandboxMustBeStoppedError, SandboxNotFoundError, SandboxProviderError, SandboxReadError, SandboxRefreshError, SandboxRegisterError, SandboxRemovedError, SandboxStopError, SandboxTransitionConflictError, SandboxUnavailError, SandboxUnsupportedError, SandboxWakeError, makeRedactor, providerError, providerErrorCause, providerErrorIsNotFound, sanitizeError };
|
package/sandbox/filesystem.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as Provider, c as filesystem_d_exports, d as
|
|
2
|
-
export { FileStat, FileSystemError, Interface, type LineScan, type LineScanOptions, OperationUnsupportedError, Provider, RmOptions, filesystem_d_exports as SandboxFileSystem, scan_d_exports as Scan, Service, fromProvider, isNotFoundError, realpathScripts, validateRmOptions, withCwd };
|
|
1
|
+
import { _ as LineScanOptions, a as Provider, c as filesystem_d_exports, d as readBytesScript, f as readBytesViaShell, g as LineScan, h as withCwd, i as OperationUnsupportedError, l as fromProvider, m as validateRmOptions, n as FileSystemError, o as RmOptions, p as realpathScripts, r as Interface, s as Service, t as FileStat, u as isNotFoundError, v as scan_d_exports } from "../filesystem-CuGE9poU.mjs";
|
|
2
|
+
export { FileStat, FileSystemError, Interface, type LineScan, type LineScanOptions, OperationUnsupportedError, Provider, RmOptions, filesystem_d_exports as SandboxFileSystem, scan_d_exports as Scan, Service, fromProvider, isNotFoundError, readBytesScript, readBytesViaShell, realpathScripts, validateRmOptions, withCwd };
|
package/sandbox/filesystem.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as fromProvider, c as
|
|
2
|
-
export { FileSystemError, OperationUnsupportedError, filesystem_exports as SandboxFileSystem, scan_exports as Scan, Service, fromProvider, isNotFoundError, realpathScripts, validateRmOptions, withCwd };
|
|
1
|
+
import { a as fromProvider, c as readBytesViaShell, d as withCwd, f as scan_exports, i as filesystem_exports, l as realpathScripts, n as OperationUnsupportedError, o as isNotFoundError, r as Service, s as readBytesScript, t as FileSystemError, u as validateRmOptions } from "../filesystem-B9bz-Lsa.mjs";
|
|
2
|
+
export { FileSystemError, OperationUnsupportedError, filesystem_exports as SandboxFileSystem, scan_exports as Scan, Service, fromProvider, isNotFoundError, readBytesScript, readBytesViaShell, realpathScripts, validateRmOptions, withCwd };
|
package/sandbox/instance.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Ct as mountable, St as isMountable, Tt as toField, _t as Status, bt as fromField, ft as ID, gt as PersistedError, ht as Ownership, mt as Kind, pt as Info, vt as Usage, wt as toColumn, xt as instance_d_exports, yt as fromColumn } from "../io-
|
|
1
|
+
import { Ct as mountable, St as isMountable, Tt as toField, _t as Status, bt as fromField, ft as ID, gt as PersistedError, ht as Ownership, mt as Kind, pt as Info, vt as Usage, wt as toColumn, xt as instance_d_exports, yt as fromColumn } from "../io-nhvNKC33.mjs";
|
|
2
2
|
export { ID, Info, Kind, Ownership, PersistedError, instance_d_exports as SandboxInstance, Status, Usage, fromColumn, fromField, isMountable, mountable, toColumn, toField };
|
package/sandbox/io.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as withMutation, a as Layer, c as Shell, d as identityLayer, f as io_d_exports, g as virtual, h as resolveMountCwd, i as Identity, l as host, m as remote, n as DEFAULT_SPILL_PATH, o as Mutation, p as mount, r as FileSystem, s as Provides, t as Current, u as hostLayer } from "../io-
|
|
1
|
+
import { _ as withMutation, a as Layer, c as Shell, d as identityLayer, f as io_d_exports, g as virtual, h as resolveMountCwd, i as Identity, l as host, m as remote, n as DEFAULT_SPILL_PATH, o as Mutation, p as mount, r as FileSystem, s as Provides, t as Current, u as hostLayer } from "../io-nhvNKC33.mjs";
|
|
2
2
|
export { Current, DEFAULT_SPILL_PATH, FileSystem, Identity, Layer, Mutation, Provides, io_d_exports as SandboxIO, Shell, host, hostLayer, identityLayer, mount, remote, resolveMountCwd, virtual, withMutation };
|
package/sandbox/io.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import "./instance.mjs";
|
|
2
|
-
import { a as Shell, c as identityLayer, d as remote, f as resolveMountCwd, i as Mutation, l as io_exports, m as withMutation, n as DEFAULT_SPILL_PATH, o as host, p as virtual, r as FileSystem, s as hostLayer, t as Current, u as mount } from "../io-
|
|
2
|
+
import { a as Shell, c as identityLayer, d as remote, f as resolveMountCwd, i as Mutation, l as io_exports, m as withMutation, n as DEFAULT_SPILL_PATH, o as host, p as virtual, r as FileSystem, s as hostLayer, t as Current, u as mount } from "../io-CnEW_rHm.mjs";
|
|
3
3
|
export { Current, DEFAULT_SPILL_PATH, FileSystem, Mutation, io_exports as SandboxIO, Shell, host, hostLayer, identityLayer, mount, remote, resolveMountCwd, virtual, withMutation };
|
package/sandbox.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as RuntimeConfigBase, C as Module, D as Provisioned, E as Observed, F as driver, N as apiVersion, P as defineModule, S as Driver, T as Name, X as SandboxProviderError, _ as withMutation, a as Layer, b as Capabilities, c as Shell, ct as providerError, dt as sanitizeError, i as Identity, j as RuntimeInput, k as Registration, lt as providerErrorCause, n as DEFAULT_SPILL_PATH, o as Mutation, r as FileSystem, s as Provides, st as makeRedactor, t as Current, ut as providerErrorIsNotFound, v as AbsolutePath, w as ModuleDefinition, x as Definition, xt as instance_d_exports, y as ApiVersion, z as Redactor } from "./io-
|
|
2
|
-
import { c as filesystem_d_exports } from "./filesystem-
|
|
1
|
+
import { A as RuntimeConfigBase, C as Module, D as Provisioned, E as Observed, F as driver, N as apiVersion, P as defineModule, S as Driver, T as Name, X as SandboxProviderError, _ as withMutation, a as Layer, b as Capabilities, c as Shell, ct as providerError, dt as sanitizeError, i as Identity, j as RuntimeInput, k as Registration, lt as providerErrorCause, n as DEFAULT_SPILL_PATH, o as Mutation, r as FileSystem, s as Provides, st as makeRedactor, t as Current, ut as providerErrorIsNotFound, v as AbsolutePath, w as ModuleDefinition, x as Definition, xt as instance_d_exports, y as ApiVersion, z as Redactor } from "./io-nhvNKC33.mjs";
|
|
2
|
+
import { c as filesystem_d_exports } from "./filesystem-CuGE9poU.mjs";
|
|
3
3
|
import { a as ShellError, i as Shell$1, l as quote, n as ExecResult, o as ShellOptions, r as ISandboxExe, s as fromExec, t as ExecChunk, u as quoteArgv } from "./shell-CZ6Y4lNU.mjs";
|
|
4
4
|
import { SandboxResource as resource_d_exports } from "./sandbox/resource.mjs";
|
|
5
5
|
declare namespace driver_d_exports {
|
package/sandbox.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { SandboxInstance as instance_exports } from "./sandbox/instance.mjs";
|
|
3
|
-
import { i as filesystem_exports } from "./filesystem-
|
|
4
|
-
import { a as Shell, i as Mutation, m as withMutation, n as DEFAULT_SPILL_PATH, r as FileSystem, t as Current } from "./io-
|
|
3
|
+
import { i as filesystem_exports } from "./filesystem-B9bz-Lsa.mjs";
|
|
4
|
+
import { a as Shell, i as Mutation, m as withMutation, n as DEFAULT_SPILL_PATH, r as FileSystem, t as Current } from "./io-CnEW_rHm.mjs";
|
|
5
5
|
import { Shell as Shell$1, ShellError, fromExec, quote, quoteArgv } from "./sandbox/shell.mjs";
|
|
6
6
|
import { AbsolutePath, Name, RuntimeConfigBase, driver, module as defineModule } from "./sandbox/driver.mjs";
|
|
7
7
|
import { SandboxProviderError, makeRedactor, providerError, providerErrorCause, providerErrorIsNotFound, sanitizeError } from "./sandbox/errors.mjs";
|
package/tool/progress.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as IToolProgress, b as make, v as ToolProgress, x as noop, y as ToolProgressPartial } from "../tool-
|
|
1
|
+
import { _ as IToolProgress, b as make, v as ToolProgress, x as noop, y as ToolProgressPartial } from "../tool-B7sWVmBt.mjs";
|
|
2
2
|
export { IToolProgress, ToolProgress, ToolProgressPartial, make, noop };
|
|
@@ -81,6 +81,11 @@ interface ToolDef<Name extends string = string, Params extends Schema.Top = Sche
|
|
|
81
81
|
readonly encodeContent?: (success: Success["Type"]) => ModelContent;
|
|
82
82
|
/** Render an expected failure for the model. Omit → executor falls back to JSON text. */
|
|
83
83
|
readonly encodeFailureContent?: (failure: Failure["Type"]) => ModelContent;
|
|
84
|
+
/**
|
|
85
|
+
* The `details` kept with a success, for UIs and programmatic consumers. Omit → the encoded
|
|
86
|
+
* success. Set it when `encodeContent` already carries the payload, so it is not stored twice.
|
|
87
|
+
*/
|
|
88
|
+
readonly encodeDetails?: (success: Success["Type"]) => unknown;
|
|
84
89
|
}
|
|
85
90
|
/** A handler: validated params + context → typed success or typed failure. */
|
|
86
91
|
type Handler<Params extends Schema.Top, Success extends Schema.Top, Failure extends Schema.Top, R = never> = (params: Params["Type"], ctx: ToolCallContext) => Effect.Effect<Success["Type"], Failure["Type"], R>;
|
|
@@ -96,12 +101,14 @@ interface DefineInput<Name extends string, Params extends Schema.Top, Success ex
|
|
|
96
101
|
readonly description: string;
|
|
97
102
|
readonly label?: string;
|
|
98
103
|
readonly promptSnippet?: string;
|
|
104
|
+
readonly promptGuidelines?: ReadonlyArray<string>;
|
|
99
105
|
readonly parameters: Params;
|
|
100
106
|
readonly constrainedSampling?: Message.Tool["constrainedSampling"];
|
|
101
107
|
readonly success: Success;
|
|
102
108
|
readonly failure?: Failure;
|
|
103
109
|
readonly encodeContent?: (success: Success["Type"]) => ModelContent;
|
|
104
110
|
readonly encodeFailureContent?: (failure: Failure["Type"]) => ModelContent;
|
|
111
|
+
readonly encodeDetails?: (success: Success["Type"]) => unknown;
|
|
105
112
|
}
|
|
106
113
|
/** Define a pure tool (handler attached later via {@link implement} or a toolkit). */
|
|
107
114
|
declare const define: <Name extends string, Params extends Schema.Top, Success extends Schema.Top, Failure extends Schema.Top = Schema.Top>(input: DefineInput<Name, Params, Success, Failure>) => ToolDef<Name, Params, Success, Failure>;
|
|
@@ -145,4 +152,4 @@ declare const toProviderJsonSchema: (schema: Schema.Top) => Record<string, unkno
|
|
|
145
152
|
declare const toAikitTool: (def: AnyToolDef) => Message.Tool;
|
|
146
153
|
//#endregion
|
|
147
154
|
export { IToolProgress as _, RegisteredTool as a, make$1 as b, ToolImpl as c, make as d, provide as f, tool_d_exports as g, toProviderJsonSchema as h, ModelContent as i, define as l, toAikitTool as m, AnyToolImpl as n, ToolCallContext as o, register as p, Handler as r, ToolDef as s, AnyToolDef as t, implement as u, ToolProgress as v, noop as x, ToolProgressPartial as y };
|
|
148
|
-
//# sourceMappingURL=tool-
|
|
155
|
+
//# sourceMappingURL=tool-B7sWVmBt.d.mts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as RegisteredTool, i as ModelContent, t as AnyToolDef } from "./tool-
|
|
1
|
+
import { a as RegisteredTool, i as ModelContent, t as AnyToolDef } from "./tool-B7sWVmBt.mjs";
|
|
2
2
|
import { Effect, Schema } from "effect";
|
|
3
3
|
declare namespace tool_d_exports {
|
|
4
4
|
export { HookReturn, ToolAddOptions, ToolAfter, ToolAfterFn, ToolAfterResult, ToolBefore, ToolBeforeFn, ToolBeforeResult, ToolDefPatch, ToolRegistration, ToolRegistry, ToolResultContent };
|
|
@@ -284,4 +284,4 @@ interface ToolRegistry {
|
|
|
284
284
|
}
|
|
285
285
|
//#endregion
|
|
286
286
|
export { ToolAfterResult as a, ToolBeforeResult as c, ToolRegistry as d, ToolResultContent as f, ToolAfterFn as i, ToolDefPatch as l, ToolAddOptions as n, ToolBefore as o, tool_d_exports as p, ToolAfter as r, ToolBeforeFn as s, HookReturn as t, ToolRegistration as u };
|
|
287
|
-
//# sourceMappingURL=tool-
|
|
287
|
+
//# sourceMappingURL=tool-hXy4__zc.d.mts.map
|
package/tool.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as RegisteredTool, c as ToolImpl, d as make, f as provide, h as toProviderJsonSchema, i as ModelContent, l as define, m as toAikitTool, n as AnyToolImpl, o as ToolCallContext, p as register, r as Handler, s as ToolDef, t as AnyToolDef, u as implement } from "./tool-
|
|
1
|
+
import { a as RegisteredTool, c as ToolImpl, d as make, f as provide, h as toProviderJsonSchema, i as ModelContent, l as define, m as toAikitTool, n as AnyToolImpl, o as ToolCallContext, p as register, r as Handler, s as ToolDef, t as AnyToolDef, u as implement } from "./tool-B7sWVmBt.mjs";
|
|
2
2
|
export { AnyToolDef, AnyToolImpl, Handler, ModelContent, RegisteredTool, ToolCallContext, ToolDef, ToolImpl, define, implement, make, provide, register, toAikitTool, toProviderJsonSchema };
|
package/tool.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.mjs","names":[],"sources":["../../src/tool.ts"],"sourcesContent":["import type { Message } from \"@codeworksh/aikit\";\nimport { Effect, type Layer, Schema } from \"effect\";\nimport type { TSchema } from \"typebox\";\nimport { ToolExecutionError } from \"./tool/error.ts\";\nimport type { ToolProgress } from \"./tool/progress.ts\";\n\n/**\n * The tool definition + handler model.\n *\n * A tool definition is pure, serializable data: name, description, and Effect\n * Schema for parameters / success / failure. Execution is a separate `Handler`\n * — an `Effect` whose capability dependencies (e.g. `ToolShell`) live in its\n * requirements `R`, provided by a Layer at runtime. Separating the two is the\n * main testing win: assert on the definition as plain data, and run the handler\n * against a stub capability Layer.\n *\n * Effect Schema is the single source of truth. {@link toAikitTool} derives a\n * provider-safe JSON Schema object for the aikit wire view; the harness\n * decode/encodes arguments and results with Effect Schema natively (it does not\n * use aikit's Typebox validators).\n */\n\n/** What the model reads next turn (the `content` side of content/details). */\nexport type ModelContent = ReadonlyArray<Message.TextContent | Message.ImageContent>;\n\n/** Per-call metadata handed to a handler instead of positional args. */\nexport const ToolCallContext = Schema.Struct({\n\tcallID: Schema.String,\n\ttoolName: Schema.String,\n\trawArgs: Schema.Record(Schema.String, Schema.Unknown),\n});\nexport type ToolCallContext = typeof ToolCallContext.Type;\n\n/**\n * A pure tool definition. Parametrised over the *schema* instances so the\n * decoded parameter/success/failure types can be recovered via `[\"Type\"]`.\n */\nexport interface ToolDef<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\t/** Human-readable display label (kept from the previous `AgentTool`). */\n\treadonly label?: string;\n\t/**\n\t * A short one-line summary for compact tool listings (e.g. a system-prompt tool index),\n\t * distinct from the fuller `description`.\n\t */\n\treadonly promptSnippet?: string;\n\t/** Optional guideline bullets appended to the default system prompt Guidelines section when this tool is active. */\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n\treadonly parameters: Params;\n\t/**\n\t * How the provider constrains the generated arguments. `{ type: \"json_schema\", strict: \"prefer\" }` sends\n\t * `parameters` in strict mode where the provider can express it and falls back to non-strict otherwise.\n\t */\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\t/** Declared, model-visible failures (typed). Omit for tools that cannot fail expectedly. */\n\treadonly failure?: Failure;\n\t/** Render success for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\t/** Render an expected failure for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n}\n\n/** A handler: validated params + context → typed success or typed failure. */\nexport type Handler<Params extends Schema.Top, Success extends Schema.Top, Failure extends Schema.Top, R = never> = (\n\tparams: Params[\"Type\"],\n\tctx: ToolCallContext,\n) => Effect.Effect<Success[\"Type\"], Failure[\"Type\"], R>;\n\n/** A definition paired with its handler (the unit the executor runs). */\nexport interface ToolImpl<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n> {\n\treadonly definition: ToolDef<Name, Params, Success, Failure>;\n\treadonly handler: Handler<Params, Success, Failure, R>;\n}\n\n// Heterogeneous-collection aliases. `any` for the schema generics keeps handlers\n// of differing parameter types assignable into one array (the precise generics\n// live on the authoring helpers below).\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolDef = ToolDef<string, any, any, any>;\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolImpl<R = never> = ToolImpl<string, any, any, any, R>;\n\ninterface DefineInput<\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\treadonly label?: string;\n\treadonly promptSnippet?: string;\n\treadonly parameters: Params;\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\treadonly failure?: Failure;\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n}\n\n/** Define a pure tool (handler attached later via {@link implement} or a toolkit). */\nexport const define = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure>,\n): ToolDef<Name, Params, Success, Failure> => ({\n\t...input,\n});\n\n/** Attach a handler to an existing definition (the testable def/exec split). */\nexport const implement = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR = never,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, R>,\n): ToolImpl<Name, Params, Success, Failure, R> => ({ definition, handler });\n\n/** Sugar for the co-located case: a definition with its handler in one object. */\nexport const make = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure> & {\n\t\treadonly handler: Handler<Params, Success, Failure, R>;\n\t},\n): ToolImpl<Name, Params, Success, Failure, R> => {\n\tconst { handler, ...rest } = input;\n\treturn { definition: define(rest), handler };\n};\n\n/**\n * A tool ready to register: its capability requirements have been discharged, leaving only\n * the executor-provided {@link ToolProgress}. The registry and executor hold `RegisteredTool`s\n * and are non-generic (only `handle` is generic, over a progress sink's `RProgress`), so any\n * number of tools — built-in or\n * third-party/plugin — compose without a shared capability union\n */\nexport interface RegisteredTool {\n\treadonly definition: AnyToolDef;\n\treadonly handler: (\n\t\tparams: unknown,\n\t\tctx: ToolCallContext,\n\t) => Effect.Effect<unknown, ToolExecutionError, ToolProgress>;\n}\n\nconst toRegistered = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, ToolProgress>,\n): RegisteredTool => ({\n\tdefinition,\n\t// The executor decodes with `definition.parameters` before invoking this\n\t// erased handler, so restoring the authored parameter type is safe here.\n\thandler: (params, ctx) =>\n\t\thandler(params as Params[\"Type\"], ctx).pipe(\n\t\t\tEffect.mapError((cause) => new ToolExecutionError({ toolName: definition.name, cause })),\n\t\t),\n});\n\n/** Register a tool whose only requirement is the executor-provided progress service. */\nexport const register = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, ToolProgress>,\n): RegisteredTool => toRegistered(impl.definition, impl.handler);\n\n/**\n * Discharge a tool's capability requirements into a {@link RegisteredTool}, erasing its `R`\n * (the executor still provides `ToolProgress`). This is the registration boundary: a\n * plugin/third-party tool provides its own fully-resolved capability Layer here, so the\n * registry never has to unify anyone's `R`.\n */\nexport const provide = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, R | ToolProgress>,\n\tlayer: Layer.Layer<R>,\n): RegisteredTool =>\n\t// `Effect.provide` discharges `R`, leaving `ToolProgress`. TS can't simplify\n\t// `Exclude<ToolProgress, R>` for a generic `R`, so localize the cast before\n\t// crossing the registered-tool boundary.\n\ttoRegistered(impl.definition, ((params, ctx) => impl.handler(params, ctx).pipe(Effect.provide(layer))) as Handler<\n\t\tParams,\n\t\tSuccess,\n\t\tFailure,\n\t\tToolProgress\n\t>);\n\n/**\n * Derive a provider-safe JSON Schema object from an Effect Schema. This is the\n * single boundary that crosses into the provider wire; if a provider rejects a\n * construct, fix it here. Draft-07 inlines the root (no top-level `$ref`).\n */\nexport const toProviderJsonSchema = (schema: Schema.Top): Record<string, unknown> =>\n\tSchema.toStandardJSONSchemaV1(schema)[\"~standard\"].jsonSchema.input({ target: \"draft-07\" });\n\n/**\n * Build the aikit `Message.Tool` wire view from a definition. The derived JSON\n * Schema object satisfies aikit's `parameters` slot structurally at runtime; the\n * single localized cast keeps aikit untouched (decision 3-A).\n */\nexport const toAikitTool = (def: AnyToolDef): Message.Tool => ({\n\tname: def.name,\n\tdescription: def.description,\n\tparameters: toProviderJsonSchema(def.parameters) as unknown as TSchema,\n\t...(def.constrainedSampling === undefined ? {} : { constrainedSampling: def.constrainedSampling }),\n});\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,MAAa,kBAAkB,OAAO,OAAO;CAC5C,QAAQ,OAAO;CACf,UAAU,OAAO;CACjB,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;AACrD,CAAC;;AAoFD,MAAa,UAMZ,WAC8C,EAC9C,GAAG,MACJ;;AAGA,MAAa,aAOZ,YACA,aACkD;CAAE;CAAY;AAAQ;;AAGzE,MAAa,QAOZ,UAGiD;CACjD,MAAM,EAAE,SAAS,GAAG,SAAS;CAC7B,OAAO;EAAE,YAAY,OAAO,IAAI;EAAG;CAAQ;AAC5C;AAiBA,MAAM,gBAML,YACA,aACqB;CACrB;CAGA,UAAU,QAAQ,QACjB,QAAQ,QAA0B,GAAG,CAAC,CAAC,KACtC,OAAO,UAAU,UAAU,IAAI,mBAAmB;EAAE,UAAU,WAAW;EAAM;CAAM,CAAC,CAAC,CACxF;AACF;;AAGA,MAAa,YAMZ,SACoB,aAAa,KAAK,YAAY,KAAK,OAAO;;;;;;;AAQ/D,MAAa,WAOZ,MACA,UAKA,aAAa,KAAK,cAAc,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,CAAC,EAKnG;;;;;;AAOF,MAAa,wBAAwB,WACpC,OAAO,uBAAuB,MAAM,CAAC,CAAC,YAAY,CAAC,WAAW,MAAM,EAAE,QAAQ,WAAW,CAAC;;;;;;AAO3F,MAAa,eAAe,SAAmC;CAC9D,MAAM,IAAI;CACV,aAAa,IAAI;CACjB,YAAY,qBAAqB,IAAI,UAAU;CAC/C,GAAI,IAAI,wBAAwB,KAAA,IAAY,CAAC,IAAI,EAAE,qBAAqB,IAAI,oBAAoB;AACjG"}
|
|
1
|
+
{"version":3,"file":"tool.mjs","names":[],"sources":["../../src/tool.ts"],"sourcesContent":["import type { Message } from \"@codeworksh/aikit\";\nimport { Effect, type Layer, Schema } from \"effect\";\nimport type { TSchema } from \"typebox\";\nimport { ToolExecutionError } from \"./tool/error.ts\";\nimport type { ToolProgress } from \"./tool/progress.ts\";\n\n/**\n * The tool definition + handler model.\n *\n * A tool definition is pure, serializable data: name, description, and Effect\n * Schema for parameters / success / failure. Execution is a separate `Handler`\n * — an `Effect` whose capability dependencies (e.g. `ToolShell`) live in its\n * requirements `R`, provided by a Layer at runtime. Separating the two is the\n * main testing win: assert on the definition as plain data, and run the handler\n * against a stub capability Layer.\n *\n * Effect Schema is the single source of truth. {@link toAikitTool} derives a\n * provider-safe JSON Schema object for the aikit wire view; the harness\n * decode/encodes arguments and results with Effect Schema natively (it does not\n * use aikit's Typebox validators).\n */\n\n/** What the model reads next turn (the `content` side of content/details). */\nexport type ModelContent = ReadonlyArray<Message.TextContent | Message.ImageContent>;\n\n/** Per-call metadata handed to a handler instead of positional args. */\nexport const ToolCallContext = Schema.Struct({\n\tcallID: Schema.String,\n\ttoolName: Schema.String,\n\trawArgs: Schema.Record(Schema.String, Schema.Unknown),\n});\nexport type ToolCallContext = typeof ToolCallContext.Type;\n\n/**\n * A pure tool definition. Parametrised over the *schema* instances so the\n * decoded parameter/success/failure types can be recovered via `[\"Type\"]`.\n */\nexport interface ToolDef<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\t/** Human-readable display label (kept from the previous `AgentTool`). */\n\treadonly label?: string;\n\t/**\n\t * A short one-line summary for compact tool listings (e.g. a system-prompt tool index),\n\t * distinct from the fuller `description`.\n\t */\n\treadonly promptSnippet?: string;\n\t/** Optional guideline bullets appended to the default system prompt Guidelines section when this tool is active. */\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n\treadonly parameters: Params;\n\t/**\n\t * How the provider constrains the generated arguments. `{ type: \"json_schema\", strict: \"prefer\" }` sends\n\t * `parameters` in strict mode where the provider can express it and falls back to non-strict otherwise.\n\t */\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\t/** Declared, model-visible failures (typed). Omit for tools that cannot fail expectedly. */\n\treadonly failure?: Failure;\n\t/** Render success for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\t/** Render an expected failure for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n\t/**\n\t * The `details` kept with a success, for UIs and programmatic consumers. Omit → the encoded\n\t * success. Set it when `encodeContent` already carries the payload, so it is not stored twice.\n\t */\n\treadonly encodeDetails?: (success: Success[\"Type\"]) => unknown;\n}\n\n/** A handler: validated params + context → typed success or typed failure. */\nexport type Handler<Params extends Schema.Top, Success extends Schema.Top, Failure extends Schema.Top, R = never> = (\n\tparams: Params[\"Type\"],\n\tctx: ToolCallContext,\n) => Effect.Effect<Success[\"Type\"], Failure[\"Type\"], R>;\n\n/** A definition paired with its handler (the unit the executor runs). */\nexport interface ToolImpl<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n> {\n\treadonly definition: ToolDef<Name, Params, Success, Failure>;\n\treadonly handler: Handler<Params, Success, Failure, R>;\n}\n\n// Heterogeneous-collection aliases. `any` for the schema generics keeps handlers\n// of differing parameter types assignable into one array (the precise generics\n// live on the authoring helpers below).\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolDef = ToolDef<string, any, any, any>;\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolImpl<R = never> = ToolImpl<string, any, any, any, R>;\n\ninterface DefineInput<\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\treadonly label?: string;\n\treadonly promptSnippet?: string;\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n\treadonly parameters: Params;\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\treadonly failure?: Failure;\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n\treadonly encodeDetails?: (success: Success[\"Type\"]) => unknown;\n}\n\n/** Define a pure tool (handler attached later via {@link implement} or a toolkit). */\nexport const define = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure>,\n): ToolDef<Name, Params, Success, Failure> => ({\n\t...input,\n});\n\n/** Attach a handler to an existing definition (the testable def/exec split). */\nexport const implement = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR = never,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, R>,\n): ToolImpl<Name, Params, Success, Failure, R> => ({ definition, handler });\n\n/** Sugar for the co-located case: a definition with its handler in one object. */\nexport const make = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure> & {\n\t\treadonly handler: Handler<Params, Success, Failure, R>;\n\t},\n): ToolImpl<Name, Params, Success, Failure, R> => {\n\tconst { handler, ...rest } = input;\n\treturn { definition: define(rest), handler };\n};\n\n/**\n * A tool ready to register: its capability requirements have been discharged, leaving only\n * the executor-provided {@link ToolProgress}. The registry and executor hold `RegisteredTool`s\n * and are non-generic (only `handle` is generic, over a progress sink's `RProgress`), so any\n * number of tools — built-in or\n * third-party/plugin — compose without a shared capability union\n */\nexport interface RegisteredTool {\n\treadonly definition: AnyToolDef;\n\treadonly handler: (\n\t\tparams: unknown,\n\t\tctx: ToolCallContext,\n\t) => Effect.Effect<unknown, ToolExecutionError, ToolProgress>;\n}\n\nconst toRegistered = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, ToolProgress>,\n): RegisteredTool => ({\n\tdefinition,\n\t// The executor decodes with `definition.parameters` before invoking this\n\t// erased handler, so restoring the authored parameter type is safe here.\n\thandler: (params, ctx) =>\n\t\thandler(params as Params[\"Type\"], ctx).pipe(\n\t\t\tEffect.mapError((cause) => new ToolExecutionError({ toolName: definition.name, cause })),\n\t\t),\n});\n\n/** Register a tool whose only requirement is the executor-provided progress service. */\nexport const register = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, ToolProgress>,\n): RegisteredTool => toRegistered(impl.definition, impl.handler);\n\n/**\n * Discharge a tool's capability requirements into a {@link RegisteredTool}, erasing its `R`\n * (the executor still provides `ToolProgress`). This is the registration boundary: a\n * plugin/third-party tool provides its own fully-resolved capability Layer here, so the\n * registry never has to unify anyone's `R`.\n */\nexport const provide = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, R | ToolProgress>,\n\tlayer: Layer.Layer<R>,\n): RegisteredTool =>\n\t// `Effect.provide` discharges `R`, leaving `ToolProgress`. TS can't simplify\n\t// `Exclude<ToolProgress, R>` for a generic `R`, so localize the cast before\n\t// crossing the registered-tool boundary.\n\ttoRegistered(impl.definition, ((params, ctx) => impl.handler(params, ctx).pipe(Effect.provide(layer))) as Handler<\n\t\tParams,\n\t\tSuccess,\n\t\tFailure,\n\t\tToolProgress\n\t>);\n\n/**\n * Derive a provider-safe JSON Schema object from an Effect Schema. This is the\n * single boundary that crosses into the provider wire; if a provider rejects a\n * construct, fix it here. Draft-07 inlines the root (no top-level `$ref`).\n */\nexport const toProviderJsonSchema = (schema: Schema.Top): Record<string, unknown> =>\n\tSchema.toStandardJSONSchemaV1(schema)[\"~standard\"].jsonSchema.input({ target: \"draft-07\" });\n\n/**\n * Build the aikit `Message.Tool` wire view from a definition. The derived JSON\n * Schema object satisfies aikit's `parameters` slot structurally at runtime; the\n * single localized cast keeps aikit untouched (decision 3-A).\n */\nexport const toAikitTool = (def: AnyToolDef): Message.Tool => ({\n\tname: def.name,\n\tdescription: def.description,\n\tparameters: toProviderJsonSchema(def.parameters) as unknown as TSchema,\n\t...(def.constrainedSampling === undefined ? {} : { constrainedSampling: def.constrainedSampling }),\n});\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,MAAa,kBAAkB,OAAO,OAAO;CAC5C,QAAQ,OAAO;CACf,UAAU,OAAO;CACjB,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;AACrD,CAAC;;AA2FD,MAAa,UAMZ,WAC8C,EAC9C,GAAG,MACJ;;AAGA,MAAa,aAOZ,YACA,aACkD;CAAE;CAAY;AAAQ;;AAGzE,MAAa,QAOZ,UAGiD;CACjD,MAAM,EAAE,SAAS,GAAG,SAAS;CAC7B,OAAO;EAAE,YAAY,OAAO,IAAI;EAAG;CAAQ;AAC5C;AAiBA,MAAM,gBAML,YACA,aACqB;CACrB;CAGA,UAAU,QAAQ,QACjB,QAAQ,QAA0B,GAAG,CAAC,CAAC,KACtC,OAAO,UAAU,UAAU,IAAI,mBAAmB;EAAE,UAAU,WAAW;EAAM;CAAM,CAAC,CAAC,CACxF;AACF;;AAGA,MAAa,YAMZ,SACoB,aAAa,KAAK,YAAY,KAAK,OAAO;;;;;;;AAQ/D,MAAa,WAOZ,MACA,UAKA,aAAa,KAAK,cAAc,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,CAAC,EAKnG;;;;;;AAOF,MAAa,wBAAwB,WACpC,OAAO,uBAAuB,MAAM,CAAC,CAAC,YAAY,CAAC,WAAW,MAAM,EAAE,QAAQ,WAAW,CAAC;;;;;;AAO3F,MAAa,eAAe,SAAmC;CAC9D,MAAM,IAAI;CACV,aAAa,IAAI;CACjB,YAAY,qBAAqB,IAAI,UAAU;CAC/C,GAAI,IAAI,wBAAwB,KAAA,IAAY,CAAC,IAAI,EAAE,qBAAqB,IAAI,oBAAoB;AACjG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem-BFCKzgND.mjs","names":["validateScan"],"sources":["../../src/sandbox/scan.ts","../../src/sandbox/filesystem.ts"],"sourcesContent":["/**\n * Bounded line reads: one pass over a file that returns a window of its lines\n * without ever holding more than that window.\n *\n * Lines are the file split on `\\n`, where a trailing newline ends the last line\n * rather than starting an empty one: `\"\"` has 0 lines, `\"a\"` and `\"a\\n\"` have 1,\n * `\"a\\n\\n\"` has 2. A UTF-8 byte-order mark at the start of the file is not part\n * of the first line. Line lengths are in bytes.\n *\n * Two implementations share these rules, and a backend uses whichever fits:\n * {@link LineScanner} over a byte stream, or {@link script} run inside the\n * sandbox so only the window crosses the network.\n */\n\nexport interface LineScanOptions {\n\t/** First selected line, 0-based. */\n\treadonly startLine: number;\n\t/** End of the selection, exclusive; absent selects to the end of the file. */\n\treadonly endLine?: number;\n\t/** Most UTF-8 bytes of selected text to return; selection stops at the last whole line that fits. */\n\treadonly maxBytes: number;\n}\n\nexport interface LineScan {\n\t/**\n\t * The selected whole lines that fit `maxBytes`, joined with `\\n`. Invalid\n\t * UTF-8 becomes U+FFFD; how many per bad sequence depends on the decoder of\n\t * the backend's transport.\n\t */\n\treadonly text: string;\n\t/** Lines in {@link text}. */\n\treadonly lines: number;\n\t/** Lines in the whole file. */\n\treadonly totalLines: number;\n\t/** Bytes in the whole file, byte-order mark included. */\n\treadonly totalBytes: number;\n\t/**\n\t * Bytes of the first selected line, 0 when nothing is selected. Larger than\n\t * `maxBytes` exactly when that line alone does not fit, and `text` is empty.\n\t */\n\treadonly firstLineBytes: number;\n}\n\n/** A defect, not a file error: callers derive these from already-validated input. */\nexport const validate = (options: LineScanOptions): void => {\n\tconst { startLine, endLine, maxBytes } = options;\n\tif (!Number.isSafeInteger(startLine) || startLine < 0) throw new RangeError(`Invalid startLine: ${startLine}`);\n\tif (endLine !== undefined && (!Number.isSafeInteger(endLine) || endLine <= startLine))\n\t\tthrow new RangeError(`Invalid endLine: ${endLine}`);\n\tif (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) throw new RangeError(`Invalid maxBytes: ${maxBytes}`);\n};\n\nconst NEWLINE = 0x0a;\nconst BOM = [0xef, 0xbb, 0xbf] as const;\n\n/**\n * Computes a {@link LineScan} from a file's bytes fed in order, in memory\n * bounded by `maxBytes`. Feed at most the file size observed when the read\n * started, so a file that keeps growing cannot keep the scan going.\n */\nexport class LineScanner {\n\tprivate readonly start: number;\n\tprivate readonly end: number;\n\tprivate readonly maxBytes: number;\n\t// Only a mark at the very start of the file is dropped, and that happens on\n\t// the bytes; one starting a later line is text.\n\tprivate readonly decoder = new TextDecoder(\"utf-8\", { ignoreBOM: true });\n\n\t/** The first bytes, held until it is known whether they are a byte-order mark. */\n\tprivate head: Array<number> | undefined = [];\n\tprivate totalBytes = 0;\n\tprivate line = 0;\n\tprivate lineLength = 0;\n\tprivate lineOpen = false;\n\t/** The current line's bytes, kept only while it is selected and could still fit. */\n\tprivate pieces: Array<Uint8Array> = [];\n\tprivate selected: Array<Uint8Array> = [];\n\tprivate selectedBytes = 0;\n\tprivate firstLineBytes = 0;\n\tprivate full = false;\n\n\tconstructor(options: LineScanOptions) {\n\t\tvalidate(options);\n\t\tthis.start = options.startLine;\n\t\tthis.end = options.endLine ?? Number.POSITIVE_INFINITY;\n\t\tthis.maxBytes = options.maxBytes;\n\t}\n\n\tpush(chunk: Uint8Array): void {\n\t\tthis.totalBytes += chunk.length;\n\t\tif (this.head !== undefined) {\n\t\t\tconst take = Math.min(BOM.length - this.head.length, chunk.length);\n\t\t\tthis.head.push(...chunk.subarray(0, take));\n\t\t\tif (this.head.length < BOM.length) return;\n\t\t\tthis.releaseHead();\n\t\t\tchunk = chunk.subarray(take);\n\t\t}\n\t\tthis.scan(chunk);\n\t}\n\n\tfinish(): LineScan {\n\t\tif (this.head !== undefined) this.releaseHead();\n\t\tif (this.lineOpen) this.endLine();\n\t\tconst text = this.selected.map((line) => this.decoder.decode(line)).join(\"\\n\");\n\t\treturn {\n\t\t\ttext,\n\t\t\tlines: this.selected.length,\n\t\t\ttotalLines: this.line,\n\t\t\ttotalBytes: this.totalBytes,\n\t\t\tfirstLineBytes: this.firstLineBytes,\n\t\t};\n\t}\n\n\tprivate releaseHead(): void {\n\t\tconst head = Uint8Array.from(this.head ?? []);\n\t\tthis.head = undefined;\n\t\tconst bom = head.length === BOM.length && BOM.every((byte, index) => head[index] === byte);\n\t\tif (!bom) this.scan(head);\n\t}\n\n\tprivate scan(chunk: Uint8Array): void {\n\t\tlet from = 0;\n\t\twhile (from < chunk.length) {\n\t\t\tconst newline = chunk.indexOf(NEWLINE, from);\n\t\t\tconst to = newline === -1 ? chunk.length : newline;\n\t\t\tthis.append(chunk.subarray(from, to));\n\t\t\tif (newline === -1) return;\n\t\t\tthis.endLine();\n\t\t\tfrom = newline + 1;\n\t\t}\n\t}\n\n\tprivate isSelected(): boolean {\n\t\treturn !this.full && this.line >= this.start && this.line < this.end;\n\t}\n\n\tprivate append(bytes: Uint8Array): void {\n\t\tif (bytes.length === 0) {\n\t\t\tthis.lineOpen = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.lineOpen = true;\n\t\t// Past `maxBytes` the line cannot fit, so its bytes are only counted. Copied,\n\t\t// not sliced: a Node `Buffer` slice is a view the reader may overwrite.\n\t\tif (this.isSelected() && this.lineLength + bytes.length <= this.maxBytes) this.pieces.push(new Uint8Array(bytes));\n\t\tthis.lineLength += bytes.length;\n\t}\n\n\tprivate endLine(): void {\n\t\tif (this.isSelected()) {\n\t\t\tconst first = this.selected.length === 0;\n\t\t\tif (first) this.firstLineBytes = this.lineLength;\n\t\t\tconst added = first ? this.lineLength : this.lineLength + 1;\n\t\t\tif (this.selectedBytes + added > this.maxBytes) this.full = true;\n\t\t\telse {\n\t\t\t\tthis.selected.push(concat(this.pieces, this.lineLength));\n\t\t\t\tthis.selectedBytes += added;\n\t\t\t}\n\t\t}\n\t\tthis.pieces = [];\n\t\tthis.lineLength = 0;\n\t\tthis.lineOpen = false;\n\t\tthis.line++;\n\t}\n}\n\nconst concat = (pieces: ReadonlyArray<Uint8Array>, length: number): Uint8Array => {\n\tif (pieces.length === 1) return pieces[0]!;\n\tconst out = new Uint8Array(length);\n\tlet offset = 0;\n\tfor (const piece of pieces) {\n\t\tout.set(piece, offset);\n\t\toffset += piece.length;\n\t}\n\treturn out;\n};\n\n/**\n * {@link LineScanner} as a POSIX shell script, for backends that only expose a\n * process API. Run as `sh -c <script> _ <path> <startLine> <endLine|-1> <maxBytes>`.\n * The whole file is read inside the sandbox; only the window is printed, after a\n * header line `<lines> <totalLines> <totalBytes> <firstLineBytes>` and before a\n * closing `|` — see {@link parse}.\n * Exits 2 when the path does not exist.\n */\nexport const script = [\n\t'[ -e \"$1\" ] || exit 2',\n\t// Arithmetic expansion drops the padding some `wc` builds print.\n\t'size=$(($(wc -c < \"$1\"))) || exit 1',\n\t// `C` makes awk's `length` count bytes; `head -c` bounds a file that is still growing.\n\t'head -c \"$size\" -- \"$1\" | LC_ALL=C awk -v s=\"$2\" -v e=\"$3\" -v m=\"$4\" -v size=\"$size\" \\'',\n\t// A file that is only a byte-order mark has no lines; anything after one keeps its own.\n\t'NR == 1 && $0 == \"\\\\357\\\\273\\\\277\" && size == 3 { exit }',\n\t'NR == 1 && substr($0, 1, 3) == \"\\\\357\\\\273\\\\277\" { $0 = substr($0, 4) }',\n\t\"{ total = NR }\",\n\t\"NR > s && (e < 0 || NR <= e) && !full {\",\n\t\" len = length($0)\",\n\t\" added = lines == 0 ? len : len + 1\",\n\t\" if (lines == 0 && !seen) { seen = 1; first = len }\",\n\t\" if (bytes + added > m) { full = 1; next }\",\n\t' out = lines == 0 ? $0 : out \"\\\\n\" $0',\n\t\" bytes += added; lines++\",\n\t\"}\",\n\t// The trailing `|` survives a transport that trims trailing whitespace off stdout.\n\t// `%.0f`, not `%d`: some mawk builds clamp `%d` to a 32-bit integer.\n\t'END { printf \"%.0f %.0f %.0f %.0f\\\\n%s|\", lines, total, size, first, out }',\n\t\"'\",\n].join(\"\\n\");\n\n/** Arguments for {@link script} after the path. */\nexport const scriptArgs = (options: LineScanOptions): Array<string> => {\n\tvalidate(options);\n\treturn [String(options.startLine), String(options.endLine ?? -1), String(options.maxBytes)];\n};\n\n/** Read {@link script}'s output. */\nexport const parse = (stdout: string): LineScan => {\n\tconst body = stdout.trimEnd();\n\tconst newline = body.indexOf(\"\\n\");\n\tconst header = (newline === -1 ? \"\" : body.slice(0, newline)).trim().split(/\\s+/).map(Number);\n\tconst [lines, totalLines, totalBytes, firstLineBytes] = header;\n\tif (!body.endsWith(\"|\") || header.length !== 4 || header.some((value) => !Number.isSafeInteger(value)))\n\t\tthrow new Error(`Unexpected scanLines output: ${stdout.slice(0, 200)}`);\n\treturn {\n\t\ttext: body.slice(newline + 1, -1),\n\t\tlines: lines!,\n\t\ttotalLines: totalLines!,\n\t\ttotalBytes: totalBytes!,\n\t\tfirstLineBytes: firstLineBytes!,\n\t};\n};\n\nexport interface ShellRun {\n\treadonly exitCode: number;\n\treadonly stdout: string;\n\treadonly stderr?: string;\n}\n\n/**\n * `Provider.scanLines` for a backend that runs an argument vector and collects\n * its output: runs {@link script} in the sandbox and reads the result. A missing\n * path rejects with `ENOENT`, the shape `isNotFoundError` recognises.\n */\nexport const viaShell =\n\t(run: (argv: ReadonlyArray<string>) => Promise<ShellRun>) =>\n\t// oxlint-disable-next-line effecttsgo/async-function -- the Provider contract is Promise-based\n\tasync (path: string, options: LineScanOptions): Promise<LineScan> => {\n\t\tconst result = await run([\"sh\", \"-c\", script, \"_\", path, ...scriptArgs(options)]);\n\t\tif (result.exitCode === 2)\n\t\t\tthrow Object.assign(new Error(`ENOENT: no such file or directory, scanLines '${path}'`), { code: \"ENOENT\" });\n\t\tif (result.exitCode !== 0)\n\t\t\tthrow new Error(`scanLines failed (exit ${result.exitCode}): ${(result.stderr ?? result.stdout).trim()}`);\n\t\treturn parse(result.stdout);\n\t};\n","import { Context, Effect, Schema } from \"effect\";\nimport { posix } from \"../posix.ts\";\nimport { type LineScan, type LineScanOptions, validate as validateScan } from \"./scan.ts\";\n\nexport type { LineScan, LineScanOptions } from \"./scan.ts\";\n/** The shared line-scan rules: `LineScanner` for byte streams, `script` for shell-only backends. */\nexport * as Scan from \"./scan.ts\";\n\n/**\n * The runtime filesystem contract, independent of any backend.\n *\n * Two surfaces, deliberately:\n * - {@link Provider} is what a backend implements — plain promises that reject,\n * matching every SDK we wrap.\n * - {@link Interface} is what the harness consumes — Effect with a typed error\n * channel and tracing spans. {@link fromProvider} bridges the two exactly\n * once, so no consumer ever writes `Effect.tryPromise` against a filesystem.\n *\n * Implementations:\n * - Local:\n * implement it over a VFS (`./local`);\n * local filesystem use OS primitives; hence have broader filesytem capabilities.\n *\n * - Remote:\n * implement it over a provider (`./remote`).\n * remote filesytems depends on the interface provided by the remote provider; hence can have limited filesytem capabilities.\n *\n * `isFile`/`isDirectory` are required booleans; size, mtime, and isSymbolicLink are omitted when the\n * backend cannot report them — never fabricated.\n *\n * **Paths are POSIX, and the harness is Unix-only (for now!).** Every path uses `/`\n * separators on both the host and inside a sandbox — Windows is not supported,\n * so no translation layer exists. Consumers must use the shared Effect POSIX\n * path implementation, never the platform default, or a host running the harness would\n * impose its own flavour on a remote sandbox's paths. Relative paths resolve\n * against the backend's configured `cwd`.\n */\n\nexport class OperationUnsupportedError extends Schema.TaggedError<OperationUnsupportedError>()(\n\t\"OperationUnsupportedError\",\n\t{\n\t\toperation: Schema.String,\n\t\tmessage: Schema.String,\n\t},\n) {}\n\n/** A backend operation failed. `cause` carries the provider's own rejection. */\nexport class FileSystemError extends Schema.TaggedError<FileSystemError>()(\"SandboxFileSystemError\", {\n\tmethod: Schema.String,\n\tpath: Schema.String,\n\tcause: Schema.optional(Schema.Defect()),\n}) {}\n\nexport interface FileStat {\n\treadonly isFile: boolean;\n\treadonly isDirectory: boolean;\n\treadonly isSymbolicLink?: boolean;\n\treadonly size?: number;\n\treadonly mtime?: Date;\n}\n\nexport interface RmOptions {\n\treadonly recursive?: boolean;\n\treadonly force?: boolean;\n}\n\n/** Whether a provider failure means the path itself is definitively absent. */\nexport const isNotFoundError = (cause: unknown) => {\n\tconst code = (cause as NodeJS.ErrnoException | undefined)?.code;\n\treturn code === \"ENOENT\" || code === \"ENOTDIR\";\n};\n\n/**\n * Shell forms of `realpath` for backends that only expose a process API. Run as\n * `sh -c <script> _ <path>`, trying each in turn. `realpath -e` (coreutils)\n * resolves every component, a symlinked file included, and fails on a missing\n * path. Where it is absent, `pwd -P` is the portable primitive: directories\n * resolve directly, anything else resolves its parent and keeps the final name\n * as given — so a symlinked *file* stays unresolved there.\n */\nexport const realpathScripts = [\n\t'realpath -e -- \"$1\"',\n\t'cd -- \"$1\" && pwd -P',\n\t'cd -- \"$(dirname -- \"$1\")\" && printf \\'%s/%s\\' \"$(pwd -P)\" \"$(basename -- \"$1\")\"',\n] as const;\n\n/**\n * The backend-facing contract. Backends author plain promises and let them\n * reject; {@link fromProvider} turns rejections into typed failures.\n */\nexport interface Provider {\n\treadonly readFile: (path: string) => Promise<string>;\n\treadonly readFileBuffer: (path: string) => Promise<Uint8Array>;\n\t/**\n\t * Write the file. Parents may be missing — do not create them here;\n\t * {@link fromProvider} owns that guarantee for every backend.\n\t */\n\treadonly writeFile: (path: string, content: string | Uint8Array) => Promise<void>;\n\treadonly stat: (path: string) => Promise<FileStat>;\n\treadonly readdir: (path: string) => Promise<string[]>;\n\treadonly exists: (path: string) => Promise<boolean>;\n\treadonly mkdir: (path: string, options?: { recursive?: boolean }) => Promise<void>;\n\treadonly rm: (path: string, options?: RmOptions) => Promise<void>;\n\t/** Canonical absolute path with symlinks resolved; rejects when the path does not exist. */\n\treadonly realpath: (path: string) => Promise<string>;\n\t/**\n\t * A window of the file's lines, by the rules in `Scan`. Bounded: never\n\t * returns, or holds, more than the window. A remote backend runs the scan\n\t * inside the sandbox (`Scan.script`) so only the window crosses the network.\n\t */\n\treadonly scanLines: (path: string, options: LineScanOptions) => Promise<LineScan>;\n\t/**\n\t * Metadata for the directory entry itself rather than a symlink's target.\n\t * Optional: a backend whose `stat` has mixed symlink semantics implements it\n\t * so symlink identity is asked for explicitly, never inferred.\n\t */\n\treadonly lstat?: (path: string) => Promise<FileStat>;\n}\n\n/**\n * The consumer-facing contract. `exists` distinguishes \"absent\" from \"could not\n * tell\": a backend failure is a typed failure, not `false`, so a caller acting\n * on absence never acts on a network blip. Use `SandboxFs.existsOrFalse` where\n * a best-effort answer really is wanted.\n */\nexport interface Interface {\n\treadonly readFile: (path: string) => Effect.Effect<string, FileSystemError>;\n\treadonly readFileBuffer: (path: string) => Effect.Effect<Uint8Array, FileSystemError>;\n\t/** Creates missing parent directories, on every backend. */\n\treadonly writeFile: (path: string, content: string | Uint8Array) => Effect.Effect<void, FileSystemError>;\n\treadonly stat: (path: string) => Effect.Effect<FileStat, FileSystemError>;\n\treadonly readdir: (path: string) => Effect.Effect<string[], FileSystemError>;\n\treadonly exists: (path: string) => Effect.Effect<boolean, FileSystemError>;\n\treadonly mkdir: (path: string, options?: { recursive?: boolean }) => Effect.Effect<void, FileSystemError>;\n\treadonly rm: (path: string, options?: RmOptions) => Effect.Effect<void, FileSystemError | OperationUnsupportedError>;\n\t/** Canonical absolute path with symlinks resolved; fails when the path does not exist. */\n\treadonly realpath: (path: string) => Effect.Effect<string, FileSystemError>;\n\t/** A bounded window of the file's lines; see `Scan`. Invalid options are a defect. */\n\treadonly scanLines: (path: string, options: LineScanOptions) => Effect.Effect<LineScan, FileSystemError>;\n\t// `lstat` is present only when the backend supports it; check before calling.\n\treadonly lstat?: (path: string) => Effect.Effect<FileStat, FileSystemError>;\n}\n\n/** The runtime filesystem service — the live {@link Interface} for the active sandbox. */\nexport class Service extends Context.Service<Service, Interface>()(\"@codeworksh/plugin/sandbox/filesystem/Service\") {}\n\n/**\n * Reject `rm` options a provider does not implement, before any mutation. Only\n * `recursive` and `force` are part of the contract; anything else is refused\n * loudly rather than silently ignored.\n */\nexport const validateRmOptions = (\n\toptions: RmOptions | undefined,\n\toperation = \"rm\",\n): Effect.Effect<void, OperationUnsupportedError> =>\n\tEffect.suspend(() => {\n\t\tfor (const option of Object.keys((options ?? {}) as Record<string, unknown>)) {\n\t\t\tif (option === \"recursive\" || option === \"force\") continue;\n\t\t\treturn Effect.fail(new OperationUnsupportedError({ operation, message: `Unsupported rm option: ${option}` }));\n\t\t}\n\t\treturn Effect.void;\n\t});\n\n/**\n * Lift a {@link Provider} into the runtime {@link Interface}: one place that\n * converts rejections into {@link FileSystemError}, validates `rm` options,\n * creates missing parents on write, and names a tracing span per operation.\n */\nexport const fromProvider = (provider: Provider): Interface => {\n\tconst attempt = <A>(method: string, path: string, run: () => Promise<A>) =>\n\t\tEffect.tryPromise({ try: run, catch: (cause) => new FileSystemError({ method, path, cause }) });\n\n\t// The parent-creation guarantee, installed once for every backend instead of\n\t// re-implemented per provider: anything that reaches `Interface` reaches it\n\t// through here, so a backend cannot forget it.\n\t//\n\t// Lazy by design — try the write first, so the happy path stays a single call\n\t// and no remote backend pays a round-trip per write. A failure is usually a\n\t// missing parent, so create it and retry once. The mkdir's own error is\n\t// dropped on purpose: when the write failed for some other reason (EACCES,\n\t// EROFS, a dropped connection), the retry reproduces it, and *that* is the\n\t// failure the caller must see rather than a misleading mkdir error standing\n\t// in for it.\n\tconst writeCreatingParents = (path: string, content: string | Uint8Array) => {\n\t\tconst write = attempt(\"writeFile\", path, () => provider.writeFile(path, content));\n\t\tconst parent = posix.dirname(path);\n\t\treturn write.pipe(\n\t\t\tEffect.catch(() =>\n\t\t\t\tattempt(\"mkdir\", parent, () => provider.mkdir(parent, { recursive: true })).pipe(\n\t\t\t\t\tEffect.ignore,\n\t\t\t\t\tEffect.andThen(write),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t};\n\n\treturn {\n\t\treadFile: Effect.fn(\"SandboxFileSystem.readFile\")((path: string) =>\n\t\t\tattempt(\"readFile\", path, () => provider.readFile(path)),\n\t\t),\n\t\treadFileBuffer: Effect.fn(\"SandboxFileSystem.readFileBuffer\")((path: string) =>\n\t\t\tattempt(\"readFileBuffer\", path, () => provider.readFileBuffer(path)),\n\t\t),\n\t\twriteFile: Effect.fn(\"SandboxFileSystem.writeFile\")(writeCreatingParents),\n\t\tstat: Effect.fn(\"SandboxFileSystem.stat\")((path: string) => attempt(\"stat\", path, () => provider.stat(path))),\n\t\t// carried through only when the backend actually implements it\n\t\t...(provider.lstat === undefined\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tlstat: Effect.fn(\"SandboxFileSystem.lstat\")((path: string) =>\n\t\t\t\t\t\tattempt(\"lstat\", path, () => provider.lstat!(path)),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\treaddir: Effect.fn(\"SandboxFileSystem.readdir\")((path: string) =>\n\t\t\tattempt(\"readdir\", path, () => provider.readdir(path)),\n\t\t),\n\t\t// A backend that cannot answer fails; it does not report \"absent\". A\n\t\t// caller acting on absence — deleting a record, say — must not be told\n\t\t// the path is gone because a token expired or a request timed out.\n\t\texists: Effect.fn(\"SandboxFileSystem.exists\")((path: string) =>\n\t\t\tattempt(\"exists\", path, () => provider.exists(path)),\n\t\t),\n\t\tmkdir: Effect.fn(\"SandboxFileSystem.mkdir\")((path: string, options?: { recursive?: boolean }) =>\n\t\t\tattempt(\"mkdir\", path, () => provider.mkdir(path, options)),\n\t\t),\n\t\trm: Effect.fn(\"SandboxFileSystem.rm\")((path: string, options?: RmOptions) =>\n\t\t\tvalidateRmOptions(options).pipe(Effect.andThen(attempt(\"rm\", path, () => provider.rm(path, options)))),\n\t\t),\n\t\trealpath: Effect.fn(\"SandboxFileSystem.realpath\")((path: string) =>\n\t\t\tattempt(\"realpath\", path, () => provider.realpath(path)),\n\t\t),\n\t\tscanLines: Effect.fn(\"SandboxFileSystem.scanLines\")((path: string, options: LineScanOptions) =>\n\t\t\tEffect.sync(() => validateScan(options)).pipe(\n\t\t\t\tEffect.andThen(attempt(\"scanLines\", path, () => provider.scanLines(path, options))),\n\t\t\t),\n\t\t),\n\t};\n};\n\n/**\n * Bind a cwd-neutral filesystem to one mount's working directory.\n *\n * The counterpart of `Shell.withCwd`, and the reason relative paths mean the\n * same thing to both: a shared transport stays rooted at the namespace root, so\n * resolution happens here, per mount, rather than inside a VFS whose `chdir` is\n * global state two mounts would fight over.\n */\nexport const withCwd = (fs: Interface, cwd: string): Interface => {\n\tconst at = (path: string) => posix.resolve(cwd, path);\n\treturn {\n\t\treadFile: (path) => fs.readFile(at(path)),\n\t\treadFileBuffer: (path) => fs.readFileBuffer(at(path)),\n\t\twriteFile: (path, content) => fs.writeFile(at(path), content),\n\t\tstat: (path) => fs.stat(at(path)),\n\t\treaddir: (path) => fs.readdir(at(path)),\n\t\texists: (path) => fs.exists(at(path)),\n\t\tmkdir: (path, options) => fs.mkdir(at(path), options),\n\t\trm: (path, options) => fs.rm(at(path), options),\n\t\trealpath: (path) => fs.realpath(at(path)),\n\t\tscanLines: (path, options) => fs.scanLines(at(path), options),\n\t\t// carried through only when the backend implements it, so a caller can\n\t\t// still detect absence by checking the property\n\t\t...(fs.lstat === undefined ? {} : { lstat: (path: string) => fs.lstat!(at(path)) }),\n\t};\n};\n\nexport * as SandboxFileSystem from \"./filesystem.ts\";\n"],"mappings":"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"}
|