@codeworksh/harness 0.0.1-dev.20260917115353 → 0.0.1-dev.20260922135939

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.
@@ -1,770 +0,0 @@
1
- import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
- import { Context, DateTime, Effect, Layer, Option, Path, Schema, SchemaGetter } from "effect";
3
- import { uuidv7 } from "uuidv7";
4
- import { Message } from "@codeworksh/aikit";
5
- import TypeBoxSchema from "typebox/schema";
6
- //#region src/schema.ts
7
- const aikitValidators = /* @__PURE__ */ new WeakMap();
8
- const aikitValidatorFor = (schema) => {
9
- const cached = aikitValidators.get(schema);
10
- if (cached !== void 0) return cached;
11
- const compiled = TypeBoxSchema.Compile(schema);
12
- aikitValidators.set(schema, compiled);
13
- return compiled;
14
- };
15
- const aikitErrorPath = (error) => {
16
- if (error.instancePath) return error.instancePath.substring(1);
17
- const required = error.params?.requiredProperties;
18
- return Array.isArray(required) ? required.join(", ") : "root";
19
- };
20
- const validateAikitSchema = (schema, value, label) => {
21
- const validator = aikitValidatorFor(schema);
22
- if (validator.Check(value)) return value;
23
- const [, issues] = validator.Errors(value);
24
- const details = issues.map((issue) => ` - ${aikitErrorPath(issue)}: ${issue.message}`).join("\n") || "unknown error";
25
- throw new Error(`validation failed for ${label}\n${details}`);
26
- };
27
- /** Validate an aikit message without coercing or rewriting durable data. */
28
- const validateAikitMessage = (value, label) => validateAikitSchema(Message.MessageSchema, value, label);
29
- const validateAikitUserMessage = (value, label) => validateAikitSchema(Message.UserMessageSchema, value, label);
30
- const validateAikitAssistantMessage = (value, label) => validateAikitSchema(Message.AssistantMessageSchema, value, label);
31
- const validateAikitToolCallTerminalPart = (value, label) => validateAikitSchema(Message.ToolCallTerminalPartSchema, value, label);
32
- const isAikitAssistantMessage = (value) => aikitValidatorFor(Message.AssistantMessageSchema).Check(value);
33
- const isAikitToolCallTerminalPart = (value) => aikitValidatorFor(Message.ToolCallTerminalPartSchema).Check(value);
34
- Schema.Int.check(Schema.isGreaterThan(0));
35
- /**
36
- * Integer greater than or equal to zero.
37
- */
38
- const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
39
- /**
40
- * Cost greater than or equal with finite value
41
- */
42
- const NonNegativeCost = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0));
43
- /**
44
- * Absolute file path (e.g., `/home/user/projects/myapp/src/main.ts`).
45
- */
46
- const AbsolutePath$1 = Schema.String.pipe(Schema.brand("AbsolutePath"));
47
- /**
48
- * Optional public JSON field that can hold explicit `undefined` on the type
49
- * side but encodes it as an omitted key, matching legacy `JSON.stringify`.
50
- */
51
- const optional = (schema) => Schema.optionalKey(schema).pipe(Schema.decodeTo(Schema.optional(Schema.toType(schema)), {
52
- decode: SchemaGetter.passthrough({ strict: false }),
53
- encode: SchemaGetter.transformOptional(Option.filter((value) => value !== void 0))
54
- }));
55
- /**
56
- * Attach static methods to a schema object. Designed to be used with `.pipe()`:
57
- *
58
- * @example
59
- * export const Foo = fooSchema.pipe(
60
- * withStatics((schema) => ({
61
- * zero: schema.make(0),
62
- * from: Schema.decodeUnknownOption(schema),
63
- * }))
64
- * )
65
- */
66
- const withStatics = (methods) => (schema) => Object.assign(schema, methods(schema));
67
- const DateTimeUtcFromMillis = Schema.Finite.pipe(Schema.decodeTo(Schema.DateTimeUtc, {
68
- decode: SchemaGetter.transform((value) => DateTime.makeUnsafe(value)),
69
- encode: SchemaGetter.transform((value) => DateTime.toEpochMillis(value))
70
- }));
71
- //#endregion
72
- //#region src/util/posix.ts
73
- /** Shared POSIX path implementation for sandbox and remote-runtime paths. */
74
- const posix = Effect.runSync(Path.Path.pipe(Effect.provide(Path.layer)));
75
- //#endregion
76
- //#region src/sandbox/instance.ts
77
- var instance_exports = /* @__PURE__ */ __exportAll({
78
- ID: () => ID,
79
- Kind: () => Kind,
80
- Ownership: () => Ownership,
81
- PersistedError: () => PersistedError,
82
- SandboxInstance: () => instance_exports,
83
- Status: () => Status,
84
- Usage: () => Usage,
85
- fromColumn: () => fromColumn,
86
- fromField: () => fromField,
87
- isMountable: () => isMountable,
88
- mountable: () => mountable,
89
- toColumn: () => toColumn,
90
- toField: () => toField
91
- });
92
- /**
93
- * A Sandbox instance is a **durable filesystem namespace** plus whatever compute
94
- * acts on it — a device in Unix terms, which exists whether or not anything has
95
- * it mounted. `Sandbox.Controller` is the only thing that creates,
96
- * stops, or destroys one; this module is just its identity and state model.
97
- *
98
- * The application ID is deliberately separate from the driver's own resource
99
- * locator: callers never parse a Vercel name or a Daytona ID, driver formats may
100
- * change, and a destroyed resource must stay identifiable in Project/Session
101
- * history. A missing resource is never recreated under an existing ID — a new
102
- * resource is a new namespace and therefore a new ID.
103
- */
104
- const ID = Schema.String.pipe(Schema.brand("SandboxInstance.ID"), withStatics((schema) => ({
105
- /**
106
- * The host. Reserved, and never written to a column — see {@link toColumn}.
107
- * It exists at runtime so nothing has to branch on "is this the host": it is
108
- * what identity reads, what logs show, and what the transport cache keys on.
109
- */
110
- local: schema.make("local"),
111
- /** A fresh identity for a namespace nothing has named yet. */
112
- create: () => schema.make(`sbx_${uuidv7()}`)
113
- })));
114
- /**
115
- * The storage boundary for namespace references, in one place.
116
- *
117
- * The host filesystem exists whether or not a row describes it, so it gets no
118
- * row and `NULL` is the only spelling of it — the Unix analogue is exact, since
119
- * `/` has no entry in the mount table you consult to find other mounts. That
120
- * makes a session or directory writable before any namespace is registered (the
121
- * foreign key is skipped on NULL), makes `SET sandbox_instance_id = NULL` a
122
- * meaningful "revert to the host", and leaves the host impossible to tombstone,
123
- * collect, or destroy, because there is nothing to point at.
124
- *
125
- * Two SQLite consequences ride on this and break correctness silently if missed:
126
- * unique indexes treat NULLs as distinct, so every uniqueness constraint
127
- * spanning a namespace column coalesces to `'local'`; and `= NULL` never
128
- * matches, so namespace-scoped reads use `IS`.
129
- */
130
- const toColumn = (id) => id === ID.local ? null : id;
131
- const fromColumn = (value) => value === null ? ID.local : ID.make(value);
132
- /**
133
- * The same mapping for row models, whose optional columns are `Option` rather
134
- * than `null`. Kept beside {@link toColumn} so the boundary stays one place:
135
- * `toColumn`/`fromColumn` for SQL parameters, these for `Model.FieldOption`.
136
- */
137
- const toField = (id) => id === ID.local ? Option.none() : Option.some(id);
138
- const fromField = (value) => Option.getOrElse(value, () => ID.local);
139
- /**
140
- * Filesystem-class taxonomy, mirroring Unix: disk, tmpfs/procfs, NFS/CIFS.
141
- * Stored on the row rather than derived from the registered driver, so reading
142
- * an instance never depends on the registry — which matters most when a driver
143
- * is *not* configured and you need to list or clean up its rows.
144
- */
145
- const Kind = Schema.Literals([
146
- "local",
147
- "virtual",
148
- "remote"
149
- ]);
150
- const Ownership = Schema.Literals(["managed", "external"]);
151
- /**
152
- * Lifecycle state, in ZFS pool vocabulary. This is the **last observed** value,
153
- * not live driver truth: Daytona auto-stops and auto-archives, Vercel sandboxes
154
- * expire on their own timeout, so drift is normal. `stateObservedAt` carries the
155
- * freshness and `Controller.refresh` updates it without waking anything.
156
- *
157
- * `removed` and `unavail` are deliberately distinct. `removed` means we deleted
158
- * it; `unavail` means the driver claims it is gone. A "not found" is frequently a
159
- * misclassification — wrong region, wrong API url, a revoked key answering 404,
160
- * eventual consistency right after create — so it must never be recorded as if we
161
- * had destroyed the resource ourselves.
162
- */
163
- const Status = Schema.Literals([
164
- "provisioning",
165
- "online",
166
- "offline",
167
- "suspending",
168
- "removing",
169
- "removed",
170
- "unavail",
171
- "faulted"
172
- ]);
173
- /**
174
- * The statuses a `mount` may proceed from. This is the predicate every
175
- * conditional write depends on, so it is enumerated once here rather than
176
- * restated as prose at each call site.
177
- *
178
- * `offline` qualifies because mounting wakes.
179
- * `faulted` qualifies because a fault is a *usability* condition, not an identity one — see {@link Status}.
180
- *
181
- * There is no `resuming`: it would exist to be observed by nothing, since
182
- * mounting wakes, `offline` is already mountable, and waking is not destructive
183
- * so it needs no claim. `suspending` and `removing` stay because they *are*
184
- * compare-and-set claims, blocking a concurrent mount mid-destruction.
185
- */
186
- const mountable = /* @__PURE__ */ new Set([
187
- "online",
188
- "offline",
189
- "faulted"
190
- ]);
191
- const isMountable = (status) => mountable.has(status);
192
- /**
193
- * Reference state, derived — never stored. `busy` carries its `umount` meaning:
194
- * something holds this and destruction must not proceed unforced.
195
- *
196
- * `pinned` is the kernel sense of the word: never reclaimable. It short-circuits
197
- * counting entirely for instances that cannot be stopped or destroyed (the local
198
- * host), which is what keeps them out of any future collector by construction
199
- * rather than by an ownership check happening to catch them.
200
- */
201
- const Usage = Schema.Literals([
202
- "idle",
203
- "busy",
204
- "pinned"
205
- ]);
206
- /** Sanitized driver failure. The only error shape allowed to be persisted or logged. */
207
- const PersistedError = Schema.Struct({
208
- name: Schema.String,
209
- message: Schema.String,
210
- code: Schema.optional(Schema.String)
211
- });
212
- //#endregion
213
- //#region src/sandbox/fs/filesystem.ts
214
- var filesystem_exports = /* @__PURE__ */ __exportAll({
215
- FileSystemError: () => FileSystemError,
216
- OperationUnsupportedError: () => OperationUnsupportedError,
217
- SandboxFileSystem: () => filesystem_exports,
218
- Service: () => Service$1,
219
- fromProvider: () => fromProvider,
220
- isNotFoundError: () => isNotFoundError,
221
- realpathScripts: () => realpathScripts,
222
- validateRmOptions: () => validateRmOptions,
223
- withCwd: () => withCwd$1
224
- });
225
- /**
226
- * The runtime filesystem contract, independent of any backend.
227
- *
228
- * Two surfaces, deliberately:
229
- * - {@link Provider} is what a backend implements — plain promises that reject,
230
- * matching every SDK we wrap.
231
- * - {@link Interface} is what the harness consumes — Effect with a typed error
232
- * channel and tracing spans. {@link fromProvider} bridges the two exactly
233
- * once, so no consumer ever writes `Effect.tryPromise` against a filesystem.
234
- *
235
- * Implementations:
236
- * - Local:
237
- * implement it over a VFS (`./local`);
238
- * local filesystem use OS primitives; hence have broader filesytem capabilities.
239
- *
240
- * - Remote:
241
- * implement it over a provider (`./remote`).
242
- * remote filesytems depends on the interface provided by the remote provider; hence can have limited filesytem capabilities.
243
- *
244
- * `isFile`/`isDirectory` are required booleans; size, mtime, and isSymbolicLink are omitted when the
245
- * backend cannot report them — never fabricated.
246
- *
247
- * **Paths are POSIX, and the harness is Unix-only (for now!).** Every path uses `/`
248
- * separators on both the host and inside a sandbox — Windows is not supported,
249
- * so no translation layer exists. Consumers must use the shared Effect POSIX
250
- * path implementation, never the platform default, or a host running the harness would
251
- * impose its own flavour on a remote sandbox's paths. Relative paths resolve
252
- * against the backend's configured `cwd`.
253
- */
254
- var OperationUnsupportedError = class extends Schema.TaggedError()("OperationUnsupportedError", {
255
- operation: Schema.String,
256
- message: Schema.String
257
- }) {};
258
- /** A backend operation failed. `cause` carries the provider's own rejection. */
259
- var FileSystemError = class extends Schema.TaggedError()("SandboxFileSystemError", {
260
- method: Schema.String,
261
- path: Schema.String,
262
- cause: Schema.optional(Schema.Defect())
263
- }) {};
264
- /** Whether a provider failure means the path itself is definitively absent. */
265
- const isNotFoundError = (cause) => {
266
- const code = cause?.code;
267
- return code === "ENOENT" || code === "ENOTDIR";
268
- };
269
- /**
270
- * Shell forms of `realpath` for backends that only expose a process API.
271
- * `pwd -P` is the portable primitive: directories resolve directly, anything
272
- * else resolves its parent and keeps the final name as given. Run as
273
- * `sh -c <script> _ <path>`; try the first, fall back to the second.
274
- */
275
- const realpathScripts = ["cd -- \"$1\" && pwd -P", "cd -- \"$(dirname -- \"$1\")\" && printf '%s/%s' \"$(pwd -P)\" \"$(basename -- \"$1\")\""];
276
- /** The runtime filesystem service — the live {@link Interface} for the active sandbox. */
277
- var Service$1 = class extends Context.Service()("@codeworksh/harness/sandbox/fs/filesystem/Service") {};
278
- /**
279
- * Reject `rm` options a provider does not implement, before any mutation. Only
280
- * `recursive` and `force` are part of the contract; anything else is refused
281
- * loudly rather than silently ignored.
282
- */
283
- const validateRmOptions = (options, operation = "rm") => Effect.suspend(() => {
284
- for (const option of Object.keys(options ?? {})) {
285
- if (option === "recursive" || option === "force") continue;
286
- return Effect.fail(new OperationUnsupportedError({
287
- operation,
288
- message: `Unsupported rm option: ${option}`
289
- }));
290
- }
291
- return Effect.void;
292
- });
293
- /**
294
- * Lift a {@link Provider} into the runtime {@link Interface}: one place that
295
- * converts rejections into {@link FileSystemError}, validates `rm` options,
296
- * creates missing parents on write, and names a tracing span per operation.
297
- */
298
- const fromProvider = (provider) => {
299
- const attempt = (method, path, run) => Effect.tryPromise({
300
- try: run,
301
- catch: (cause) => new FileSystemError({
302
- method,
303
- path,
304
- cause
305
- })
306
- });
307
- const writeCreatingParents = (path, content) => {
308
- const write = attempt("writeFile", path, () => provider.writeFile(path, content));
309
- const parent = posix.dirname(path);
310
- return write.pipe(Effect.catch(() => attempt("mkdir", parent, () => provider.mkdir(parent, { recursive: true })).pipe(Effect.ignore, Effect.andThen(write))));
311
- };
312
- return {
313
- readFile: Effect.fn("SandboxFileSystem.readFile")((path) => attempt("readFile", path, () => provider.readFile(path))),
314
- readFileBuffer: Effect.fn("SandboxFileSystem.readFileBuffer")((path) => attempt("readFileBuffer", path, () => provider.readFileBuffer(path))),
315
- writeFile: Effect.fn("SandboxFileSystem.writeFile")(writeCreatingParents),
316
- stat: Effect.fn("SandboxFileSystem.stat")((path) => attempt("stat", path, () => provider.stat(path))),
317
- ...provider.lstat === void 0 ? {} : { lstat: Effect.fn("SandboxFileSystem.lstat")((path) => attempt("lstat", path, () => provider.lstat(path))) },
318
- readdir: Effect.fn("SandboxFileSystem.readdir")((path) => attempt("readdir", path, () => provider.readdir(path))),
319
- exists: Effect.fn("SandboxFileSystem.exists")((path) => attempt("exists", path, () => provider.exists(path))),
320
- mkdir: Effect.fn("SandboxFileSystem.mkdir")((path, options) => attempt("mkdir", path, () => provider.mkdir(path, options))),
321
- rm: Effect.fn("SandboxFileSystem.rm")((path, options) => validateRmOptions(options).pipe(Effect.andThen(attempt("rm", path, () => provider.rm(path, options))))),
322
- realpath: Effect.fn("SandboxFileSystem.realpath")((path) => attempt("realpath", path, () => provider.realpath(path)))
323
- };
324
- };
325
- /**
326
- * Bind a cwd-neutral filesystem to one mount's working directory.
327
- *
328
- * The counterpart of `Shell.withCwd`, and the reason relative paths mean the
329
- * same thing to both: a shared transport stays rooted at the namespace root, so
330
- * resolution happens here, per mount, rather than inside a VFS whose `chdir` is
331
- * global state two mounts would fight over.
332
- */
333
- const withCwd$1 = (fs, cwd) => {
334
- const at = (path) => posix.resolve(cwd, path);
335
- return {
336
- readFile: (path) => fs.readFile(at(path)),
337
- readFileBuffer: (path) => fs.readFileBuffer(at(path)),
338
- writeFile: (path, content) => fs.writeFile(at(path), content),
339
- stat: (path) => fs.stat(at(path)),
340
- readdir: (path) => fs.readdir(at(path)),
341
- exists: (path) => fs.exists(at(path)),
342
- mkdir: (path, options) => fs.mkdir(at(path), options),
343
- rm: (path, options) => fs.rm(at(path), options),
344
- realpath: (path) => fs.realpath(at(path)),
345
- ...fs.lstat === void 0 ? {} : { lstat: (path) => fs.lstat(at(path)) }
346
- };
347
- };
348
- //#endregion
349
- //#region src/sandbox/shell/shell.ts
350
- /**
351
- * The pluggable execution contract. Local sandboxes usually get a Shell through
352
- * just-bash over the local `Local.Vfs`; remote sandboxes provide their own
353
- * native Shell. Either way the rest of the harness depends only on this service
354
- * tag.
355
- */
356
- var ShellError = class extends Schema.TaggedError()("ShellError", {
357
- command: Schema.String,
358
- cause: Schema.optional(Schema.Defect())
359
- }) {};
360
- /**
361
- * Mount-local shell factories are attached out-of-band so the public Shell
362
- * contract stays about command execution only.
363
- *
364
- * Most transports are safely shared and need only the cwd wrapper below.
365
- * Stateful in-process interpreters use this hook to construct one interpreter
366
- * per mount while retaining the underlying filesystem transport. This tag must
367
- * remain on the outermost wrapper consumed by {@link withCwd}; wrapper helpers
368
- * such as {@link fromExec} must propagate it when they return a new object.
369
- */
370
- const mountFactories = /* @__PURE__ */ new WeakMap();
371
- const perMount = (transport, make) => {
372
- mountFactories.set(transport, make);
373
- return transport;
374
- };
375
- /**
376
- * POSIX single-quote escaping: wrap in `'…'` and rewrite each embedded quote as
377
- * `'\''`. Everything inside single quotes is literal to the shell, so this is
378
- * safe for arbitrary bytes.
379
- */
380
- const quote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
381
- /** Render an argument vector as one shell-safe command string. */
382
- const quoteArgv = (argv) => argv.map(quote).join(" ");
383
- /**
384
- * Resolve a per-command cwd against the sandbox cwd. Passing a relative cwd
385
- * straight to a host or remote process API would otherwise resolve it against
386
- * that API's own default, which need not be the filesystem's configured cwd.
387
- */
388
- const resolveCwd = (base, cwd) => {
389
- if (cwd === void 0 || posix.isAbsolute(cwd) || base === void 0) return cwd ?? base;
390
- return posix.resolve(base, cwd);
391
- };
392
- /**
393
- * Complete a string-only backend: `execArgv` quotes the vector and runs it
394
- * through `exec`. Backends that spawn a real argument vector (Vercel) implement
395
- * `execArgv` themselves instead, so the args never meet a shell parser at all.
396
- *
397
- * `cwd` rides the options rather than a `cd <dir> && …` prefix. Every backend
398
- * we wrap takes a working directory natively, and the prefix form cannot tell a
399
- * failed `cd` from a failed command — both arrive as one exit code.
400
- */
401
- const fromExec = (backend) => {
402
- const wrapped = {
403
- ...backend,
404
- execArgv: (argv, options) => backend.exec(quoteArgv(argv), options)
405
- };
406
- const mountFactory = mountFactories.get(backend);
407
- return mountFactory === void 0 ? wrapped : perMount(wrapped, (cwd) => fromExec(mountFactory(cwd)));
408
- };
409
- /**
410
- * Bind a cwd-neutral backend to one mount's working directory.
411
- *
412
- * The transport is shared between mounts and must stay rooted at the namespace
413
- * root, so the directory cannot live inside it: two mounts at different
414
- * directories would otherwise see each other's. This wrapper is per mount, and
415
- * an operation-level `cwd` still wins — resolved against the mount's, so a
416
- * relative one means what it reads like.
417
- */
418
- const withCwd = (backend, cwd) => {
419
- const mounted = mountFactories.get(backend)?.(cwd) ?? backend;
420
- const at = (options) => {
421
- const resolvedCwd = resolveCwd(cwd, options?.cwd);
422
- return {
423
- ...options,
424
- ...resolvedCwd === void 0 ? {} : { cwd: resolvedCwd }
425
- };
426
- };
427
- const stream = mounted.stream;
428
- return {
429
- exec: (command, options) => mounted.exec(command, at(options)),
430
- execArgv: (argv, options) => mounted.execArgv(argv, at(options)),
431
- ...stream === void 0 ? {} : { stream: (command, options) => stream(command, at(options)) }
432
- };
433
- };
434
- /** Execution service — the live {@link ISandboxExe} for the active sandbox. */
435
- var Shell$1 = class extends Context.Service()("@codeworksh/harness/sandbox/shell/shell") {};
436
- //#endregion
437
- //#region src/sandbox/io.ts
438
- /**
439
- * `SandboxIO` is a **mount**: a filesystem, a shell, and the identity and
440
- * working directory they act on.
441
- *
442
- * It is the whole vocabulary a consumer needs. Project, Git, Copy, Location, and
443
- * every tool ask for `SandboxIO.FileSystem`, `SandboxIO.Shell`, and
444
- * `SandboxIO.Current` — never for a driver, an address, or a provider SDK — so
445
- * a host directory, an in-memory VFS, and a remote microVM are interchangeable
446
- * behind one contract.
447
- *
448
- * The mount neither creates nor destroys infrastructure. `SandboxInstance` is
449
- * the durable namespace it acts on — a device, which exists whether or not
450
- * anything has it mounted — and `Sandbox.Controller` is the only path that
451
- * creates, stops, or destroys one.
452
- */
453
- /**
454
- * The filesystem tag. Re-exported here so consumers import one namespace —
455
- * Project, Git, Copy, and the runner ask for `SandboxIO.FileSystem`, never for
456
- * the module that happens to define it. Code *inside* `sandbox/` keeps importing
457
- * the tag directly, since `io.ts` is built on top of it.
458
- */
459
- const FileSystem$1 = Service$1;
460
- /** The shell tag. Re-exported here so consumers import one namespace. */
461
- const Shell = Shell$1;
462
- /** Identity and working directory of the current mount. */
463
- var Current = class extends Context.Service()("@codeworksh/harness/sandbox/io/Current") {};
464
- /**
465
- * Resolve a mount's cwd without consulting ambient process state.
466
- *
467
- * The default is supplied by the namespace adapter:
468
- * provider metadata remotely, `/` for a virtual filesystem, and `process.cwd()` for the host adapter.
469
- * An explicit absolute cwd replaces it; a relative cwd is resolved inside it. The
470
- * result is therefore always the one concrete absolute path `Current` requires.
471
- *
472
- * A non-absolute default throws rather than failing typed. It is the one
473
- * defect-level guard in this module, and deliberately so:
474
- * Adapters reading a value from a provider call this inside their own error channel,
475
- * where the throw becomes their typed failure (see `EnvDaytona.mountCwd`).
476
- */
477
- const resolveMountCwd = (defaultCwd, cwd) => {
478
- if (!posix.isAbsolute(defaultCwd)) throw new TypeError(`Sandbox default cwd must be absolute: ${defaultCwd}`);
479
- if (cwd === void 0) return posix.resolve(defaultCwd);
480
- return posix.isAbsolute(cwd) ? posix.resolve(cwd) : posix.resolve(defaultCwd, cwd);
481
- };
482
- /**
483
- * Bind a cwd-neutral transport to one mount.
484
- *
485
- * The transport underneath is shared between
486
- * mounts and stays rooted at the namespace root, and everything directory-shaped
487
- * happens here, once per mount. Two mounts of one namespace at different working
488
- * directories therefore coexist without seeing or moving each other's.
489
- *
490
- * It consumes the same two tags it provides — the transport is supplied by the
491
- * layer this is composed over, not by itself.
492
- */
493
- const mount = (identity) => Layer.mergeAll(Layer.succeed(Current, identity), Layer.effect(Service$1, Effect.map(Service$1, (fs) => withCwd$1(fs, identity.cwd))), Layer.effect(Shell$1, Effect.map(Shell$1, (shell) => withCwd(shell, identity.cwd))));
494
- /**
495
- * The host, rooted at `cwd`. Always `SandboxInstance.ID.local`: the working
496
- * directory selects where relative paths resolve, it does not make a second host
497
- * namespace — two mounts rooted at different directories still agree on absolute
498
- * paths.
499
- *
500
- * The host adapter defaults to `process.cwd()`, matching the OS process it wraps.
501
- * This is the one namespace where that coordinate is intrinsically valid; remote
502
- * and virtual adapters must never inherit it.
503
- */
504
- const host = (cwd) => ({
505
- id: ID.local,
506
- driver: "local",
507
- kind: "local",
508
- cwd: resolveMountCwd(process.cwd(), cwd)
509
- });
510
- /** Open driver identity. Adding a driver never extends a union in core. */
511
- const Name = Schema.String.check(Schema.isNonEmpty()).pipe(Schema.brand("SandboxDriver.Name"));
512
- /** A path whose coordinate system is the mounted namespace. */
513
- const AbsolutePath = Schema.String.check(Schema.isStartsWith("/")).pipe(Schema.brand("SandboxDriver.AbsolutePath"));
514
- const RuntimeConfigBase = Schema.Struct({ defaultCwd: AbsolutePath });
515
- const erase = (value) => ({
516
- name: value.name,
517
- kind: value.kind,
518
- capabilities: value.capabilities,
519
- createConfigCodec: value.createConfigCodec,
520
- runtimeConfigCodec: value.runtimeConfigCodec,
521
- create: (input) => value.create({
522
- instanceId: input.instanceId,
523
- config: input.config
524
- }),
525
- ...value.runtimeConfigFor === void 0 ? {} : { runtimeConfigFor: (input) => value.runtimeConfigFor({
526
- providerResourceId: input.providerResourceId,
527
- ...input.overrides === void 0 ? {} : { overrides: input.overrides }
528
- }) },
529
- attach: (input) => value.attach(input),
530
- ...value.inspect === void 0 ? {} : { inspect: (input) => value.inspect(input) },
531
- ...value.wake === void 0 ? {} : { wake: (input) => value.wake(input) },
532
- ...value.stop === void 0 ? {} : { stop: (input) => value.stop(input) },
533
- ...value.destroy === void 0 ? {} : { destroy: (input) => value.destroy(input) }
534
- });
535
- /** Define the default export of a loadable sandbox package. */
536
- const defineModule = (value) => ({
537
- ...value,
538
- name: Name.make(value.name)
539
- });
540
- /** Construct a driver and its registry contribution. */
541
- const driver = (value) => Object.assign(value, {
542
- registered: erase(value),
543
- apiVersion: 1,
544
- source: "builtin"
545
- });
546
- /** Attach trusted origin metadata without changing the driver implementation. */
547
- const withSource = (registration, source) => ({
548
- ...registration,
549
- source
550
- });
551
- //#endregion
552
- //#region src/sandbox/errors.ts
553
- var errors_exports = /* @__PURE__ */ __exportAll({
554
- SandboxBusyError: () => SandboxBusyError,
555
- SandboxDriverLoadError: () => SandboxDriverLoadError,
556
- SandboxDriverLoadPhase: () => SandboxDriverLoadPhase,
557
- SandboxDriverNotRegisteredError: () => SandboxDriverNotRegisteredError,
558
- SandboxDriverRegistrationError: () => SandboxDriverRegistrationError,
559
- SandboxError: () => errors_exports,
560
- SandboxMustBeStoppedError: () => SandboxMustBeStoppedError,
561
- SandboxNotFoundError: () => SandboxNotFoundError,
562
- SandboxProviderError: () => SandboxProviderError,
563
- SandboxRemovedError: () => SandboxRemovedError,
564
- SandboxTransitionConflictError: () => SandboxTransitionConflictError,
565
- SandboxUnavailError: () => SandboxUnavailError,
566
- SandboxUnsupportedError: () => SandboxUnsupportedError,
567
- makeRedactor: () => makeRedactor,
568
- providerError: () => providerError,
569
- providerErrorCause: () => providerErrorCause,
570
- providerErrorIsNotFound: () => providerErrorIsNotFound,
571
- sanitizeError: () => sanitizeError
572
- });
573
- /**
574
- * Lifecycle errors are confined to the control plane. Once a mount succeeds,
575
- * consumers continue to see only FileSystemError and ShellError.
576
- */
577
- var SandboxNotFoundError = class extends Schema.TaggedError()("SandboxNotFoundError", { id: ID }) {};
578
- var SandboxDriverNotRegisteredError = class extends Schema.TaggedError()("SandboxDriverNotRegisteredError", {
579
- driver: Schema.String,
580
- registered: Schema.optional(Schema.Array(Schema.String))
581
- }) {};
582
- var SandboxDriverRegistrationError = class extends Schema.TaggedError()("SandboxDriverRegistrationError", {
583
- driver: Schema.String,
584
- reason: Schema.String
585
- }) {};
586
- const SandboxDriverLoadPhase = Schema.Literals([
587
- "resolve",
588
- "import",
589
- "module",
590
- "api-version",
591
- "options",
592
- "factory",
593
- "registration"
594
- ]);
595
- var SandboxDriverLoadError = class extends Schema.TaggedError()("SandboxDriverLoadError", {
596
- specifier: Schema.String,
597
- phase: SandboxDriverLoadPhase,
598
- driver: Schema.optional(Schema.String),
599
- reason: Schema.String
600
- }) {};
601
- var SandboxBusyError = class extends Schema.TaggedError()("SandboxBusyError", {
602
- id: ID,
603
- refCount: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
604
- }) {};
605
- var SandboxMustBeStoppedError = class extends Schema.TaggedError()("SandboxMustBeStoppedError", {
606
- id: ID,
607
- status: Status
608
- }) {};
609
- var SandboxRemovedError = class extends Schema.TaggedError()("SandboxRemovedError", {
610
- id: ID,
611
- removedAt: Schema.optional(Schema.DateTimeUtc)
612
- }) {};
613
- var SandboxUnavailError = class extends Schema.TaggedError()("SandboxUnavailError", {
614
- id: ID,
615
- reason: Schema.String
616
- }) {};
617
- var SandboxUnsupportedError = class extends Schema.TaggedError()("SandboxUnsupportedError", {
618
- id: Schema.optional(ID),
619
- driver: Schema.String,
620
- operation: Schema.String
621
- }) {};
622
- var SandboxTransitionConflictError = class extends Schema.TaggedError()("SandboxTransitionConflictError", {
623
- id: ID,
624
- expected: Schema.Array(Status),
625
- actual: Status
626
- }) {};
627
- /**
628
- * A lifecycle failure safe to serialize, persist, or log.
629
- *
630
- * The raw SDK defect is deliberately absent from the schema. It is retained on
631
- * a non-enumerable symbol by {@link providerError}, so Effect's default
632
- * formatting and JSON serialization cannot expose credentials nested in it.
633
- */
634
- var SandboxProviderError = class extends Schema.TaggedError()("SandboxProviderError", {
635
- driver: Schema.String,
636
- operation: Schema.String,
637
- sanitized: PersistedError
638
- }) {};
639
- const rawCause = Symbol("@codework/sandbox/provider/error/raw/cause");
640
- const missingResource = Symbol("@codework/sandbox/provider/error/missing/resource");
641
- const providerErrorCause = (error) => error[rawCause];
642
- const providerErrorIsNotFound = (error) => error[missingResource] === true;
643
- const REDACTED = "<redacted>";
644
- /**
645
- * Conservative text redaction shared by every driver sanitizer.
646
- *
647
- * Disclaimer: This can really leak. Its never safe
648
- *
649
- * Configured secrets are removed exactly. Common authorization/header and URL
650
- * query shapes are masked as a second line of defence for values the caller did
651
- * not explicitly seed.
652
- *
653
- * Note: add support for diff regex as needed.
654
- */
655
- const makeRedactor = (secrets = []) => {
656
- const configured = [...secrets].filter((secret) => secret.length > 0).sort((a, b) => b.length - a.length);
657
- return (value) => {
658
- let redacted = value;
659
- for (const secret of configured) redacted = redacted.replaceAll(secret, REDACTED);
660
- return redacted.replace(/\b(authorization\s*:\s*(?:bearer|basic)\s+)[^\s,;]+/gi, `$1${REDACTED}`).replace(/\b((?:api[-_]?key|token|secret|password)\s*[=:]\s*)[^\s,;&]+/gi, `$1${REDACTED}`).replace(/([?&](?:access_token|api_key|token|secret|password)=)[^&#\s]+/gi, `$1${REDACTED}`).replace(/\b(?:gh[opsu]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/g, REDACTED);
661
- };
662
- };
663
- const errorCode = (cause) => {
664
- if (typeof cause !== "object" || cause === null || !("code" in cause)) return void 0;
665
- const code = cause.code;
666
- return typeof code === "string" || typeof code === "number" ? String(code) : void 0;
667
- };
668
- const errorName = (cause) => {
669
- if (typeof cause !== "object" || cause === null || !("name" in cause) || typeof cause.name !== "string") return "Error";
670
- return cause.name;
671
- };
672
- const errorMessage = (cause) => {
673
- if (typeof cause === "object" && cause !== null && "message" in cause && typeof cause.message === "string") return cause.message;
674
- return String(cause);
675
- };
676
- const sanitizeError = (cause, redact = makeRedactor()) => {
677
- const code = errorCode(cause);
678
- return {
679
- name: redact(errorName(cause)),
680
- message: redact(errorMessage(cause)),
681
- ...code === void 0 ? {} : { code: redact(code) }
682
- };
683
- };
684
- const providerError = (input) => {
685
- const redact = input.redact ?? makeRedactor();
686
- const error = new SandboxProviderError({
687
- driver: input.driver,
688
- operation: input.operation,
689
- sanitized: (input.sanitize ?? sanitizeError)(input.cause, redact)
690
- });
691
- Object.defineProperty(error, rawCause, {
692
- configurable: false,
693
- enumerable: false,
694
- value: input.cause,
695
- writable: false
696
- });
697
- Object.defineProperty(error, missingResource, {
698
- configurable: false,
699
- enumerable: false,
700
- value: input.notFound === true,
701
- writable: false
702
- });
703
- return error;
704
- };
705
- //#endregion
706
- //#region src/sandbox/public/driver.ts
707
- var driver_exports = /* @__PURE__ */ __exportAll({
708
- AbsolutePath: () => AbsolutePath,
709
- Name: () => Name,
710
- RuntimeConfigBase: () => RuntimeConfigBase,
711
- SandboxDriver: () => driver_exports,
712
- apiVersion: () => 1,
713
- driver: () => driver,
714
- module: () => defineModule
715
- });
716
- //#endregion
717
- //#region src/sandbox/public/io.ts
718
- var io_exports = /* @__PURE__ */ __exportAll({
719
- Current: () => Current,
720
- FileSystem: () => FileSystem$1,
721
- SandboxIO: () => io_exports,
722
- Shell: () => Shell
723
- });
724
- //#endregion
725
- //#region src/sandbox/error.ts
726
- var error_exports = /* @__PURE__ */ __exportAll({
727
- SandboxProviderError: () => SandboxProviderError,
728
- makeRedactor: () => makeRedactor,
729
- providerError: () => providerError,
730
- providerErrorCause: () => providerErrorCause,
731
- providerErrorIsNotFound: () => providerErrorIsNotFound,
732
- sanitizeError: () => sanitizeError
733
- });
734
- //#endregion
735
- //#region src/sandbox/resource.ts
736
- var resource_exports = /* @__PURE__ */ __exportAll({
737
- SandboxResource: () => resource_exports,
738
- Service: () => Service
739
- });
740
- /**
741
- * The driver's own locator for the attached resource — a Vercel sandbox name, a
742
- * Daytona sandbox id.
743
- *
744
- * Deliberately *not* on `SandboxIO.Current`: consumers never parse one,
745
- * and keeps it separate from the application id precisely so a driver's format can
746
- * change without touching identity.
747
- *
748
- * It exists for the control plane, which records it as `provider_resource_id`,
749
- * and for tests that reattach to the same resource.
750
- *
751
- * One tag for every driver rather than one per driver. A mount has exactly one
752
- * driver, so there is nothing to disambiguate, and the control plane has to read
753
- * the locator without knowing which driver produced it — keeps the
754
- * driver name open, so anything keyed on a closed `"vercel" | "daytona"` set is
755
- * a bug waiting for the third driver.
756
- */
757
- var Service = class extends Context.Service()("@codeworksh/harness/sandbox/resource/Service") {};
758
- //#endregion
759
- //#region src/sandbox/public/shell.ts
760
- var shell_exports = /* @__PURE__ */ __exportAll({
761
- Shell: () => Shell$1,
762
- ShellError: () => ShellError,
763
- fromExec: () => fromExec,
764
- quote: () => quote,
765
- quoteArgv: () => quoteArgv
766
- });
767
- //#endregion
768
- export { PersistedError as $, Current as A, quote as B, AbsolutePath as C, driver as D, defineModule as E, resolveMountCwd as F, filesystem_exports as G, resolveCwd as H, Shell$1 as I, realpathScripts as J, fromProvider as K, ShellError as L, Shell as M, host as N, erase as O, mount as P, Ownership as Q, fromExec as R, sanitizeError as S, RuntimeConfigBase as T, withCwd as U, quoteArgv as V, Service$1 as W, ID as X, withCwd$1 as Y, Kind as Z, SandboxUnsupportedError as _, validateAikitUserMessage as _t, io_exports as a, toField as at, providerError as b, SandboxDriverLoadError as c, DateTimeUtcFromMillis as ct, SandboxMustBeStoppedError as d, isAikitAssistantMessage as dt, Status as et, SandboxNotFoundError as f, isAikitToolCallTerminalPart as ft, SandboxUnavailError as g, validateAikitToolCallTerminalPart as gt, SandboxTransitionConflictError as h, validateAikitMessage as ht, error_exports as i, toColumn as it, FileSystem$1 as j, withSource as k, SandboxDriverNotRegisteredError as l, NonNegativeCost as lt, SandboxRemovedError as m, validateAikitAssistantMessage as mt, Service as n, instance_exports as nt, driver_exports as o, posix as ot, SandboxProviderError as p, optional as pt, isNotFoundError as q, resource_exports as r, isMountable as rt, SandboxBusyError as s, AbsolutePath$1 as st, shell_exports as t, fromField as tt, SandboxDriverRegistrationError as u, NonNegativeInt as ut, errors_exports as v, withStatics as vt, Name as w, providerErrorIsNotFound as x, makeRedactor as y, perMount as z };
769
-
770
- //# sourceMappingURL=sandbox-Dlz9cGeD.mjs.map