@polos/sdk 0.2.0 → 0.2.1

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/dist/index.d.cts CHANGED
@@ -4787,9 +4787,9 @@ declare function stripAnsi(text: string): string;
4787
4787
  declare function createExecTool(getEnv: () => Promise<ExecutionEnvironment>, config?: ExecToolConfig): ToolWorkflow;
4788
4788
 
4789
4789
  /**
4790
- * Path-based approval for read-only sandbox tools.
4790
+ * Path-based approval for sandbox tools.
4791
4791
  *
4792
- * When pathRestriction is set, read-only tools (read, glob, grep) allow
4792
+ * When pathRestriction is set, tools (read, write, edit, glob, grep) allow
4793
4793
  * operations within the restricted path without approval. Operations
4794
4794
  * outside the restriction suspend for user approval.
4795
4795
  */
@@ -4816,21 +4816,43 @@ declare function createReadTool(getEnv: () => Promise<ExecutionEnvironment>, pat
4816
4816
 
4817
4817
  /**
4818
4818
  * Write tool — create or overwrite files in the execution environment.
4819
+ *
4820
+ * When pathRestriction is set, writes within the restriction proceed
4821
+ * without approval. Writes outside the restriction suspend for user approval.
4822
+ * Set approval to 'always' to require approval for every write, or 'none'
4823
+ * to skip approval entirely (overrides path restriction).
4819
4824
  */
4820
4825
 
4826
+ interface WriteToolConfig {
4827
+ /** Explicit approval override. 'always' = approve every write, 'none' = never approve. */
4828
+ approval?: ToolApproval;
4829
+ /** Path restriction config — writes inside are allowed, outside require approval. */
4830
+ pathConfig?: PathRestrictionConfig;
4831
+ }
4821
4832
  /**
4822
4833
  * Create the write tool for writing file contents.
4823
4834
  */
4824
- declare function createWriteTool(getEnv: () => Promise<ExecutionEnvironment>, approval?: ToolApproval): ToolWorkflow;
4835
+ declare function createWriteTool(getEnv: () => Promise<ExecutionEnvironment>, config?: WriteToolConfig): ToolWorkflow;
4825
4836
 
4826
4837
  /**
4827
4838
  * Edit tool — find-and-replace text in files in the execution environment.
4839
+ *
4840
+ * When pathRestriction is set, edits within the restriction proceed
4841
+ * without approval. Edits outside the restriction suspend for user approval.
4842
+ * Set approval to 'always' to require approval for every edit, or 'none'
4843
+ * to skip approval entirely (overrides path restriction).
4828
4844
  */
4829
4845
 
4846
+ interface EditToolConfig {
4847
+ /** Explicit approval override. 'always' = approve every edit, 'none' = never approve. */
4848
+ approval?: ToolApproval;
4849
+ /** Path restriction config — edits inside are allowed, outside require approval. */
4850
+ pathConfig?: PathRestrictionConfig;
4851
+ }
4830
4852
  /**
4831
4853
  * Create the edit tool for find-and-replace in files.
4832
4854
  */
4833
- declare function createEditTool(getEnv: () => Promise<ExecutionEnvironment>, approval?: ToolApproval): ToolWorkflow;
4855
+ declare function createEditTool(getEnv: () => Promise<ExecutionEnvironment>, config?: EditToolConfig): ToolWorkflow;
4834
4856
 
4835
4857
  /**
4836
4858
  * Glob tool — find files by pattern in the execution environment.
package/dist/index.d.ts CHANGED
@@ -4787,9 +4787,9 @@ declare function stripAnsi(text: string): string;
4787
4787
  declare function createExecTool(getEnv: () => Promise<ExecutionEnvironment>, config?: ExecToolConfig): ToolWorkflow;
4788
4788
 
4789
4789
  /**
4790
- * Path-based approval for read-only sandbox tools.
4790
+ * Path-based approval for sandbox tools.
4791
4791
  *
4792
- * When pathRestriction is set, read-only tools (read, glob, grep) allow
4792
+ * When pathRestriction is set, tools (read, write, edit, glob, grep) allow
4793
4793
  * operations within the restricted path without approval. Operations
4794
4794
  * outside the restriction suspend for user approval.
4795
4795
  */
@@ -4816,21 +4816,43 @@ declare function createReadTool(getEnv: () => Promise<ExecutionEnvironment>, pat
4816
4816
 
4817
4817
  /**
4818
4818
  * Write tool — create or overwrite files in the execution environment.
4819
+ *
4820
+ * When pathRestriction is set, writes within the restriction proceed
4821
+ * without approval. Writes outside the restriction suspend for user approval.
4822
+ * Set approval to 'always' to require approval for every write, or 'none'
4823
+ * to skip approval entirely (overrides path restriction).
4819
4824
  */
4820
4825
 
4826
+ interface WriteToolConfig {
4827
+ /** Explicit approval override. 'always' = approve every write, 'none' = never approve. */
4828
+ approval?: ToolApproval;
4829
+ /** Path restriction config — writes inside are allowed, outside require approval. */
4830
+ pathConfig?: PathRestrictionConfig;
4831
+ }
4821
4832
  /**
4822
4833
  * Create the write tool for writing file contents.
4823
4834
  */
4824
- declare function createWriteTool(getEnv: () => Promise<ExecutionEnvironment>, approval?: ToolApproval): ToolWorkflow;
4835
+ declare function createWriteTool(getEnv: () => Promise<ExecutionEnvironment>, config?: WriteToolConfig): ToolWorkflow;
4825
4836
 
4826
4837
  /**
4827
4838
  * Edit tool — find-and-replace text in files in the execution environment.
4839
+ *
4840
+ * When pathRestriction is set, edits within the restriction proceed
4841
+ * without approval. Edits outside the restriction suspend for user approval.
4842
+ * Set approval to 'always' to require approval for every edit, or 'none'
4843
+ * to skip approval entirely (overrides path restriction).
4828
4844
  */
4829
4845
 
4846
+ interface EditToolConfig {
4847
+ /** Explicit approval override. 'always' = approve every edit, 'none' = never approve. */
4848
+ approval?: ToolApproval;
4849
+ /** Path restriction config — edits inside are allowed, outside require approval. */
4850
+ pathConfig?: PathRestrictionConfig;
4851
+ }
4830
4852
  /**
4831
4853
  * Create the edit tool for find-and-replace in files.
4832
4854
  */
4833
- declare function createEditTool(getEnv: () => Promise<ExecutionEnvironment>, approval?: ToolApproval): ToolWorkflow;
4855
+ declare function createEditTool(getEnv: () => Promise<ExecutionEnvironment>, config?: EditToolConfig): ToolWorkflow;
4834
4856
 
4835
4857
  /**
4836
4858
  * Glob tool — find files by pattern in the execution environment.
package/dist/index.js CHANGED
@@ -292,7 +292,7 @@ var OrchestratorClient = class {
292
292
  }
293
293
  if (attempt < retries) {
294
294
  const delay = Math.min(1e3 * Math.pow(2, attempt), 16e3);
295
- await new Promise((resolve8) => setTimeout(resolve8, delay));
295
+ await new Promise((resolve10) => setTimeout(resolve10, delay));
296
296
  }
297
297
  }
298
298
  }
@@ -744,7 +744,7 @@ var OrchestratorClient = class {
744
744
  if (execution.status === "completed" || execution.status === "failed" || execution.status === "cancelled") {
745
745
  return execution;
746
746
  }
747
- await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
747
+ await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
748
748
  }
749
749
  throw new Error(`Execution ${executionId} timed out after ${String(timeout)}ms`);
750
750
  }
@@ -1670,7 +1670,7 @@ function calculateDelay(attempt, options) {
1670
1670
  return Math.round(delay);
1671
1671
  }
1672
1672
  function sleep(ms) {
1673
- return new Promise((resolve8) => setTimeout(resolve8, ms));
1673
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
1674
1674
  }
1675
1675
  async function retry(fn, options = {}) {
1676
1676
  const opts = { ...DEFAULT_OPTIONS, ...options };
@@ -1856,7 +1856,7 @@ function createStepHelper(options) {
1856
1856
  if (options2.days) totalSeconds += options2.days * 86400;
1857
1857
  if (options2.weeks) totalSeconds += options2.weeks * 604800;
1858
1858
  const totalMs = totalSeconds * 1e3;
1859
- await new Promise((resolve8) => setTimeout(resolve8, totalMs));
1859
+ await new Promise((resolve10) => setTimeout(resolve10, totalMs));
1860
1860
  store.set(key, { wait_until: new Date(Date.now() + totalMs).toISOString() });
1861
1861
  },
1862
1862
  async waitUntil(key, date) {
@@ -1864,7 +1864,7 @@ function createStepHelper(options) {
1864
1864
  if (cached) return;
1865
1865
  const now = Date.now();
1866
1866
  const waitMs = Math.max(0, date.getTime() - now);
1867
- await new Promise((resolve8) => setTimeout(resolve8, waitMs));
1867
+ await new Promise((resolve10) => setTimeout(resolve10, waitMs));
1868
1868
  store.set(key, { wait_until: date.toISOString() });
1869
1869
  },
1870
1870
  // eslint-disable-next-line @typescript-eslint/require-await -- stub implementation
@@ -4504,7 +4504,7 @@ function createOrchestratorStepHelper(orchestratorClient, cachedSteps, execCtx,
4504
4504
  });
4505
4505
  const waitThreshold = Number(process.env["POLOS_WAIT_THRESHOLD_SECONDS"] ?? "10");
4506
4506
  if (totalSeconds <= waitThreshold) {
4507
- await new Promise((resolve8) => setTimeout(resolve8, totalSeconds * 1e3));
4507
+ await new Promise((resolve10) => setTimeout(resolve10, totalSeconds * 1e3));
4508
4508
  await saveStepOutput(key, { wait_until: waitUntil.toISOString() });
4509
4509
  return;
4510
4510
  }
@@ -4540,7 +4540,7 @@ function createOrchestratorStepHelper(orchestratorClient, cachedSteps, execCtx,
4540
4540
  });
4541
4541
  const waitThreshold = Number(process.env["POLOS_WAIT_THRESHOLD_SECONDS"] ?? "10");
4542
4542
  if (waitSeconds <= waitThreshold) {
4543
- await new Promise((resolve8) => setTimeout(resolve8, waitSeconds * 1e3));
4543
+ await new Promise((resolve10) => setTimeout(resolve10, waitSeconds * 1e3));
4544
4544
  await saveStepOutput(key, { wait_until: date.toISOString() });
4545
4545
  return;
4546
4546
  }
@@ -5293,7 +5293,7 @@ var DEFAULT_CONTAINER_WORKDIR = "/workspace";
5293
5293
  var DEFAULT_TIMEOUT_SECONDS = 300;
5294
5294
  var DEFAULT_MAX_OUTPUT_CHARS = 1e5;
5295
5295
  function spawnCommand(command, args, options) {
5296
- return new Promise((resolve8, reject) => {
5296
+ return new Promise((resolve10, reject) => {
5297
5297
  let settled = false;
5298
5298
  const settle = (fn) => {
5299
5299
  if (!settled) {
@@ -5326,13 +5326,13 @@ function spawnCommand(command, args, options) {
5326
5326
  clearTimeout(timer);
5327
5327
  settle(() => {
5328
5328
  if (killed) {
5329
- resolve8({
5329
+ resolve10({
5330
5330
  exitCode: 137,
5331
5331
  stdout,
5332
5332
  stderr: stderr + "\n[Process killed: timeout exceeded]"
5333
5333
  });
5334
5334
  } else {
5335
- resolve8({ exitCode: code ?? 1, stdout, stderr });
5335
+ resolve10({ exitCode: code ?? 1, stdout, stderr });
5336
5336
  }
5337
5337
  });
5338
5338
  });
@@ -5549,7 +5549,7 @@ var DockerEnvironment = class {
5549
5549
  var DEFAULT_TIMEOUT_SECONDS2 = 300;
5550
5550
  var DEFAULT_MAX_OUTPUT_CHARS2 = 1e5;
5551
5551
  function spawnLocal(command, options) {
5552
- return new Promise((resolve8, reject) => {
5552
+ return new Promise((resolve10, reject) => {
5553
5553
  let settled = false;
5554
5554
  const settle = (fn) => {
5555
5555
  if (!settled) {
@@ -5586,13 +5586,13 @@ function spawnLocal(command, options) {
5586
5586
  clearTimeout(timer);
5587
5587
  settle(() => {
5588
5588
  if (killed) {
5589
- resolve8({
5589
+ resolve10({
5590
5590
  exitCode: 137,
5591
5591
  stdout,
5592
5592
  stderr: stderr + "\n[Process killed: timeout exceeded]"
5593
5593
  });
5594
5594
  } else {
5595
- resolve8({ exitCode: code ?? 1, stdout, stderr });
5595
+ resolve10({ exitCode: code ?? 1, stdout, stderr });
5596
5596
  }
5597
5597
  });
5598
5598
  });
@@ -6000,8 +6000,8 @@ var SandboxManager = class {
6000
6000
  }
6001
6001
  let resolveLock;
6002
6002
  let rejectLock;
6003
- const lockPromise = new Promise((resolve8, reject) => {
6004
- resolveLock = resolve8;
6003
+ const lockPromise = new Promise((resolve10, reject) => {
6004
+ resolveLock = resolve10;
6005
6005
  rejectLock = reject;
6006
6006
  });
6007
6007
  this.sessionCreationLocks.set(ctx.sessionId, lockPromise);
@@ -6193,7 +6193,7 @@ var SandboxManager = class {
6193
6193
  }
6194
6194
  };
6195
6195
  function spawnSimple(command, args) {
6196
- return new Promise((resolve8, reject) => {
6196
+ return new Promise((resolve10, reject) => {
6197
6197
  const proc = spawn(command, args, { stdio: ["pipe", "pipe", "pipe"] });
6198
6198
  let stdout = "";
6199
6199
  let stderr = "";
@@ -6204,7 +6204,7 @@ function spawnSimple(command, args) {
6204
6204
  stderr += data.toString();
6205
6205
  });
6206
6206
  proc.on("close", (code) => {
6207
- resolve8({ exitCode: code ?? 1, stdout, stderr });
6207
+ resolve10({ exitCode: code ?? 1, stdout, stderr });
6208
6208
  });
6209
6209
  proc.on("error", reject);
6210
6210
  });
@@ -6339,10 +6339,10 @@ var Worker = class {
6339
6339
  process.on("SIGINT", signalHandler);
6340
6340
  process.on("SIGTERM", signalHandler);
6341
6341
  this.signalHandler = signalHandler;
6342
- await new Promise((resolve8) => {
6342
+ await new Promise((resolve10) => {
6343
6343
  const checkState = () => {
6344
6344
  if (this.state === "stopping" || this.state === "stopped") {
6345
- resolve8();
6345
+ resolve10();
6346
6346
  } else {
6347
6347
  setTimeout(checkState, 100);
6348
6348
  }
@@ -6376,7 +6376,7 @@ var Worker = class {
6376
6376
  const waitTimeout = 3e4;
6377
6377
  const waitStart = Date.now();
6378
6378
  while (this.activeExecutions.size > 0 && Date.now() - waitStart < waitTimeout) {
6379
- await new Promise((resolve8) => setTimeout(resolve8, 100));
6379
+ await new Promise((resolve10) => setTimeout(resolve10, 100));
6380
6380
  }
6381
6381
  if (this.activeExecutions.size > 0) {
6382
6382
  logger9.warn(`${String(this.activeExecutions.size)} executions did not complete in time`);
@@ -7481,7 +7481,7 @@ function createReadTool(getEnv, pathConfig) {
7481
7481
  }
7482
7482
  );
7483
7483
  }
7484
- function createWriteTool(getEnv, approval) {
7484
+ function createWriteTool(getEnv, config) {
7485
7485
  return defineTool(
7486
7486
  {
7487
7487
  id: "write",
@@ -7490,16 +7490,23 @@ function createWriteTool(getEnv, approval) {
7490
7490
  path: z.string().describe("Path to the file to write"),
7491
7491
  content: z.string().describe("Content to write to the file")
7492
7492
  }),
7493
- approval
7493
+ // Only use blanket approval if explicitly set to 'always'
7494
+ approval: config?.approval === "always" ? "always" : void 0
7494
7495
  },
7495
- async (_ctx, input) => {
7496
+ async (ctx, input) => {
7496
7497
  const env = await getEnv();
7498
+ if (!config?.approval && config?.pathConfig?.pathRestriction) {
7499
+ const resolved = resolve(env.getCwd(), input.path);
7500
+ if (!isPathAllowed(resolved, config.pathConfig.pathRestriction)) {
7501
+ await requirePathApproval(ctx, "write", resolved, config.pathConfig.pathRestriction);
7502
+ }
7503
+ }
7497
7504
  await env.writeFile(input.path, input.content);
7498
7505
  return { success: true, path: input.path };
7499
7506
  }
7500
7507
  );
7501
7508
  }
7502
- function createEditTool(getEnv, approval) {
7509
+ function createEditTool(getEnv, config) {
7503
7510
  return defineTool(
7504
7511
  {
7505
7512
  id: "edit",
@@ -7509,10 +7516,17 @@ function createEditTool(getEnv, approval) {
7509
7516
  old_text: z.string().describe("Exact text to find and replace"),
7510
7517
  new_text: z.string().describe("Text to replace the old_text with")
7511
7518
  }),
7512
- approval
7519
+ // Only use blanket approval if explicitly set to 'always'
7520
+ approval: config?.approval === "always" ? "always" : void 0
7513
7521
  },
7514
- async (_ctx, input) => {
7522
+ async (ctx, input) => {
7515
7523
  const env = await getEnv();
7524
+ if (!config?.approval && config?.pathConfig?.pathRestriction) {
7525
+ const resolved = resolve(env.getCwd(), input.path);
7526
+ if (!isPathAllowed(resolved, config.pathConfig.pathRestriction)) {
7527
+ await requirePathApproval(ctx, "edit", resolved, config.pathConfig.pathRestriction);
7528
+ }
7529
+ }
7516
7530
  const content = await env.readFile(input.path);
7517
7531
  if (!content.includes(input.old_text)) {
7518
7532
  throw new Error(
@@ -7617,16 +7631,17 @@ function sandboxTools(config) {
7617
7631
  throw new Error("E2B environment is not yet implemented.");
7618
7632
  }
7619
7633
  const effectiveExecConfig = envType === "local" && !config?.exec?.security ? { ...config?.exec, security: "approval-always" } : config?.exec;
7620
- const fileApproval = config?.fileApproval ?? (envType === "local" ? "always" : void 0);
7621
7634
  const pathConfig = config?.local?.pathRestriction ? { pathRestriction: config.local.pathRestriction } : void 0;
7635
+ const fileApproval = config?.fileApproval;
7636
+ const writeEditConfig = fileApproval ? { approval: fileApproval } : pathConfig ? { pathConfig } : void 0;
7622
7637
  const include = new Set(
7623
7638
  config?.tools ?? ["exec", "read", "write", "edit", "glob", "grep"]
7624
7639
  );
7625
7640
  const tools = [];
7626
7641
  if (include.has("exec")) tools.push(createExecTool(getEnv, effectiveExecConfig));
7627
7642
  if (include.has("read")) tools.push(createReadTool(getEnv, pathConfig));
7628
- if (include.has("write")) tools.push(createWriteTool(getEnv, fileApproval));
7629
- if (include.has("edit")) tools.push(createEditTool(getEnv, fileApproval));
7643
+ if (include.has("write")) tools.push(createWriteTool(getEnv, writeEditConfig));
7644
+ if (include.has("edit")) tools.push(createEditTool(getEnv, writeEditConfig));
7630
7645
  if (include.has("glob")) tools.push(createGlobTool(getEnv, pathConfig));
7631
7646
  if (include.has("grep")) tools.push(createGrepTool(getEnv, pathConfig));
7632
7647
  return tools;