@aiden-ade/sandbox-agent 0.1.22 → 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 (2) hide show
  1. package/dist/index.cjs +183 -33
  2. package/package.json +1 -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.22";
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
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiden-ade/sandbox-agent",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aiden-agent": "./dist/index.cjs"