@giselles-ai/sandkit 0.1.1 → 0.1.2
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/README.md +46 -6
- package/dist/adapters/drizzle.d.ts +1 -1
- package/dist/adapters/memory.d.ts +1 -1
- package/dist/adapters/sqlite-bun.d.ts +1 -1
- package/dist/chunk-T76VM5D2.js +23 -0
- package/dist/chunk-T76VM5D2.js.map +1 -0
- package/dist/{chunk-HVYCAAZQ.js → chunk-XN6DGLRP.js} +1 -1
- package/dist/chunk-XN6DGLRP.js.map +1 -0
- package/dist/chunk-YGUNJGP7.js +23 -0
- package/dist/chunk-YGUNJGP7.js.map +1 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.js +348 -122
- package/dist/index.js.map +1 -1
- package/dist/integrations/mock.d.ts +2 -2
- package/dist/integrations/mock.js +20 -3
- package/dist/integrations/mock.js.map +1 -1
- package/dist/integrations/vercel.d.ts +2 -2
- package/dist/integrations/vercel.js +40 -10
- package/dist/integrations/vercel.js.map +1 -1
- package/dist/policies/bun.d.ts +9 -0
- package/dist/policies/bun.js +10 -0
- package/dist/policies/bun.js.map +1 -0
- package/dist/policies/npm.d.ts +12 -0
- package/dist/policies/npm.js +10 -0
- package/dist/policies/npm.js.map +1 -0
- package/dist/{types-BRMAvcWc.d.ts → types-DNpj280o.d.ts} +1 -1
- package/dist/{types-B5N9o-ew.d.ts → types-nu3vpBCZ.d.ts} +34 -4
- package/package.json +11 -1
- package/dist/chunk-HVYCAAZQ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
allowNpm,
|
|
3
|
+
npm
|
|
4
|
+
} from "./chunk-T76VM5D2.js";
|
|
1
5
|
import {
|
|
2
6
|
github
|
|
3
7
|
} from "./chunk-5MXHFOJH.js";
|
|
8
|
+
import {
|
|
9
|
+
getSandboxDriverFactory
|
|
10
|
+
} from "./chunk-XN6DGLRP.js";
|
|
4
11
|
import "./chunk-UDFWES6J.js";
|
|
5
12
|
import "./chunk-BDPTYR6V.js";
|
|
6
13
|
import "./chunk-RMMOQD5Y.js";
|
|
7
14
|
import {
|
|
8
15
|
createMemoryAdapter
|
|
9
16
|
} from "./chunk-CSOBTLWV.js";
|
|
17
|
+
import {
|
|
18
|
+
createId
|
|
19
|
+
} from "./chunk-DLGUA3H7.js";
|
|
20
|
+
import {
|
|
21
|
+
allowBun,
|
|
22
|
+
bun
|
|
23
|
+
} from "./chunk-YGUNJGP7.js";
|
|
10
24
|
import {
|
|
11
25
|
codex
|
|
12
26
|
} from "./chunk-2M2AZUOC.js";
|
|
@@ -16,10 +30,6 @@ import {
|
|
|
16
30
|
import {
|
|
17
31
|
aiGateway
|
|
18
32
|
} from "./chunk-UEAKE56H.js";
|
|
19
|
-
import {
|
|
20
|
-
getSandboxDriverFactory
|
|
21
|
-
} from "./chunk-HVYCAAZQ.js";
|
|
22
|
-
import "./chunk-DLGUA3H7.js";
|
|
23
33
|
import {
|
|
24
34
|
allowAll,
|
|
25
35
|
allowService,
|
|
@@ -397,7 +407,12 @@ var ManagedSandbox = class {
|
|
|
397
407
|
normalized.command,
|
|
398
408
|
normalized.args,
|
|
399
409
|
normalized.policy,
|
|
400
|
-
() => this.executeCommand(
|
|
410
|
+
() => this.executeCommand(
|
|
411
|
+
normalized.command,
|
|
412
|
+
normalized.args,
|
|
413
|
+
normalized.policy,
|
|
414
|
+
normalized.detached
|
|
415
|
+
)
|
|
401
416
|
);
|
|
402
417
|
}
|
|
403
418
|
async normalizeRunCommandInput(inputOrCommand, args) {
|
|
@@ -405,13 +420,17 @@ var ManagedSandbox = class {
|
|
|
405
420
|
return {
|
|
406
421
|
command: inputOrCommand,
|
|
407
422
|
args,
|
|
408
|
-
policy: await this.#resolveDefaultPolicy()
|
|
423
|
+
policy: await this.#resolveDefaultPolicy(),
|
|
424
|
+
timeoutMs: void 0,
|
|
425
|
+
detached: false
|
|
409
426
|
};
|
|
410
427
|
}
|
|
411
428
|
return {
|
|
412
429
|
command: inputOrCommand.command,
|
|
413
430
|
args: inputOrCommand.args ?? [],
|
|
414
|
-
policy: inputOrCommand.policy ?? await this.#resolveDefaultPolicy()
|
|
431
|
+
policy: inputOrCommand.policy ?? await this.#resolveDefaultPolicy(),
|
|
432
|
+
timeoutMs: inputOrCommand.timeoutMs,
|
|
433
|
+
detached: "detached" in inputOrCommand ? inputOrCommand.detached : false
|
|
415
434
|
};
|
|
416
435
|
}
|
|
417
436
|
ensureCommandShape(command, args) {
|
|
@@ -425,44 +444,35 @@ var ManagedSandbox = class {
|
|
|
425
444
|
async runUnitOfWork(command, args, effectivePolicy, operation) {
|
|
426
445
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
427
446
|
const runId = await this.startRun(command, args, effectivePolicy, now);
|
|
428
|
-
let
|
|
429
|
-
let commandResult;
|
|
430
|
-
try {
|
|
431
|
-
commandResult = await operation();
|
|
432
|
-
} catch (error) {
|
|
433
|
-
commandError = error;
|
|
434
|
-
}
|
|
435
|
-
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
436
|
-
const commandStatus = commandError === void 0 ? commandResult?.exitCode === 0 ? "succeeded" : "failed" : "failed";
|
|
437
|
-
let providerCommit;
|
|
438
|
-
let finalizeError;
|
|
447
|
+
let commandHandle;
|
|
439
448
|
try {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
449
|
+
commandHandle = await operation();
|
|
450
|
+
} catch (commandError) {
|
|
451
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
452
|
+
let providerCommit;
|
|
453
|
+
let finalizeError;
|
|
454
|
+
try {
|
|
455
|
+
const commit = await this.snapshotWithFallback();
|
|
456
|
+
providerCommit = commit.state;
|
|
457
|
+
if (this.#onCommit) {
|
|
458
|
+
await this.persistCommit(commit);
|
|
459
|
+
}
|
|
460
|
+
} catch (error) {
|
|
461
|
+
finalizeError = error;
|
|
462
|
+
providerCommit = void 0;
|
|
444
463
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
finishedAt,
|
|
457
|
-
exitCode: commandResult?.exitCode,
|
|
458
|
-
stdout: commandResult?.stdout,
|
|
459
|
-
stderr: commandResult?.stderr
|
|
460
|
-
});
|
|
464
|
+
try {
|
|
465
|
+
if (runId) {
|
|
466
|
+
await this.finishRun({
|
|
467
|
+
runId,
|
|
468
|
+
status: "failed",
|
|
469
|
+
providerCommit,
|
|
470
|
+
finishedAt
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
} catch (error) {
|
|
474
|
+
finalizeError = finalizeError ?? error;
|
|
461
475
|
}
|
|
462
|
-
} catch (error) {
|
|
463
|
-
finalizeError = finalizeError ?? error;
|
|
464
|
-
}
|
|
465
|
-
if (commandError !== void 0) {
|
|
466
476
|
if (finalizeError !== void 0) {
|
|
467
477
|
throw new AggregateError(
|
|
468
478
|
[commandError, finalizeError],
|
|
@@ -471,13 +481,67 @@ var ManagedSandbox = class {
|
|
|
471
481
|
}
|
|
472
482
|
throw commandError;
|
|
473
483
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
484
|
+
const waitResult = (async () => {
|
|
485
|
+
let commandError;
|
|
486
|
+
let commandResult;
|
|
487
|
+
let providerCommit;
|
|
488
|
+
let finalizeError;
|
|
489
|
+
try {
|
|
490
|
+
commandResult = await commandHandle.wait();
|
|
491
|
+
} catch (error) {
|
|
492
|
+
commandError = error;
|
|
493
|
+
}
|
|
494
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
495
|
+
const commandStatus = commandError === void 0 ? commandResult?.exitCode === 0 ? "succeeded" : "failed" : "failed";
|
|
496
|
+
try {
|
|
497
|
+
const commit = await this.snapshotWithFallback();
|
|
498
|
+
providerCommit = commit.state;
|
|
499
|
+
if (this.#onCommit) {
|
|
500
|
+
await this.persistCommit(commit);
|
|
501
|
+
}
|
|
502
|
+
} catch (error) {
|
|
503
|
+
finalizeError = error;
|
|
504
|
+
providerCommit = void 0;
|
|
505
|
+
}
|
|
506
|
+
const finalRunStatus = commandError === void 0 && finalizeError === void 0 ? commandStatus : "failed";
|
|
507
|
+
try {
|
|
508
|
+
if (runId) {
|
|
509
|
+
await this.finishRun({
|
|
510
|
+
runId,
|
|
511
|
+
status: finalRunStatus,
|
|
512
|
+
providerCommit,
|
|
513
|
+
finishedAt,
|
|
514
|
+
exitCode: commandResult?.exitCode,
|
|
515
|
+
stdout: commandResult?.stdout,
|
|
516
|
+
stderr: commandResult?.stderr
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
} catch (error) {
|
|
520
|
+
finalizeError = finalizeError ?? error;
|
|
521
|
+
}
|
|
522
|
+
if (commandError !== void 0) {
|
|
523
|
+
if (finalizeError !== void 0) {
|
|
524
|
+
throw new AggregateError(
|
|
525
|
+
[commandError, finalizeError],
|
|
526
|
+
"Sandbox command failed and unit-of-work durability finalization did not complete."
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
throw commandError;
|
|
530
|
+
}
|
|
531
|
+
if (finalizeError !== void 0) {
|
|
532
|
+
throw finalizeError;
|
|
533
|
+
}
|
|
534
|
+
if (!commandResult) {
|
|
535
|
+
throw new Error("Command result was missing after successful execution.");
|
|
536
|
+
}
|
|
537
|
+
return commandResult;
|
|
538
|
+
})();
|
|
539
|
+
void waitResult.catch(() => {
|
|
540
|
+
});
|
|
541
|
+
return {
|
|
542
|
+
wait: async () => waitResult,
|
|
543
|
+
logs: commandHandle.logs
|
|
544
|
+
};
|
|
481
545
|
}
|
|
482
546
|
async startRun(command, args, effectivePolicy, at) {
|
|
483
547
|
if (!this.#runLifecycle?.onRunStart) {
|
|
@@ -490,9 +554,9 @@ var ManagedSandbox = class {
|
|
|
490
554
|
startedAt: at
|
|
491
555
|
});
|
|
492
556
|
}
|
|
493
|
-
async executeCommand(command, args, policy) {
|
|
557
|
+
async executeCommand(command, args, policy, detached) {
|
|
494
558
|
await this.#driver.applyPolicy(policy);
|
|
495
|
-
return this.#driver.runCommand(command, [...args]);
|
|
559
|
+
return this.#driver.runCommand(command, [...args], { detached });
|
|
496
560
|
}
|
|
497
561
|
async finishRun(input) {
|
|
498
562
|
if (!this.#runLifecycle?.onRunFinish) {
|
|
@@ -537,7 +601,9 @@ var ManagedSession = class {
|
|
|
537
601
|
const normalized = await this.normalizeSessionInput(inputOrCommand, args);
|
|
538
602
|
this.ensureCommandShape(normalized.command, normalized.args);
|
|
539
603
|
await this.#driver.applyPolicy(normalized.policy);
|
|
540
|
-
return this.#driver.runCommand(normalized.command, [...normalized.args]
|
|
604
|
+
return (await this.#driver.runCommand(normalized.command, [...normalized.args], {
|
|
605
|
+
detached: false
|
|
606
|
+
})).wait();
|
|
541
607
|
}
|
|
542
608
|
async commit() {
|
|
543
609
|
await this.assertSessionActive();
|
|
@@ -615,6 +681,9 @@ var ManagedSession = class {
|
|
|
615
681
|
policy: await this.resolveSessionPolicy()
|
|
616
682
|
};
|
|
617
683
|
}
|
|
684
|
+
if ("detached" in inputOrCommand) {
|
|
685
|
+
throw new Error("session exec does not support detached execution.");
|
|
686
|
+
}
|
|
618
687
|
return {
|
|
619
688
|
command: inputOrCommand.command,
|
|
620
689
|
args: inputOrCommand.args ?? [],
|
|
@@ -669,11 +738,15 @@ var LazySandboxHandle = class {
|
|
|
669
738
|
this.#getActiveLease = getActiveLease;
|
|
670
739
|
}
|
|
671
740
|
async runCommand(inputOrCommand, args = []) {
|
|
672
|
-
const sandbox = await this.#resolveSandbox();
|
|
741
|
+
const sandbox = typeof inputOrCommand === "string" ? await this.#resolveSandbox() : await this.#resolveSandbox(inputOrCommand);
|
|
673
742
|
if (typeof inputOrCommand === "string") {
|
|
674
|
-
return sandbox.runCommand(inputOrCommand, args);
|
|
743
|
+
return sandbox.runCommand(inputOrCommand, args).then((command2) => command2.wait());
|
|
744
|
+
}
|
|
745
|
+
const command = await sandbox.runCommand(inputOrCommand);
|
|
746
|
+
if ("detached" in inputOrCommand && inputOrCommand.detached === true) {
|
|
747
|
+
return command;
|
|
675
748
|
}
|
|
676
|
-
return
|
|
749
|
+
return command.wait();
|
|
677
750
|
}
|
|
678
751
|
async openSession(input) {
|
|
679
752
|
return this.#openSession(input);
|
|
@@ -687,25 +760,169 @@ var LazySandboxHandle = class {
|
|
|
687
760
|
};
|
|
688
761
|
|
|
689
762
|
// src/core/workspace.ts
|
|
763
|
+
var inFlightDurableCommands = /* @__PURE__ */ new Set();
|
|
690
764
|
function setupStateFingerprint(command, args, policy) {
|
|
691
765
|
return encodeURIComponent(
|
|
692
766
|
JSON.stringify({
|
|
693
767
|
command,
|
|
694
768
|
args,
|
|
695
|
-
policy:
|
|
769
|
+
policy: {
|
|
696
770
|
id: describeWorkspacePolicyId(policy),
|
|
697
771
|
config: asPolicySnapshotConfig(policy)
|
|
698
|
-
}
|
|
772
|
+
}
|
|
699
773
|
})
|
|
700
774
|
);
|
|
701
775
|
}
|
|
702
776
|
var sharedSetupStateId = (adapterId, setup) => {
|
|
703
|
-
if (setup
|
|
777
|
+
if (setup) {
|
|
704
778
|
assertWorkspacePolicyIsDurable(setup.policy);
|
|
705
779
|
}
|
|
706
780
|
const fingerprint = setup ? setupStateFingerprint(setup.command, [...setup.args ?? []], setup.policy) : "no-bootstrap";
|
|
707
781
|
return `${adapterId}:shared-bootstrap:${fingerprint}`;
|
|
708
782
|
};
|
|
783
|
+
function sharedSetupRecordId(ctx) {
|
|
784
|
+
if (!ctx.options.setup) {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
return sharedSetupStateId(ctx.adapter.id, ctx.options.setup);
|
|
788
|
+
}
|
|
789
|
+
function assertNoDurableCommandInFlight(workspaceId) {
|
|
790
|
+
if (inFlightDurableCommands.has(workspaceId)) {
|
|
791
|
+
throw new Error(
|
|
792
|
+
"Cannot run a durable command while another durable command is still in flight."
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
function beginDurableCommand(workspaceId) {
|
|
797
|
+
assertNoDurableCommandInFlight(workspaceId);
|
|
798
|
+
inFlightDurableCommands.add(workspaceId);
|
|
799
|
+
}
|
|
800
|
+
function endDurableCommand(workspaceId) {
|
|
801
|
+
inFlightDurableCommands.delete(workspaceId);
|
|
802
|
+
}
|
|
803
|
+
async function readSharedSetupState(ctx) {
|
|
804
|
+
if (!ctx.options.setup) {
|
|
805
|
+
return null;
|
|
806
|
+
}
|
|
807
|
+
const sharedSetupId = sharedSetupRecordId(ctx);
|
|
808
|
+
if (!sharedSetupId) {
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
const setupState = await ctx.adapter.setupStates.getSetupState(sharedSetupId);
|
|
812
|
+
return setupState ? setupState.state : null;
|
|
813
|
+
}
|
|
814
|
+
async function persistSharedSetupState(ctx, state) {
|
|
815
|
+
const sharedSetupId = sharedSetupRecordId(ctx);
|
|
816
|
+
if (!sharedSetupId) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
await ctx.adapter.setupStates.putSetupState({
|
|
820
|
+
id: sharedSetupId,
|
|
821
|
+
state: {
|
|
822
|
+
kind: state.kind,
|
|
823
|
+
sessionId: state.sessionId,
|
|
824
|
+
state: state.state
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
async function clearSharedSetupState(ctx) {
|
|
829
|
+
const sharedSetupId = sharedSetupRecordId(ctx);
|
|
830
|
+
if (!sharedSetupId) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
await ctx.adapter.setupStates.deleteSetupState(sharedSetupId);
|
|
834
|
+
}
|
|
835
|
+
function isRecoverableSetupStateError(error) {
|
|
836
|
+
if (!(error instanceof Error)) {
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
return error.message.includes("Sandkit durable state corruption") && error.message.includes("sandkit_setup_states");
|
|
840
|
+
}
|
|
841
|
+
function assertSharedSetupAndPolicy(ctx) {
|
|
842
|
+
if (!ctx.options.setup) {
|
|
843
|
+
throw new Error("Sandkit setup is not configured.");
|
|
844
|
+
}
|
|
845
|
+
const { setup } = ctx.options;
|
|
846
|
+
if (!setup.policy) {
|
|
847
|
+
throw new Error("Shared setup policy is required.");
|
|
848
|
+
}
|
|
849
|
+
return setup;
|
|
850
|
+
}
|
|
851
|
+
async function bootstrapSharedSetupState(ctx, workspace, options) {
|
|
852
|
+
const setup = assertSharedSetupAndPolicy(ctx);
|
|
853
|
+
const sandbox = await ctx.driverFactory.createSandbox(workspace, {
|
|
854
|
+
...options,
|
|
855
|
+
policy: setup.policy
|
|
856
|
+
});
|
|
857
|
+
const result = await runCommandAndWait(sandbox, setup.command, setup.args);
|
|
858
|
+
if (result.exitCode !== 0) {
|
|
859
|
+
throw new Error(
|
|
860
|
+
`Workspace setup failed with exit code ${result.exitCode}. ${result.stderr.trim()}`.trim()
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
const state = await sandbox.snapshot();
|
|
864
|
+
await persistSharedSetupState(ctx, state);
|
|
865
|
+
return state;
|
|
866
|
+
}
|
|
867
|
+
async function runCommandAndWait(sandbox, command, args) {
|
|
868
|
+
const commandArgs = args ?? [];
|
|
869
|
+
return (await sandbox.runCommand(command, [...commandArgs])).wait();
|
|
870
|
+
}
|
|
871
|
+
async function resolveSharedSetupState(ctx, workspace, options) {
|
|
872
|
+
if (!ctx.options.setup) {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
assertSharedSetupAndPolicy(ctx);
|
|
876
|
+
try {
|
|
877
|
+
const setupState = await readSharedSetupState(ctx);
|
|
878
|
+
if (!setupState) {
|
|
879
|
+
return bootstrapSharedSetupState(ctx, workspace, options);
|
|
880
|
+
}
|
|
881
|
+
return setupState;
|
|
882
|
+
} catch (error) {
|
|
883
|
+
if (!isRecoverableSetupStateError(error)) {
|
|
884
|
+
throw error;
|
|
885
|
+
}
|
|
886
|
+
await clearSharedSetupState(ctx);
|
|
887
|
+
return bootstrapSharedSetupState(ctx, workspace, options);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
function createInternalSharedBootstrapWorkspaceRecord() {
|
|
891
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
892
|
+
return {
|
|
893
|
+
id: createId("sandkit-internal-bootstrap"),
|
|
894
|
+
status: "inactive",
|
|
895
|
+
createdAt: now,
|
|
896
|
+
updatedAt: now
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
async function bootstrapSharedSetup(ctx) {
|
|
900
|
+
if (!ctx.options.setup) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
const setup = assertSharedSetupAndPolicy(ctx);
|
|
904
|
+
const sharedSetupId = sharedSetupRecordId(ctx);
|
|
905
|
+
if (!sharedSetupId) {
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
const workspace = createInternalSharedBootstrapWorkspaceRecord();
|
|
909
|
+
const setupOptions = {
|
|
910
|
+
policy: setup.policy
|
|
911
|
+
};
|
|
912
|
+
let setupState;
|
|
913
|
+
try {
|
|
914
|
+
setupState = await readSharedSetupState(ctx);
|
|
915
|
+
} catch (error) {
|
|
916
|
+
if (!isRecoverableSetupStateError(error)) {
|
|
917
|
+
throw error;
|
|
918
|
+
}
|
|
919
|
+
await clearSharedSetupState(ctx);
|
|
920
|
+
setupState = null;
|
|
921
|
+
}
|
|
922
|
+
if (!setupState) {
|
|
923
|
+
await bootstrapSharedSetupState(ctx, workspace, setupOptions);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
709
926
|
var WorkspaceHandle = class {
|
|
710
927
|
#ctx;
|
|
711
928
|
#record;
|
|
@@ -729,7 +946,7 @@ var WorkspaceHandle = class {
|
|
|
729
946
|
get sandbox() {
|
|
730
947
|
if (!this.#lazySandbox) {
|
|
731
948
|
this.#lazySandbox = new LazySandboxHandle(
|
|
732
|
-
() => this.createOrResumeSandboxForCommand(),
|
|
949
|
+
(input) => this.createOrResumeSandboxForCommand(input),
|
|
733
950
|
(input) => this.openSession(input),
|
|
734
951
|
() => this.attachSession(),
|
|
735
952
|
() => this.getActiveLease()
|
|
@@ -759,19 +976,29 @@ var WorkspaceHandle = class {
|
|
|
759
976
|
}
|
|
760
977
|
return readWorkspaceSandboxLease(this.#record);
|
|
761
978
|
}
|
|
762
|
-
async createOrResumeSandboxForCommand() {
|
|
979
|
+
async createOrResumeSandboxForCommand(input) {
|
|
763
980
|
await this.resolveLatestWorkspace();
|
|
764
981
|
if (await this.resolveAttachableSession()) {
|
|
765
982
|
throw new Error(
|
|
766
983
|
"Cannot run command while a sandbox session is active. Use attachSession() to reuse it or commit the session first."
|
|
767
984
|
);
|
|
768
985
|
}
|
|
986
|
+
assertNoDurableCommandInFlight(this.#record.id);
|
|
987
|
+
beginDurableCommand(this.#record.id);
|
|
769
988
|
const workspace = await this.resolveLatestWorkspace();
|
|
770
|
-
|
|
771
|
-
|
|
989
|
+
try {
|
|
990
|
+
const sandbox = await this.resolveSandboxDriver(workspace, {
|
|
991
|
+
timeoutMs: normalizeRunCommandTimeoutMs(input?.timeoutMs)
|
|
992
|
+
});
|
|
993
|
+
return this.createManagedSandbox(sandbox);
|
|
994
|
+
} catch (error) {
|
|
995
|
+
endDurableCommand(this.#record.id);
|
|
996
|
+
throw error;
|
|
997
|
+
}
|
|
772
998
|
}
|
|
773
999
|
async openSession(input) {
|
|
774
1000
|
await this.resolveLatestWorkspace();
|
|
1001
|
+
assertNoDurableCommandInFlight(this.#record.id);
|
|
775
1002
|
if (await this.resolveAttachableSession()) {
|
|
776
1003
|
throw new Error("A sandbox session is already active for this workspace.");
|
|
777
1004
|
}
|
|
@@ -862,78 +1089,61 @@ var WorkspaceHandle = class {
|
|
|
862
1089
|
if (currentState) {
|
|
863
1090
|
return this.#ctx.driverFactory.resumeSandbox(workspace, currentState, options);
|
|
864
1091
|
}
|
|
1092
|
+
const setupState = await resolveSharedSetupState(this.#ctx, workspace, options);
|
|
1093
|
+
if (!setupState) {
|
|
1094
|
+
return this.#ctx.driverFactory.createSandbox(workspace, options);
|
|
1095
|
+
}
|
|
865
1096
|
try {
|
|
866
|
-
const setupState = await this.#readSharedSetupState();
|
|
867
|
-
if (!setupState) {
|
|
868
|
-
return this.#bootstrapSetupState(workspace, options);
|
|
869
|
-
}
|
|
870
1097
|
return await this.#ctx.driverFactory.resumeSandbox(workspace, setupState, options);
|
|
871
1098
|
} catch (error) {
|
|
872
|
-
if (!this.#ctx.driverFactory.isSessionUnavailableError?.(error) && !
|
|
1099
|
+
if (!this.#ctx.driverFactory.isSessionUnavailableError?.(error) && !isRecoverableSetupStateError(error)) {
|
|
873
1100
|
throw error;
|
|
874
1101
|
}
|
|
875
|
-
await this.#
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
}
|
|
879
|
-
async #bootstrapSetupState(workspace, options) {
|
|
880
|
-
const setup = this.#ctx.options.setup;
|
|
881
|
-
if (!setup) {
|
|
882
|
-
return this.#ctx.driverFactory.createSandbox(workspace, options);
|
|
883
|
-
}
|
|
884
|
-
const setupPolicy = setup.policy ?? options.policy;
|
|
885
|
-
const sandbox = await this.#ctx.driverFactory.createSandbox(workspace, {
|
|
886
|
-
...options,
|
|
887
|
-
policy: setupPolicy
|
|
888
|
-
});
|
|
889
|
-
const result = await sandbox.runCommand(setup.command, [...setup.args ?? []]);
|
|
890
|
-
if (result.exitCode !== 0) {
|
|
891
|
-
throw new Error(
|
|
892
|
-
`Workspace setup failed with exit code ${result.exitCode}. ${result.stderr.trim()}`.trim()
|
|
893
|
-
);
|
|
894
|
-
}
|
|
895
|
-
const setupState = await sandbox.snapshot();
|
|
896
|
-
await this.#persistSharedSetupState(setupState);
|
|
897
|
-
return this.#ctx.driverFactory.resumeSandbox(workspace, setupState, options);
|
|
898
|
-
}
|
|
899
|
-
async #readSharedSetupState() {
|
|
900
|
-
if (!this.#ctx.options.setup) {
|
|
901
|
-
return null;
|
|
902
|
-
}
|
|
903
|
-
const setupState = await this.#ctx.adapter.setupStates.getSetupState(
|
|
904
|
-
this.#sharedSetupStateId()
|
|
905
|
-
);
|
|
906
|
-
return setupState ? setupState.state : null;
|
|
907
|
-
}
|
|
908
|
-
async #persistSharedSetupState(state) {
|
|
909
|
-
await this.#ctx.adapter.setupStates.putSetupState({
|
|
910
|
-
id: this.#sharedSetupStateId(),
|
|
911
|
-
state: {
|
|
912
|
-
kind: state.kind,
|
|
913
|
-
sessionId: state.sessionId,
|
|
914
|
-
state: state.state
|
|
915
|
-
}
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
async #clearSharedSetupState() {
|
|
919
|
-
await this.#ctx.adapter.setupStates.deleteSetupState(this.#sharedSetupStateId());
|
|
920
|
-
}
|
|
921
|
-
#sharedSetupStateId() {
|
|
922
|
-
return sharedSetupStateId(this.#ctx.adapter.id, this.#ctx.options.setup);
|
|
923
|
-
}
|
|
924
|
-
#isRecoverableSetupStateError(error) {
|
|
925
|
-
if (!(error instanceof Error)) {
|
|
926
|
-
return false;
|
|
1102
|
+
await clearSharedSetupState(this.#ctx);
|
|
1103
|
+
const rerunSetupState = await bootstrapSharedSetupState(this.#ctx, workspace, options);
|
|
1104
|
+
return this.#ctx.driverFactory.resumeSandbox(workspace, rerunSetupState, options);
|
|
927
1105
|
}
|
|
928
|
-
return error.message.includes("Sandkit durable state corruption") && error.message.includes("sandkit_setup_states");
|
|
929
1106
|
}
|
|
930
1107
|
createManagedSandbox(sandbox) {
|
|
931
|
-
|
|
1108
|
+
const managed = new ManagedSandbox(
|
|
932
1109
|
sandbox,
|
|
933
1110
|
async () => this.resolveDefaultPolicy(),
|
|
934
1111
|
async (commit) => this.persistSandboxState(transitionAfterCommandCommit(commit, (/* @__PURE__ */ new Date()).toISOString())),
|
|
935
1112
|
this.createRunLifecycle(sandbox)
|
|
936
1113
|
);
|
|
1114
|
+
const workspaceId = this.#record.id;
|
|
1115
|
+
const originalRunCommand = managed.runCommand.bind(managed);
|
|
1116
|
+
const wrappedRunCommand = async (inputOrCommand, args = []) => {
|
|
1117
|
+
let releaseCalled = false;
|
|
1118
|
+
const release = async () => {
|
|
1119
|
+
if (releaseCalled) {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
releaseCalled = true;
|
|
1123
|
+
endDurableCommand(workspaceId);
|
|
1124
|
+
};
|
|
1125
|
+
try {
|
|
1126
|
+
const command = typeof inputOrCommand === "string" ? await originalRunCommand(inputOrCommand, args) : await originalRunCommand(inputOrCommand);
|
|
1127
|
+
const completion = (async () => {
|
|
1128
|
+
try {
|
|
1129
|
+
return await command.wait();
|
|
1130
|
+
} finally {
|
|
1131
|
+
await release();
|
|
1132
|
+
}
|
|
1133
|
+
})();
|
|
1134
|
+
void completion.catch(() => {
|
|
1135
|
+
});
|
|
1136
|
+
return {
|
|
1137
|
+
wait: () => completion,
|
|
1138
|
+
logs: command.logs
|
|
1139
|
+
};
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
await release();
|
|
1142
|
+
throw error;
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
managed.runCommand = wrappedRunCommand;
|
|
1146
|
+
return managed;
|
|
937
1147
|
}
|
|
938
1148
|
makeSandboxDriverOptions(policy, timeoutMs) {
|
|
939
1149
|
const next = {
|
|
@@ -1039,6 +1249,15 @@ function normalizeSessionTimeoutMs(timeoutMs) {
|
|
|
1039
1249
|
}
|
|
1040
1250
|
return timeoutMs;
|
|
1041
1251
|
}
|
|
1252
|
+
function normalizeRunCommandTimeoutMs(timeoutMs) {
|
|
1253
|
+
if (timeoutMs === void 0) {
|
|
1254
|
+
return void 0;
|
|
1255
|
+
}
|
|
1256
|
+
if (!Number.isInteger(timeoutMs) || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
1257
|
+
throw new Error("runCommand timeoutMs must be a positive integer in milliseconds.");
|
|
1258
|
+
}
|
|
1259
|
+
return timeoutMs;
|
|
1260
|
+
}
|
|
1042
1261
|
function workspaceStateIsSession(state) {
|
|
1043
1262
|
return state.kind === "session";
|
|
1044
1263
|
}
|
|
@@ -1052,6 +1271,9 @@ var Sandkit = class {
|
|
|
1052
1271
|
get context() {
|
|
1053
1272
|
return this.#ctx;
|
|
1054
1273
|
}
|
|
1274
|
+
async bootstrap() {
|
|
1275
|
+
await bootstrapSharedSetup(this.#ctx);
|
|
1276
|
+
}
|
|
1055
1277
|
async createWorkspace(input = {}) {
|
|
1056
1278
|
const { id, name, policy, metadata, status, sandboxId, lastResumedAt } = input;
|
|
1057
1279
|
const sandboxConfig = normalizeWorkspaceSandboxCreateConfig(input.sandbox);
|
|
@@ -1091,12 +1313,16 @@ export {
|
|
|
1091
1313
|
Sandkit,
|
|
1092
1314
|
aiGateway,
|
|
1093
1315
|
allowAll,
|
|
1316
|
+
allowBun,
|
|
1317
|
+
allowNpm,
|
|
1094
1318
|
allowService,
|
|
1095
1319
|
allowServices,
|
|
1320
|
+
bun,
|
|
1096
1321
|
codex,
|
|
1097
1322
|
createSandkit,
|
|
1098
1323
|
denyAll,
|
|
1099
1324
|
gemini,
|
|
1100
|
-
github
|
|
1325
|
+
github,
|
|
1326
|
+
npm
|
|
1101
1327
|
};
|
|
1102
1328
|
//# sourceMappingURL=index.js.map
|