@giselles-ai/agent 0.1.23 → 0.1.25

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.
@@ -7,7 +7,13 @@ function computeConfigHash(config) {
7
7
  files: (config.files ?? []).map((f) => ({
8
8
  path: f.path,
9
9
  content: f.content
10
- }))
10
+ })),
11
+ setup: config.setup?.script ?? null,
12
+ env: config.env ? Object.fromEntries(
13
+ Object.entries(config.env).sort(
14
+ ([a], [b]) => a < b ? -1 : a > b ? 1 : 0
15
+ )
16
+ ) : null
11
17
  });
12
18
  return createHash("sha256").update(payload).digest("hex").slice(0, 16);
13
19
  }
@@ -50,7 +56,9 @@ async function requestBuild(agent, options) {
50
56
  const requestBody = {
51
57
  config_hash: configHash,
52
58
  agent_type: agent.agentType ?? "gemini",
53
- files
59
+ files,
60
+ setup_script: agent.setup?.script ?? null,
61
+ env: agent.env ?? null
54
62
  };
55
63
  const requestHeaders = {
56
64
  "content-type": "application/json",
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AgentConfig, D as DefinedAgent } from './types-Cto-uejG.js';
2
- export { a as AgentFile } from './types-Cto-uejG.js';
1
+ import { A as AgentConfig, D as DefinedAgent } from './types-cRejduhB.js';
2
+ export { a as AgentFile, b as AgentSetup } from './types-cRejduhB.js';
3
3
 
4
4
  declare function defineAgent(config: AgentConfig): DefinedAgent;
5
5
 
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  computeConfigHash,
3
3
  requestBuild
4
- } from "./chunk-TAQV6ZOB.js";
4
+ } from "./chunk-JGH5DCA7.js";
5
5
 
6
6
  // src/define-agent.ts
7
7
  function defineAgent(config) {
@@ -9,6 +9,8 @@ function defineAgent(config) {
9
9
  agentType: config.agentType ?? "gemini",
10
10
  agentMd: config.agentMd,
11
11
  files: config.files ?? [],
12
+ env: config.env ?? {},
13
+ setup: config.setup,
12
14
  get snapshotId() {
13
15
  const id = process.env?.GISELLE_AGENT_SNAPSHOT_ID;
14
16
  if (!id) {
@@ -1,5 +1,5 @@
1
1
  import { NextConfig } from 'next';
2
- import { A as AgentConfig } from '../types-Cto-uejG.js';
2
+ import { A as AgentConfig } from '../types-cRejduhB.js';
3
3
 
4
4
  type GiselleAgentPluginOptions = {
5
5
  /** Base URL for the agent API. Default: process.env.GISELLE_AGENT_BASE_URL ?? "https://studio.giselles.ai/agent-api" */
@@ -1,9 +1,9 @@
1
1
  import {
2
+ computeConfigHash,
2
3
  requestBuild
3
- } from "../chunk-TAQV6ZOB.js";
4
+ } from "../chunk-JGH5DCA7.js";
4
5
 
5
6
  // src/next/with-giselle-agent.ts
6
- import crypto from "crypto";
7
7
  import fs from "fs";
8
8
  import { createRequire } from "module";
9
9
  import path from "path";
@@ -18,12 +18,7 @@ function resolveBaseUrl(options) {
18
18
  return (options?.baseUrl ?? process.env.GISELLE_AGENT_BASE_URL ?? "https://studio.giselles.ai/agent-api").replace(/\/+$/, "");
19
19
  }
20
20
  function getSnapshotFile(agent) {
21
- const key = {
22
- agentType: agent.agentType,
23
- agentMd: agent.agentMd,
24
- files: agent.files
25
- };
26
- const hash = crypto.createHash("sha256").update(JSON.stringify(key)).digest("hex").slice(0, 16);
21
+ const hash = computeConfigHash(agent);
27
22
  return path.join(process.cwd(), ".next", "giselle", hash);
28
23
  }
29
24
  function hasRunRecently() {
@@ -3,30 +3,6 @@ import { z } from 'zod';
3
3
  import { RelayRequest, RelayResponse } from '@giselles-ai/browser-tool';
4
4
  import { RelayRequestSubscription } from '@giselles-ai/browser-tool/relay';
5
5
 
6
- type AgentType$1 = "codex" | "gemini";
7
- declare class Agent {
8
- private _type;
9
- private _snapshotId;
10
- private _pendingOps;
11
- private constructor();
12
- static create(type: AgentType$1, options: {
13
- snapshotId: string;
14
- }): Agent;
15
- get type(): AgentType$1;
16
- get snapshotId(): string;
17
- get dirty(): boolean;
18
- addFiles(files: Array<{
19
- path: string;
20
- content: Buffer;
21
- }>): this;
22
- setAgentMd(content: string | Buffer): this;
23
- runCommands(commands: Array<{
24
- cmd: string;
25
- args?: string[];
26
- }>): this;
27
- prepare(): Promise<void>;
28
- }
29
-
30
6
  type BaseChatRequest = {
31
7
  message: string;
32
8
  session_id?: string;
@@ -143,6 +119,7 @@ type CloudChatSessionState = {
143
119
  chatId: string;
144
120
  agentSessionId?: string;
145
121
  sandboxId?: string;
122
+ snapshotId?: string;
146
123
  relay?: CloudRelaySession;
147
124
  pendingTool?: PendingToolState | null;
148
125
  updatedAt: number;
@@ -150,6 +127,7 @@ type CloudChatSessionState = {
150
127
  type CloudChatSessionPatch = {
151
128
  agentSessionId?: string;
152
129
  sandboxId?: string;
130
+ snapshotId?: string;
153
131
  relay?: CloudRelaySession;
154
132
  pendingTool?: PendingToolState | null;
155
133
  };
@@ -169,6 +147,7 @@ declare const cloudChatRunRequestSchema: z.ZodObject<{
169
147
  gemini: "gemini";
170
148
  }>;
171
149
  snapshot_id: z.ZodString;
150
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
172
151
  tool_results: z.ZodOptional<z.ZodArray<z.ZodObject<{
173
152
  toolCallId: z.ZodString;
174
153
  toolName: z.ZodEnum<{
@@ -251,4 +230,4 @@ declare function runCloudChat<TRequest extends CloudChatRequest & {
251
230
  }) => Promise<void>;
252
231
  }): Promise<Response>;
253
232
 
254
- export { Agent, type AgentApiOptions, type AgentApiStoreConfig, type AgentParam, type AgentRequest, type AgentType, type BaseChatRequest, type ChatAgent, type ChatCommand, type CloudChatRequest, type CloudChatRunRequest, type CloudChatSessionPatch, type CloudChatSessionState, type CloudChatStateStore, type CloudRelaySession, type CloudToolName, type CloudToolResult, type CreateAgentOptions, type PendingToolState, type RelaySessionFactoryResult, type RunChatImpl, type RunChatInput, type StdoutMapper, applyCloudChatPatch, cloudChatRunRequestSchema, createAgent, createAgentApi, createCodexAgent, createCodexStdoutMapper, createGeminiAgent, reduceCloudChatEvent, runChat, runCloudChat, toolNameFromRelayRequest };
233
+ export { type AgentApiOptions, type AgentApiStoreConfig, type AgentParam, type AgentRequest, type AgentType, type BaseChatRequest, type ChatAgent, type ChatCommand, type CloudChatRequest, type CloudChatRunRequest, type CloudChatSessionPatch, type CloudChatSessionState, type CloudChatStateStore, type CloudRelaySession, type CloudToolName, type CloudToolResult, type CreateAgentOptions, type PendingToolState, type RelaySessionFactoryResult, type RunChatImpl, type RunChatInput, type StdoutMapper, applyCloudChatPatch, cloudChatRunRequestSchema, createAgent, createAgentApi, createCodexAgent, createCodexStdoutMapper, createGeminiAgent, reduceCloudChatEvent, runChat, runCloudChat, toolNameFromRelayRequest };
@@ -1,87 +1,3 @@
1
- // src/agent.ts
2
- import { Sandbox } from "@vercel/sandbox";
3
- var Agent = class _Agent {
4
- _type;
5
- _snapshotId;
6
- _pendingOps = [];
7
- constructor(type, snapshotId) {
8
- this._type = type;
9
- this._snapshotId = snapshotId;
10
- }
11
- static create(type, options) {
12
- const trimmed = options.snapshotId.trim();
13
- if (!trimmed) {
14
- throw new Error("snapshotId is required.");
15
- }
16
- return new _Agent(type, trimmed);
17
- }
18
- get type() {
19
- return this._type;
20
- }
21
- get snapshotId() {
22
- return this._snapshotId;
23
- }
24
- get dirty() {
25
- return this._pendingOps.length > 0;
26
- }
27
- addFiles(files) {
28
- if (files.length === 0) {
29
- return this;
30
- }
31
- this._pendingOps.push({
32
- kind: "writeFiles",
33
- files
34
- });
35
- return this;
36
- }
37
- setAgentMd(content) {
38
- const buffer = typeof content === "string" ? Buffer.from(content) : content;
39
- console.log(`[agent] setAgentMd called, content length=${buffer.length}`);
40
- return this.addFiles([
41
- { path: "/home/vercel-sandbox/.codex/AGENTS.md", content: buffer }
42
- ]);
43
- }
44
- runCommands(commands) {
45
- for (const command of commands) {
46
- this._pendingOps.push({
47
- kind: "runCommand",
48
- cmd: command.cmd,
49
- args: command.args ?? []
50
- });
51
- }
52
- return this;
53
- }
54
- async prepare() {
55
- console.log(
56
- `[agent] prepare called, dirty=${this.dirty}, pendingOps=${this._pendingOps.length}`
57
- );
58
- if (!this.dirty) {
59
- return;
60
- }
61
- const ops = this._pendingOps;
62
- const sandbox = await Sandbox.create({
63
- source: { type: "snapshot", snapshotId: this._snapshotId }
64
- });
65
- console.log(
66
- `[sandbox] created sandbox=${sandbox.sandboxId} from snapshot=${this._snapshotId}`
67
- );
68
- for (const op of ops) {
69
- switch (op.kind) {
70
- case "writeFiles":
71
- await sandbox.writeFiles(op.files);
72
- break;
73
- case "runCommand":
74
- await sandbox.runCommand(op.cmd, op.args);
75
- break;
76
- }
77
- }
78
- const snapshot = await sandbox.snapshot();
79
- console.log(`[agent] prepare done, new snapshotId=${snapshot.snapshotId}`);
80
- this._snapshotId = snapshot.snapshotId;
81
- this._pendingOps = [];
82
- }
83
- };
84
-
85
1
  // src/agent-api.ts
86
2
  import {
87
3
  createRelayHandler,
@@ -89,7 +5,7 @@ import {
89
5
  } from "@giselles-ai/browser-tool/relay";
90
6
 
91
7
  // src/build.ts
92
- import { Sandbox as Sandbox2 } from "@vercel/sandbox";
8
+ import { Sandbox } from "@vercel/sandbox";
93
9
  var CACHE_KEY_PREFIX = "agent-build:snapshot:";
94
10
  var CACHE_TTL_SEC = 60 * 60 * 24;
95
11
  var memoryCache = /* @__PURE__ */ new Map();
@@ -135,6 +51,8 @@ function parseBuildRequest(body) {
135
51
  const configHash = record.config_hash;
136
52
  const agentType = record.agent_type;
137
53
  const files = record.files;
54
+ const setupScript = record.setup_script;
55
+ const rawEnv = record.env;
138
56
  if (typeof configHash !== "string" || !configHash.trim()) {
139
57
  return null;
140
58
  }
@@ -145,6 +63,8 @@ function parseBuildRequest(body) {
145
63
  return null;
146
64
  }
147
65
  const parsedFiles = [];
66
+ let parsedSetupScript = null;
67
+ let parsedEnv = null;
148
68
  for (const file of files) {
149
69
  if (!file || typeof file !== "object" || Array.isArray(file)) {
150
70
  return null;
@@ -158,10 +78,30 @@ function parseBuildRequest(body) {
158
78
  content: recordFile.content
159
79
  });
160
80
  }
81
+ if (setupScript !== void 0 && setupScript !== null) {
82
+ if (typeof setupScript !== "string") {
83
+ return null;
84
+ }
85
+ parsedSetupScript = setupScript;
86
+ }
87
+ if (rawEnv !== void 0 && rawEnv !== null) {
88
+ if (typeof rawEnv !== "object" || Array.isArray(rawEnv)) {
89
+ return null;
90
+ }
91
+ const envRecord = rawEnv;
92
+ for (const value of Object.values(envRecord)) {
93
+ if (typeof value !== "string") {
94
+ return null;
95
+ }
96
+ }
97
+ parsedEnv = envRecord;
98
+ }
161
99
  return {
162
100
  config_hash: configHash.trim(),
163
101
  agent_type: agentType,
164
- files: parsedFiles
102
+ files: parsedFiles,
103
+ setup_script: parsedSetupScript,
104
+ env: parsedEnv
165
105
  };
166
106
  }
167
107
  async function buildAgent(input) {
@@ -193,7 +133,7 @@ async function buildAgent(input) {
193
133
  const response2 = { snapshot_id: cached, cached: true };
194
134
  return Response.json(response2);
195
135
  }
196
- const sandbox = await Sandbox2.create({
136
+ const sandbox = await Sandbox.create({
197
137
  source: { type: "snapshot", snapshotId: baseSnapshotId }
198
138
  });
199
139
  console.log(
@@ -207,6 +147,21 @@ async function buildAgent(input) {
207
147
  }))
208
148
  );
209
149
  }
150
+ if (parsed.setup_script) {
151
+ console.log("[agent-build] running setup script...");
152
+ const result = await sandbox.runCommand({
153
+ cmd: "bash",
154
+ args: ["-lc", parsed.setup_script],
155
+ ...parsed.env ? { env: parsed.env } : {}
156
+ });
157
+ if (result.exitCode !== 0) {
158
+ const stderr = typeof result.stderr === "string" ? result.stderr : "";
159
+ throw new Error(
160
+ `Setup script failed (exit ${result.exitCode}): ${stderr}`
161
+ );
162
+ }
163
+ console.log("[agent-build] setup script completed");
164
+ }
210
165
  const snapshot = await sandbox.snapshot();
211
166
  console.log(`[agent-build] snapshot created: ${snapshot.snapshotId}`);
212
167
  await cache.set(cacheKey, snapshot.snapshotId);
@@ -443,7 +398,12 @@ function createCodexAgent(options = {}) {
443
398
  return {
444
399
  cmd: "codex",
445
400
  args,
446
- env: { CODEX_API_KEY: apiKey }
401
+ env: Object.fromEntries(
402
+ Object.entries({
403
+ ...env,
404
+ CODEX_API_KEY: apiKey
405
+ }).filter((e) => e[1] != null)
406
+ )
447
407
  };
448
408
  },
449
409
  createStdoutMapper() {
@@ -585,9 +545,12 @@ function createGeminiAgent(options = {}) {
585
545
  return {
586
546
  cmd: "gemini",
587
547
  args,
588
- env: {
589
- GEMINI_API_KEY: requiredEnv2(env, "GEMINI_API_KEY")
590
- }
548
+ env: Object.fromEntries(
549
+ Object.entries({
550
+ ...env,
551
+ GEMINI_API_KEY: requiredEnv2(env, "GEMINI_API_KEY")
552
+ }).filter((e) => e[1] != null)
553
+ )
591
554
  };
592
555
  }
593
556
  };
@@ -633,7 +596,7 @@ function createAgent(options) {
633
596
 
634
597
  // src/chat-run.ts
635
598
  import { Writable } from "stream";
636
- import { Sandbox as Sandbox3 } from "@vercel/sandbox";
599
+ import { Sandbox as Sandbox2 } from "@vercel/sandbox";
637
600
  function emitText(controller, text, encoder) {
638
601
  if (text.length === 0) {
639
602
  return;
@@ -687,23 +650,39 @@ function runChat(input) {
687
650
  const mapper = input.agent.createStdoutMapper?.();
688
651
  void (async () => {
689
652
  try {
690
- const sandbox = parsed.sandbox_id ? await Sandbox3.get({ sandboxId: parsed.sandbox_id }) : await (async () => {
691
- const snapshotId = parsed.snapshot_id?.trim() || input.agent.snapshotId?.trim();
692
- if (!snapshotId) {
693
- throw new Error(
694
- "Agent must provide snapshotId when sandbox_id is not provided."
695
- );
696
- }
697
- const created = await Sandbox3.create({
653
+ const createFromSnapshot = async (snapshotId2) => {
654
+ const created = await Sandbox2.create({
698
655
  source: {
699
656
  type: "snapshot",
700
- snapshotId
657
+ snapshotId: snapshotId2
701
658
  }
702
659
  });
703
660
  console.log(
704
- `[sandbox] created sandbox=${created.sandboxId} from snapshot=${snapshotId}`
661
+ `[sandbox] created sandbox=${created.sandboxId} from snapshot=${snapshotId2}`
705
662
  );
706
663
  return created;
664
+ };
665
+ const snapshotId = parsed.snapshot_id?.trim() || input.agent.snapshotId?.trim();
666
+ const sandbox = await (async () => {
667
+ if (parsed.sandbox_id) {
668
+ try {
669
+ return await Sandbox2.get({ sandboxId: parsed.sandbox_id });
670
+ } catch (error) {
671
+ if (!snapshotId) {
672
+ throw error;
673
+ }
674
+ console.log(
675
+ `[sandbox] sandbox=${parsed.sandbox_id} expired, recreating from snapshot=${snapshotId}`
676
+ );
677
+ return createFromSnapshot(snapshotId);
678
+ }
679
+ }
680
+ if (!snapshotId) {
681
+ throw new Error(
682
+ "Agent must provide snapshotId when sandbox_id is not provided."
683
+ );
684
+ }
685
+ return createFromSnapshot(snapshotId);
707
686
  })();
708
687
  enqueueEvent({ type: "sandbox", sandbox_id: sandbox.sandboxId });
709
688
  await input.agent.prepareSandbox({
@@ -740,6 +719,11 @@ function runChat(input) {
740
719
  }),
741
720
  signal: abortController.signal
742
721
  });
722
+ const snapshot = await sandbox.snapshot();
723
+ enqueueEvent({
724
+ type: "snapshot",
725
+ snapshot_id: snapshot.snapshotId
726
+ });
743
727
  } catch (error) {
744
728
  if (abortController.signal.aborted) {
745
729
  return;
@@ -855,6 +839,9 @@ function reduceCloudChatEvent(event) {
855
839
  if (event.type === "sandbox" && typeof event.sandbox_id === "string") {
856
840
  return { sandboxId: event.sandbox_id };
857
841
  }
842
+ if (event.type === "snapshot" && typeof event.snapshot_id === "string") {
843
+ return { snapshotId: event.snapshot_id };
844
+ }
858
845
  if (event.type === "relay.session" && typeof event.sessionId === "string" && typeof event.token === "string" && typeof event.relayUrl === "string" && typeof event.expiresAt === "number") {
859
846
  return {
860
847
  relay: {
@@ -882,6 +869,7 @@ var cloudChatRunRequestSchema = z3.object({
882
869
  message: z3.string().min(1),
883
870
  agent_type: z3.enum(["gemini", "codex"]),
884
871
  snapshot_id: z3.string().min(1),
872
+ env: z3.record(z3.string(), z3.string()).optional(),
885
873
  tool_results: z3.array(
886
874
  z3.object({
887
875
  toolCallId: z3.string().min(1),
@@ -895,6 +883,7 @@ function applyCloudChatPatch(input) {
895
883
  chatId: input.chatId,
896
884
  agentSessionId: input.patch?.agentSessionId ?? input.base?.agentSessionId,
897
885
  sandboxId: input.patch?.sandboxId ?? input.base?.sandboxId,
886
+ snapshotId: input.patch?.snapshotId ?? input.base?.snapshotId,
898
887
  relay: input.patch?.relay ?? input.base?.relay,
899
888
  pendingTool: input.patch?.pendingTool !== void 0 ? input.patch.pendingTool : input.base?.pendingTool,
900
889
  updatedAt: input.now
@@ -1016,6 +1005,7 @@ async function runCloudChat(input) {
1016
1005
  ...input.request,
1017
1006
  ...existing?.agentSessionId ? { session_id: existing.agentSessionId } : {},
1018
1007
  ...existing?.sandboxId ? { sandbox_id: existing.sandboxId } : {},
1008
+ ...existing?.snapshotId ? { snapshot_id: existing.snapshotId } : {},
1019
1009
  relay_session_id: relaySession.sessionId,
1020
1010
  relay_token: relaySession.token
1021
1011
  };
@@ -1116,6 +1106,7 @@ async function resumeCloudChat(input) {
1116
1106
  ...input.request,
1117
1107
  ...input.existing.agentSessionId ? { session_id: input.existing.agentSessionId } : {},
1118
1108
  ...input.existing.sandboxId ? { sandbox_id: input.existing.sandboxId } : {},
1109
+ ...input.existing.snapshotId ? { snapshot_id: input.existing.snapshotId } : {},
1119
1110
  relay_session_id: relaySession.sessionId,
1120
1111
  relay_token: relaySession.token
1121
1112
  };
@@ -1503,12 +1494,17 @@ function createAgentApi(options) {
1503
1494
  chat_id: parsed.data.chat_id,
1504
1495
  agent_type: parsed.data.agent_type,
1505
1496
  snapshot_id: parsed.data.snapshot_id,
1497
+ env: parsed.data.env,
1506
1498
  tool_results: parsed.data.tool_results
1507
1499
  },
1508
1500
  agent: {
1509
1501
  ...agentOptions,
1510
1502
  type: parsed.data.agent_type,
1511
- snapshotId: parsed.data.snapshot_id
1503
+ snapshotId: parsed.data.snapshot_id,
1504
+ env: {
1505
+ ...parsed.data.env,
1506
+ ...agentOptions.env
1507
+ }
1512
1508
  },
1513
1509
  signal: request.signal,
1514
1510
  store: await getStore(),
@@ -1584,7 +1580,6 @@ function createAgentApi(options) {
1584
1580
  };
1585
1581
  }
1586
1582
  export {
1587
- Agent,
1588
1583
  applyCloudChatPatch,
1589
1584
  cloudChatRunRequestSchema,
1590
1585
  createAgent,
@@ -2,20 +2,32 @@ type AgentFile = {
2
2
  path: string;
3
3
  content: string;
4
4
  };
5
+ type AgentSetup = {
6
+ /** Shell script to run inside the sandbox during build. Executed as `bash -lc`. */
7
+ script: string;
8
+ };
5
9
  type AgentConfig = {
6
10
  /** Agent type. Defaults to "gemini". */
7
11
  agentType?: "gemini" | "codex";
8
12
  /** Content for AGENTS.md in the sandbox. */
9
13
  agentMd?: string;
14
+ /** Environment variables passed to the sandbox at build and run time. */
15
+ env?: Record<string, string>;
10
16
  /** Additional files to write into the sandbox. */
11
17
  files?: AgentFile[];
18
+ /** Setup configuration for the sandbox build phase. */
19
+ setup?: AgentSetup;
12
20
  };
13
21
  type DefinedAgent = {
14
22
  readonly agentType: "gemini" | "codex";
15
23
  readonly agentMd?: string;
16
24
  readonly files: AgentFile[];
25
+ /** Setup configuration. Undefined when no setup is configured. */
26
+ readonly setup?: AgentSetup;
27
+ /** Environment variables. */
28
+ readonly env: Record<string, string>;
17
29
  /** Snapshot ID resolved from env at runtime. Throws if not set. */
18
30
  readonly snapshotId: string;
19
31
  };
20
32
 
21
- export type { AgentConfig as A, DefinedAgent as D, AgentFile as a };
33
+ export type { AgentConfig as A, DefinedAgent as D, AgentFile as a, AgentSetup as b };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@giselles-ai/agent",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "Apache-2.0",
@@ -37,8 +37,8 @@
37
37
  "format": "pnpm exec biome check --write ."
38
38
  },
39
39
  "dependencies": {
40
- "@giselles-ai/browser-tool": "0.1.23",
41
- "@vercel/sandbox": "1.6.0",
40
+ "@giselles-ai/browser-tool": "0.1.25",
41
+ "@vercel/sandbox": "1.8.1",
42
42
  "@iarna/toml": "3.0.0",
43
43
  "zod": "4.3.6"
44
44
  },