@aiden-ade/sandbox-agent 0.1.21 → 0.1.23

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.
Files changed (77) hide show
  1. package/dist/__tests__/cli-executable.test.d.ts +2 -0
  2. package/dist/__tests__/cli-executable.test.d.ts.map +1 -0
  3. package/dist/__tests__/cli-executable.test.js +83 -0
  4. package/dist/__tests__/cli-executable.test.js.map +1 -0
  5. package/dist/__tests__/cli-help.test.d.ts +2 -0
  6. package/dist/__tests__/cli-help.test.d.ts.map +1 -0
  7. package/dist/__tests__/cli-help.test.js +33 -0
  8. package/dist/__tests__/cli-help.test.js.map +1 -0
  9. package/dist/__tests__/core-agent-workflow-context.test.d.ts +2 -0
  10. package/dist/__tests__/core-agent-workflow-context.test.d.ts.map +1 -0
  11. package/dist/__tests__/core-agent-workflow-context.test.js +50 -0
  12. package/dist/__tests__/core-agent-workflow-context.test.js.map +1 -0
  13. package/dist/__tests__/daemon-socket.integration.test.d.ts +2 -0
  14. package/dist/__tests__/daemon-socket.integration.test.d.ts.map +1 -0
  15. package/dist/__tests__/daemon-socket.integration.test.js +156 -0
  16. package/dist/__tests__/daemon-socket.integration.test.js.map +1 -0
  17. package/dist/__tests__/daemon.test.d.ts +2 -0
  18. package/dist/__tests__/daemon.test.d.ts.map +1 -0
  19. package/dist/__tests__/daemon.test.js +1014 -0
  20. package/dist/__tests__/daemon.test.js.map +1 -0
  21. package/dist/__tests__/generated-images.test.d.ts +2 -0
  22. package/dist/__tests__/generated-images.test.d.ts.map +1 -0
  23. package/dist/__tests__/generated-images.test.js +50 -0
  24. package/dist/__tests__/generated-images.test.js.map +1 -0
  25. package/dist/__tests__/sandbox-workflow-context.test.d.ts +2 -0
  26. package/dist/__tests__/sandbox-workflow-context.test.d.ts.map +1 -0
  27. package/dist/__tests__/sandbox-workflow-context.test.js +66 -0
  28. package/dist/__tests__/sandbox-workflow-context.test.js.map +1 -0
  29. package/dist/aiden-system-prompt.d.ts +6 -0
  30. package/dist/aiden-system-prompt.d.ts.map +1 -0
  31. package/dist/aiden-system-prompt.js +6 -0
  32. package/dist/aiden-system-prompt.js.map +1 -0
  33. package/dist/cli-executable.d.ts +58 -0
  34. package/dist/cli-executable.d.ts.map +1 -0
  35. package/dist/cli-executable.js +301 -0
  36. package/dist/cli-executable.js.map +1 -0
  37. package/dist/cli-help.d.ts +7 -0
  38. package/dist/cli-help.d.ts.map +1 -0
  39. package/dist/cli-help.js +45 -0
  40. package/dist/cli-help.js.map +1 -0
  41. package/dist/core-agent.d.ts +6 -2
  42. package/dist/core-agent.d.ts.map +1 -1
  43. package/dist/core-agent.js +140 -21
  44. package/dist/core-agent.js.map +1 -1
  45. package/dist/daemon.d.ts +46 -0
  46. package/dist/daemon.d.ts.map +1 -0
  47. package/dist/daemon.js +876 -0
  48. package/dist/daemon.js.map +1 -0
  49. package/dist/generated-images.d.ts +4 -0
  50. package/dist/generated-images.d.ts.map +1 -0
  51. package/dist/generated-images.js +142 -0
  52. package/dist/generated-images.js.map +1 -0
  53. package/dist/index.cjs +245 -37
  54. package/dist/index.d.ts +4 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +107 -42
  57. package/dist/index.js.map +1 -1
  58. package/dist/sandbox.d.ts +6 -0
  59. package/dist/sandbox.d.ts.map +1 -1
  60. package/dist/sandbox.js +40 -10
  61. package/dist/sandbox.js.map +1 -1
  62. package/dist/updater.d.ts.map +1 -1
  63. package/dist/updater.js +0 -4
  64. package/dist/updater.js.map +1 -1
  65. package/dist/version.d.ts +1 -1
  66. package/dist/version.d.ts.map +1 -1
  67. package/dist/version.js +1 -1
  68. package/dist/version.js.map +1 -1
  69. package/dist/web-presenter.d.ts +7 -4
  70. package/dist/web-presenter.d.ts.map +1 -1
  71. package/dist/web-presenter.js +29 -4
  72. package/dist/web-presenter.js.map +1 -1
  73. package/dist/ws-client.d.ts +35 -0
  74. package/dist/ws-client.d.ts.map +1 -1
  75. package/dist/ws-client.js +32 -9
  76. package/dist/ws-client.js.map +1 -1
  77. package/package.json +2 -1
package/dist/index.cjs CHANGED
@@ -4855,6 +4855,7 @@ function resolveCommand(args, env) {
4855
4855
  }
4856
4856
 
4857
4857
  // src/daemon.ts
4858
+ var import_node_child_process3 = require("child_process");
4858
4859
  var import_node_crypto2 = require("crypto");
4859
4860
  var import_node_fs4 = require("fs");
4860
4861
  var import_node_http = __toESM(require("http"), 1);
@@ -7234,12 +7235,13 @@ var Encoder = class {
7234
7235
  var Decoder = class _Decoder extends Emitter {
7235
7236
  /**
7236
7237
  * Decoder constructor
7237
- *
7238
- * @param {function} reviver - custom reviver to pass down to JSON.stringify
7239
7238
  */
7240
- constructor(reviver) {
7239
+ constructor(opts) {
7241
7240
  super();
7242
- this.reviver = reviver;
7241
+ this.opts = Object.assign({
7242
+ reviver: void 0,
7243
+ maxAttachments: 10
7244
+ }, typeof opts === "function" ? { reviver: opts } : opts);
7243
7245
  }
7244
7246
  /**
7245
7247
  * Decodes an encoded packet string into packet JSON.
@@ -7299,7 +7301,13 @@ var Decoder = class _Decoder extends Emitter {
7299
7301
  if (buf != Number(buf) || str.charAt(i) !== "-") {
7300
7302
  throw new Error("Illegal attachments");
7301
7303
  }
7302
- p.attachments = Number(buf);
7304
+ const n = Number(buf);
7305
+ if (!isInteger(n) || n < 0) {
7306
+ throw new Error("Illegal attachments");
7307
+ } else if (n > this.opts.maxAttachments) {
7308
+ throw new Error("too many attachments");
7309
+ }
7310
+ p.attachments = n;
7303
7311
  }
7304
7312
  if ("/" === str.charAt(i + 1)) {
7305
7313
  const start = i + 1;
@@ -7341,7 +7349,7 @@ var Decoder = class _Decoder extends Emitter {
7341
7349
  }
7342
7350
  tryParse(str) {
7343
7351
  try {
7344
- return JSON.parse(str, this.reviver);
7352
+ return JSON.parse(str, this.opts.reviver);
7345
7353
  } catch (e) {
7346
7354
  return false;
7347
7355
  }
@@ -9524,22 +9532,6 @@ var STATUS_OPTIONS = [
9524
9532
  dotClass: "text-amber-700 dark:text-amber-400",
9525
9533
  headerBg: "bg-amber-400/15"
9526
9534
  },
9527
- {
9528
- value: "running",
9529
- label: "Running",
9530
- color: CATEGORICAL_COLORS.indigo,
9531
- group: "active",
9532
- dotClass: "text-indigo-500 dark:text-indigo-400",
9533
- headerBg: "bg-indigo-400/15"
9534
- },
9535
- {
9536
- value: "waiting",
9537
- label: "Waiting",
9538
- color: CATEGORICAL_COLORS.orangeDeep,
9539
- group: "active",
9540
- dotClass: "text-orange-500/80 dark:text-orange-400/80",
9541
- headerBg: "bg-orange-400/15"
9542
- },
9543
9535
  {
9544
9536
  value: "in_review",
9545
9537
  label: "In Review",
@@ -11141,8 +11133,8 @@ function parseDroidStructuredLine(line, context, state) {
11141
11133
  break;
11142
11134
  }
11143
11135
  }
11144
- function droidExecPermissionArgs(mode) {
11145
- if (mode === "plan" || mode === "ask" || mode === "review") return [];
11136
+ function droidExecPermissionArgs(config) {
11137
+ if (shouldUseReadOnlyRuntimePermissions(config)) return [];
11146
11138
  return ["--auto", "high"];
11147
11139
  }
11148
11140
  function createDroidCliBackend(command = "droid", defaultArgs = []) {
@@ -11165,7 +11157,7 @@ function createDroidCliBackend(command = "droid", defaultArgs = []) {
11165
11157
  "exec",
11166
11158
  "--output-format",
11167
11159
  "stream-json",
11168
- ...droidExecPermissionArgs(ctx.config.mode),
11160
+ ...droidExecPermissionArgs(ctx.config),
11169
11161
  ...defaultArgs
11170
11162
  ];
11171
11163
  const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
@@ -11309,7 +11301,7 @@ function createGeminiCliBackend(command = "gemini", defaultArgs = []) {
11309
11301
  buildArgs: (ctx) => {
11310
11302
  const args = ["-p", "", "--output-format", "stream-json"];
11311
11303
  const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
11312
- const approvalMode = ctx.config.mode === "plan" || ctx.config.mode === "ask" || ctx.config.mode === "review" ? "plan" : "yolo";
11304
+ const approvalMode = shouldUseReadOnlyRuntimePermissions(ctx.config) ? "plan" : "yolo";
11313
11305
  args.push("--approval-mode", approvalMode);
11314
11306
  if (resumeId) args.push("--resume", resumeId);
11315
11307
  if (ctx.config.selectedModel?.trim())
@@ -11438,6 +11430,21 @@ function createKimiCliBackend(command = "kimi-cli", defaultArgs = []) {
11438
11430
  }
11439
11431
  };
11440
11432
  }
11433
+ function getRecord(value2) {
11434
+ return typeof value2 === "object" && value2 !== null ? value2 : null;
11435
+ }
11436
+ function getString(value2) {
11437
+ return typeof value2 === "string" ? value2.trim() : "";
11438
+ }
11439
+ function getOpenCodeToolError(parsed, part) {
11440
+ const state = getRecord(part?.state) ?? getRecord(parsed.state);
11441
+ const error = getRecord(part?.error) ?? getRecord(parsed.error) ?? getRecord(state?.error);
11442
+ return getString(part?.error) || getString(state?.error) || getString(error?.message) || getString(parsed.error);
11443
+ }
11444
+ function isOpenCodeToolError(parsed, part) {
11445
+ const state = getRecord(part?.state) ?? getRecord(parsed.state);
11446
+ return part?.is_error === true || part?.isError === true || state?.status === "error" || Boolean(getOpenCodeToolError(parsed, part));
11447
+ }
11441
11448
  function parseOpencodeStructuredLine(line, context, state) {
11442
11449
  const presenter = context.presenter;
11443
11450
  let parsed = null;
@@ -11468,16 +11475,44 @@ function parseOpencodeStructuredLine(line, context, state) {
11468
11475
  }
11469
11476
  case "tool_use":
11470
11477
  case "tool.execute": {
11471
- const toolName = part && typeof part.name === "string" ? part.name : "OpenCode Tool";
11478
+ const toolName = getString(parsed.tool) || (part && typeof part.name === "string" ? part.name : "") || getString(parsed.name) || (part && typeof part.tool === "string" ? part.tool : "") || "Tool";
11472
11479
  const toolId = part && typeof part.id === "string" ? part.id : `opencode-tool-${Date.now()}`;
11473
11480
  void presenter.onToolUse(toolName, part ?? {}, toolId);
11474
11481
  break;
11475
11482
  }
11483
+ case "tool": {
11484
+ const stateRecord = getRecord(parsed.state);
11485
+ const toolName = getString(parsed.tool) || (part && typeof part.name === "string" ? part.name : "") || getString(parsed.name) || (part && typeof part.tool === "string" ? part.tool : "") || "Tool";
11486
+ const toolId = getString(parsed.id) || getString(parsed.callID) || `opencode-tool-${Date.now()}`;
11487
+ state.opencodeToolUseIds ??= /* @__PURE__ */ new Set();
11488
+ if (!state.opencodeToolUseIds.has(toolId)) {
11489
+ state.opencodeToolUseIds.add(toolId);
11490
+ void presenter.onToolUse(toolName, stateRecord?.input ?? part ?? parsed, toolId);
11491
+ }
11492
+ const status = getString(stateRecord?.status);
11493
+ if (status === "completed" || status === "error") {
11494
+ const toolError = isOpenCodeToolError(parsed, part);
11495
+ const output = getString(stateRecord?.output) || getString(stateRecord?.error) || JSON.stringify(stateRecord ?? part ?? parsed);
11496
+ void presenter.onToolResult?.(toolId, output, toolError);
11497
+ if (toolError && !state.error) {
11498
+ const message = getOpenCodeToolError(parsed, part) || "OpenCode tool call failed.";
11499
+ state.error = message;
11500
+ void presenter.onError(message);
11501
+ }
11502
+ }
11503
+ break;
11504
+ }
11476
11505
  case "tool_result":
11477
11506
  case "tool.result": {
11478
11507
  const toolId = part && typeof part.id === "string" ? part.id : `opencode-tool-${Date.now()}`;
11479
11508
  const output = part && typeof part.output === "string" ? part.output : JSON.stringify(part);
11480
- void presenter.onToolResult?.(toolId, output);
11509
+ const toolError = isOpenCodeToolError(parsed, part);
11510
+ void presenter.onToolResult?.(toolId, output, toolError);
11511
+ if (toolError && !state.error) {
11512
+ const message = getOpenCodeToolError(parsed, part) || "OpenCode tool call failed.";
11513
+ state.error = message;
11514
+ void presenter.onError(message);
11515
+ }
11481
11516
  break;
11482
11517
  }
11483
11518
  case "step_finish": {
@@ -11533,6 +11568,36 @@ function parseOpencodeStructuredLine(line, context, state) {
11533
11568
  break;
11534
11569
  }
11535
11570
  }
11571
+ var AUTONOMOUS_OPENCODE_CONFIG_CONTENT = JSON.stringify({
11572
+ $schema: "https://opencode.ai/config.json",
11573
+ permission: "allow"
11574
+ });
11575
+ function buildAutonomousOpenCodeConfigContent(existing) {
11576
+ if (!existing?.trim()) return AUTONOMOUS_OPENCODE_CONFIG_CONTENT;
11577
+ try {
11578
+ const parsed = JSON.parse(existing);
11579
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
11580
+ return JSON.stringify({
11581
+ ...parsed,
11582
+ permission: "allow"
11583
+ });
11584
+ }
11585
+ } catch {
11586
+ }
11587
+ return AUTONOMOUS_OPENCODE_CONFIG_CONTENT;
11588
+ }
11589
+ function withAutonomousOpenCodePermissions(context) {
11590
+ if (shouldUseReadOnlyRuntimePermissions(context.config)) return context;
11591
+ return {
11592
+ ...context,
11593
+ env: {
11594
+ ...context.env,
11595
+ OPENCODE_CONFIG_CONTENT: buildAutonomousOpenCodeConfigContent(
11596
+ context.env.OPENCODE_CONFIG_CONTENT
11597
+ )
11598
+ }
11599
+ };
11600
+ }
11536
11601
  function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
11537
11602
  return {
11538
11603
  kind: "opencode_cli",
@@ -11543,6 +11608,7 @@ function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
11543
11608
  context.cwd
11544
11609
  );
11545
11610
  try {
11611
+ const runContext = withAutonomousOpenCodePermissions(context);
11546
11612
  return await createGenericCliBackend({
11547
11613
  kind: "opencode_cli",
11548
11614
  supportTier: "structured",
@@ -11550,6 +11616,9 @@ function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
11550
11616
  args: [],
11551
11617
  buildArgs: (ctx, prompt) => {
11552
11618
  const args = ["run", "--format", "json"];
11619
+ if (!shouldUseReadOnlyRuntimePermissions(ctx.config)) {
11620
+ args.push("--dangerously-skip-permissions");
11621
+ }
11553
11622
  const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
11554
11623
  if (resumeId) args.push("--session", resumeId);
11555
11624
  const model = ctx.config.selectedModel?.trim();
@@ -11565,7 +11634,7 @@ function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
11565
11634
  return ctx.config.mode === "plan" ? buildPlanModePrefix(base) : base;
11566
11635
  },
11567
11636
  parseStructuredLine: parseOpencodeStructuredLine
11568
- }).run(context);
11637
+ }).run(runContext);
11569
11638
  } finally {
11570
11639
  cleanup();
11571
11640
  }
@@ -11744,6 +11813,7 @@ function expandSkillInvocationPrompt(text, cwd) {
11744
11813
  }
11745
11814
  var DEFAULT_MODEL = "claude-sonnet-4-6";
11746
11815
  var DROID_DEFAULT_MODEL = "claude-opus-4-7";
11816
+ var AGENT_ACTIVITY_HEARTBEAT_MS = 1e4;
11747
11817
  function defaultSelectedModelForBackend(backendKind) {
11748
11818
  switch (backendKind) {
11749
11819
  case "claude_cli":
@@ -11754,6 +11824,8 @@ function defaultSelectedModelForBackend(backendKind) {
11754
11824
  return "claude-sonnet-4.5";
11755
11825
  case "kimi_cli":
11756
11826
  return void 0;
11827
+ case "opencode_cli":
11828
+ return void 0;
11757
11829
  case "supatest_cli":
11758
11830
  return "medium";
11759
11831
  default:
@@ -11857,6 +11929,26 @@ var BaseMachineAgent = class _BaseMachineAgent {
11857
11929
  buildPromptText(config) {
11858
11930
  return buildPromptWithFiles(config.task, config.files);
11859
11931
  }
11932
+ getActivityHeartbeatIntervalMs() {
11933
+ return AGENT_ACTIVITY_HEARTBEAT_MS;
11934
+ }
11935
+ async runBackendWithActivityHeartbeat(backend, context) {
11936
+ const intervalMs = this.getActivityHeartbeatIntervalMs();
11937
+ let heartbeat = null;
11938
+ if (this.presenter.onActivity && intervalMs > 0) {
11939
+ void this.presenter.onActivity("background_work");
11940
+ heartbeat = setInterval(() => {
11941
+ if (!context.abortController.signal.aborted) {
11942
+ void this.presenter.onActivity?.("background_work");
11943
+ }
11944
+ }, intervalMs);
11945
+ }
11946
+ try {
11947
+ return await backend.run(context);
11948
+ } finally {
11949
+ if (heartbeat) clearInterval(heartbeat);
11950
+ }
11951
+ }
11860
11952
  // ── Shared helpers ─────────────────────────────────────────────────────
11861
11953
  abort() {
11862
11954
  this.abortController?.abort();
@@ -11941,7 +12033,7 @@ Prefer relative paths and keep your work scoped to this project.`
11941
12033
  let lastResult = null;
11942
12034
  for (let attempt = 0; attempt <= _BaseMachineAgent.MAX_RETRIES; attempt++) {
11943
12035
  if (this.abortController?.signal.aborted) break;
11944
- const result = await backend.run({
12036
+ const result = await this.runBackendWithActivityHeartbeat(backend, {
11945
12037
  presenter: this.presenter,
11946
12038
  config: runtimeConfig,
11947
12039
  abortController: this.abortController,
@@ -11974,7 +12066,7 @@ Prefer relative paths and keep your work scoped to this project.`
11974
12066
  runtimeSessionId: void 0,
11975
12067
  providerSessionId: void 0
11976
12068
  };
11977
- const retryResult = await backend.run({
12069
+ const retryResult = await this.runBackendWithActivityHeartbeat(backend, {
11978
12070
  presenter: this.presenter,
11979
12071
  config: runtimeConfig,
11980
12072
  abortController: this.abortController,
@@ -12508,9 +12600,16 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName) {
12508
12600
  }
12509
12601
 
12510
12602
  // src/version.ts
12511
- var AGENT_VERSION = "0.1.21";
12603
+ var AGENT_VERSION = "0.1.23";
12512
12604
 
12513
12605
  // src/daemon.ts
12606
+ var OPENCODE_FREE_MODEL_IDS = [
12607
+ "opencode/north-mini-code-free",
12608
+ "opencode/nemotron-3-ultra-free",
12609
+ "opencode/deepseek-v4-flash-free",
12610
+ "opencode/mimo-v2.5-free",
12611
+ "opencode/big-pickle"
12612
+ ];
12514
12613
  var PRODUCTION_API_URL = "https://api.aiden-platform.com";
12515
12614
  var PRODUCTION_WS_URL = "wss://ws.aiden-platform.com";
12516
12615
  var LOCAL_API_URL = "http://localhost:8400";
@@ -12604,6 +12703,57 @@ function normalizeBackendKind(backendKind) {
12604
12703
  if (backendKind === "codex") return "codex_app_server";
12605
12704
  return backendKind;
12606
12705
  }
12706
+ function readModelId(value2) {
12707
+ if (typeof value2 === "string") {
12708
+ const trimmed = value2.trim();
12709
+ return trimmed.length > 0 ? trimmed : null;
12710
+ }
12711
+ if (!value2 || typeof value2 !== "object") return null;
12712
+ const record = value2;
12713
+ return readModelId(record.id) ?? readModelId(record.model) ?? readModelId(record.name) ?? readModelId(record.value);
12714
+ }
12715
+ function extractModelIdsFromJson(value2) {
12716
+ if (Array.isArray(value2)) {
12717
+ return [...new Set(value2.map(readModelId).filter((model) => Boolean(model)))];
12718
+ }
12719
+ if (!value2 || typeof value2 !== "object") return [];
12720
+ const record = value2;
12721
+ for (const key of ["models", "data", "items"]) {
12722
+ const nested = extractModelIdsFromJson(record[key]);
12723
+ if (nested.length > 0) return nested;
12724
+ }
12725
+ const byProvider = record.opencode ?? record.providers;
12726
+ if (byProvider) {
12727
+ const nested = extractModelIdsFromJson(byProvider);
12728
+ if (nested.length > 0) return nested;
12729
+ }
12730
+ return [];
12731
+ }
12732
+ function discoverOpenCodeModels(executable, env) {
12733
+ for (const args of [
12734
+ ["models", "--json"],
12735
+ ["models", "list", "--json"],
12736
+ ["model", "list", "--json"]
12737
+ ]) {
12738
+ const result = (0, import_node_child_process3.spawnSync)(executable, args, {
12739
+ encoding: "utf8",
12740
+ timeout: 5e3,
12741
+ env,
12742
+ windowsHide: true
12743
+ });
12744
+ if (!result || result.error || result.status !== 0 || !result.stdout.trim()) continue;
12745
+ try {
12746
+ const models = extractModelIdsFromJson(JSON.parse(result.stdout));
12747
+ if (models.length > 0) return models;
12748
+ } catch {
12749
+ }
12750
+ }
12751
+ return OPENCODE_FREE_MODEL_IDS;
12752
+ }
12753
+ function discoverProviderModels(provider, executable, env) {
12754
+ if (provider === "opencode_cli") return discoverOpenCodeModels(executable, env);
12755
+ return [];
12756
+ }
12607
12757
  function discoverCapabilities() {
12608
12758
  const now = (/* @__PURE__ */ new Date()).toISOString();
12609
12759
  const env = getDaemonCliEnvironment();
@@ -12613,7 +12763,7 @@ function discoverCapabilities() {
12613
12763
  return {
12614
12764
  provider,
12615
12765
  available: Boolean(executable),
12616
- models: [],
12766
+ models: executable ? discoverProviderModels(provider, executable, env) : [],
12617
12767
  lastCheckedAt: now
12618
12768
  };
12619
12769
  }),
@@ -12622,6 +12772,7 @@ function discoverCapabilities() {
12622
12772
  supportsFilesystem: true
12623
12773
  };
12624
12774
  }
12775
+ var RUNNER_RECOVERY_GRACE_MS = 2 * 60 * 1e3;
12625
12776
  var USER_INTERRUPTED_RESULT = {
12626
12777
  success: false,
12627
12778
  summary: "Interrupted by user",
@@ -12634,6 +12785,36 @@ function abortActiveAgent(entry) {
12634
12785
  entry.presenter.onComplete(USER_INTERRUPTED_RESULT);
12635
12786
  entry.agent.kill();
12636
12787
  }
12788
+ function summarizeRunnerStatus(input) {
12789
+ const nowMs = input.nowMs ?? Date.now();
12790
+ const activeEntries = [...input.activeAgents.values()];
12791
+ const activeRunIds = [...input.activeAgents.keys()];
12792
+ const lastRunActivityAtMs = activeEntries.reduce((latest, entry) => {
12793
+ return latest === null ? entry.lastActivityAtMs : Math.max(latest, entry.lastActivityAtMs);
12794
+ }, null);
12795
+ const staleRunCount = input.connected ? 0 : activeEntries.filter((entry) => nowMs - entry.lastActivityAtMs >= RUNNER_RECOVERY_GRACE_MS).length;
12796
+ const pastDisconnectGrace = input.disconnectedSinceMs !== null && nowMs - input.disconnectedSinceMs >= RUNNER_RECOVERY_GRACE_MS;
12797
+ const restartRecommended = !input.connected && activeRunIds.length === 0 && pastDisconnectGrace;
12798
+ return {
12799
+ activeRunIds,
12800
+ activeRunCount: activeRunIds.length,
12801
+ acceptingRuns: input.connected && activeRunIds.length === 0,
12802
+ recovering: !input.connected && !restartRecommended,
12803
+ restartRecommended,
12804
+ staleRunCount,
12805
+ lastRunActivityAtMs,
12806
+ disconnectedSinceMs: input.disconnectedSinceMs
12807
+ };
12808
+ }
12809
+ function recoverStaleActiveRuns(input) {
12810
+ if (input.connected) return;
12811
+ const nowMs = input.nowMs ?? Date.now();
12812
+ for (const [runId, entry] of input.activeAgents.entries()) {
12813
+ if (nowMs - entry.lastActivityAtMs < RUNNER_RECOVERY_GRACE_MS) continue;
12814
+ abortActiveAgent(entry);
12815
+ input.activeAgents.delete(runId);
12816
+ }
12817
+ }
12637
12818
  function collectRuntimeMetadata() {
12638
12819
  const cpuList = (0, import_node_os4.cpus)();
12639
12820
  const metadata = {
@@ -12668,15 +12849,17 @@ async function collectRuntimeMetadataWithProviderLimits() {
12668
12849
  return metadata;
12669
12850
  }
12670
12851
  var RuntimePresenter = class {
12671
- constructor(socket, conversationId, runId, cwd) {
12852
+ constructor(socket, conversationId, runId, cwd, touchRunnerActivity) {
12672
12853
  this.socket = socket;
12673
12854
  this.conversationId = conversationId;
12674
12855
  this.runId = runId;
12675
12856
  this.cwd = cwd;
12857
+ this.touchRunnerActivity = touchRunnerActivity;
12676
12858
  }
12677
12859
  emittedGeneratedImageKeys = /* @__PURE__ */ new Set();
12678
12860
  toolNamesById = /* @__PURE__ */ new Map();
12679
12861
  emitEvent(event) {
12862
+ this.touchRunnerActivity?.();
12680
12863
  this.socket.emit("agent.event", {
12681
12864
  conversationId: this.conversationId,
12682
12865
  runId: this.runId,
@@ -12888,6 +13071,7 @@ async function startDaemon(args) {
12888
13071
  );
12889
13072
  }
12890
13073
  const activeAgents = /* @__PURE__ */ new Map();
13074
+ let disconnectedSinceMs = null;
12891
13075
  const currentCapabilities = () => discoverCapabilities();
12892
13076
  const currentMetadata = () => collectRuntimeMetadataWithProviderLimits();
12893
13077
  const recentLogs = [];
@@ -12917,6 +13101,7 @@ async function startDaemon(args) {
12917
13101
  });
12918
13102
  }, 15e3);
12919
13103
  socket.on("connect", () => {
13104
+ disconnectedSinceMs = null;
12920
13105
  pushLog(`connected runtime=${runtimeId}`);
12921
13106
  console.info("[aiden-agent] Daemon connected", { runtimeId, wsUrl, version: AGENT_VERSION });
12922
13107
  void currentMetadata().then((metadata) => {
@@ -12925,6 +13110,7 @@ async function startDaemon(args) {
12925
13110
  });
12926
13111
  let lastConnectErrorLogAt = 0;
12927
13112
  socket.on("connect_error", (error) => {
13113
+ if (!socket.connected && disconnectedSinceMs === null) disconnectedSinceMs = Date.now();
12928
13114
  pushLog(`connect_error ${error.message}`);
12929
13115
  const now = Date.now();
12930
13116
  if (now - lastConnectErrorLogAt < 5e3) return;
@@ -12933,6 +13119,7 @@ async function startDaemon(args) {
12933
13119
  console.warn("[aiden-agent] Daemon connection error:", `${error.message}.${wsHint}`);
12934
13120
  });
12935
13121
  socket.on("disconnect", (reason) => {
13122
+ if (disconnectedSinceMs === null) disconnectedSinceMs = Date.now();
12936
13123
  pushLog(`disconnected ${reason}`);
12937
13124
  console.info("[aiden-agent] Daemon disconnected:", reason);
12938
13125
  });
@@ -12956,13 +13143,28 @@ async function startDaemon(args) {
12956
13143
  socket.emit("agent.accepted", { runId: payload.runId });
12957
13144
  pushLog(`accepted run=${payload.runId}`);
12958
13145
  const cwd = payload.projectPath ?? process.cwd();
12959
- const presenter = new RuntimePresenter(socket, payload.conversationId, payload.runId, cwd);
13146
+ const nowMs = Date.now();
13147
+ const touchActivity = () => {
13148
+ const entry = activeAgents.get(payload.runId);
13149
+ if (entry) entry.lastActivityAtMs = Date.now();
13150
+ };
13151
+ const presenter = new RuntimePresenter(
13152
+ socket,
13153
+ payload.conversationId,
13154
+ payload.runId,
13155
+ cwd,
13156
+ touchActivity
13157
+ );
12960
13158
  const agent = new CoreAgent(presenter, {
12961
13159
  backendKind,
12962
13160
  runtimeCommand,
12963
13161
  providerApiKey: payload.providerApiKey
12964
13162
  });
12965
- activeAgents.set(payload.runId, { agent, presenter });
13163
+ activeAgents.set(payload.runId, {
13164
+ agent,
13165
+ presenter,
13166
+ lastActivityAtMs: nowMs
13167
+ });
12966
13168
  void agent.run({
12967
13169
  task: payload.content,
12968
13170
  maxIterations: payload.maxIterations ?? 50,
@@ -13032,13 +13234,19 @@ async function startDaemon(args) {
13032
13234
  return;
13033
13235
  }
13034
13236
  if (req.method === "GET" && req.url === "/status") {
13237
+ recoverStaleActiveRuns({ connected: socket.connected, activeAgents });
13238
+ const runnerStatus = summarizeRunnerStatus({
13239
+ connected: socket.connected,
13240
+ activeAgents,
13241
+ disconnectedSinceMs
13242
+ });
13035
13243
  res.writeHead(200, { "content-type": "application/json" }).end(
13036
13244
  JSON.stringify({
13037
13245
  configured: true,
13038
13246
  runtimeId,
13039
13247
  wsUrl,
13040
13248
  connected: socket.connected,
13041
- activeRunIds: [...activeAgents.keys()],
13249
+ ...runnerStatus,
13042
13250
  localApiPort,
13043
13251
  version: AGENT_VERSION
13044
13252
  })
package/dist/index.d.ts CHANGED
@@ -1,2 +1,6 @@
1
+ /**
2
+ * Aiden Sandbox Agent
3
+ * Runs inside E2B sandbox, connects to WS server, executes CoreAgent.
4
+ */
1
5
  export {};
2
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG"}