@aiden-ade/sandbox-agent 0.1.84 → 0.1.86

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 +266 -162
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -15240,7 +15240,7 @@ function describeError(error61) {
15240
15240
  }
15241
15241
 
15242
15242
  // src/version.ts
15243
- var AGENT_VERSION = "0.1.84";
15243
+ var AGENT_VERSION = "0.1.86";
15244
15244
 
15245
15245
  // src/daemon-worktree.ts
15246
15246
  var import_node_child_process3 = require("child_process");
@@ -35303,6 +35303,8 @@ var activeRunSlotSchema = external_exports.object({
35303
35303
  providerPid: external_exports.number().int().positive().nullable().optional(),
35304
35304
  acceptedAtMs: external_exports.number().int().nonnegative().optional(),
35305
35305
  lastActivityAtMs: external_exports.number().int().nonnegative().optional(),
35306
+ /** A live interactive prompt still owns capacity even without stream activity. */
35307
+ awaitingUser: external_exports.boolean().optional(),
35306
35308
  stale: external_exports.boolean().optional()
35307
35309
  });
35308
35310
  var RUNNER_CAPACITY_SOURCES = ["default", "config", "provider_limit"];
@@ -35409,7 +35411,7 @@ function countNonStaleActiveRuns(activeRuns, nowMs = Date.now(), graceMs = RUNNE
35409
35411
  let staleRunCount = 0;
35410
35412
  for (const run of activeRuns) {
35411
35413
  const lastActivity = run.lastActivityAtMs ?? run.acceptedAtMs ?? 0;
35412
- const stale = run.stale === true || lastActivity > 0 && nowMs - lastActivity >= graceMs;
35414
+ const stale = run.stale === true || run.awaitingUser !== true && lastActivity > 0 && nowMs - lastActivity >= graceMs;
35413
35415
  if (stale)
35414
35416
  staleRunCount += 1;
35415
35417
  else
@@ -38898,7 +38900,9 @@ function mapProviderApiError(errorCode2, apiStatus) {
38898
38900
  return "model_mismatch";
38899
38901
  }
38900
38902
  if (code.includes("authentication") || code.includes("permission_error")) return "auth_invalid";
38901
- if (code.includes("rate_limit")) return "rate_limited";
38903
+ if (code.includes("rate_limit") || code.includes("resource_exhausted")) {
38904
+ return "rate_limited";
38905
+ }
38902
38906
  if (code.includes("overloaded")) return "overloaded";
38903
38907
  if (code.includes("insufficient_quota") || code.includes("billing")) return "quota_exceeded";
38904
38908
  }
@@ -38955,7 +38959,7 @@ function classifyCliErrorDetailed(stderr, _exitCode, opts) {
38955
38959
  if (has("datapolicyerror", "requires explicit opt in")) return specForErrorKind("model_mismatch");
38956
38960
  if (has("no chat found", "chat not found", "session not found", "could not resume"))
38957
38961
  return specForErrorKind("resume_failed");
38958
- if (has("rate_limit", "rate limit") || /\b429\b/.test(haystack))
38962
+ if (has("rate_limit", "rate limit", "resource_exhausted", "resource exhausted") || /\b429\b/.test(haystack))
38959
38963
  return specForErrorKind("rate_limited");
38960
38964
  if (has("authentication_failed", "authentication error", "authentication failed") || isLikelyProviderAuthError(haystack))
38961
38965
  return specForErrorKind("auth_invalid");
@@ -39027,7 +39031,7 @@ function classifyCliErrorDetailed(stderr, _exitCode, opts) {
39027
39031
  }
39028
39032
  function isTransientError(errorMessage) {
39029
39033
  const lower = errorMessage.toLowerCase();
39030
- return lower.includes("rate limit") || lower.includes("overloaded") || /(?:http|status)\s*500\b|\[500\]|\b500 internal server error\b/.test(lower) || lower.includes("502") || lower.includes("503") || lower.includes("504") || lower.includes("524") || lower.includes("429") || lower.includes("service unavailable") || // Node's generic fetch() network-layer failure (opencode_serve's SSE/HTTP calls).
39034
+ return lower.includes("rate limit") || lower.includes("resource_exhausted") || lower.includes("resource exhausted") || lower.includes("overloaded") || /(?:http|status)\s*500\b|\[500\]|\b500 internal server error\b/.test(lower) || lower.includes("502") || lower.includes("503") || lower.includes("504") || lower.includes("524") || lower.includes("429") || lower.includes("service unavailable") || // Node's generic fetch() network-layer failure (opencode_serve's SSE/HTTP calls).
39031
39035
  lower.includes("fetch failed") || lower.includes("etimedout") || lower.includes("econnreset") || lower.includes("econnrefused") || // DNS resolution blips (e.g. "getaddrinfo ENOTFOUND api2.cursor.sh") are
39032
39036
  // transient connectivity failures — the machine briefly can't resolve the
39033
39037
  // provider host and recovers seconds later. Retry with backoff instead of
@@ -39891,8 +39895,10 @@ function createGenericCliBackend(options) {
39891
39895
  }
39892
39896
  const stderrText = (stderrLines.join("\n") || stderrChunks.join("")).trim();
39893
39897
  const hasStructuredError = exitCode === 0 && !!state.error?.trim();
39898
+ const cursorRetrievalResourceExhaustedBeforeTurn = options.kind === "cursor_agent_cli" && state.iterations === 0 && !state.resultReceived && !state.summary.trim() && stderrText.toLowerCase().includes("cursor-retrieval") && /resource[_ ]exhausted/i.test(stderrText);
39899
+ const exitedWithoutResponse = options.kind === "codex_app_server" && exitCode === 0 && exitSignal === null && !state.resultReceived && !hasRenderableTurn && !midSubagentParentExit;
39894
39900
  const expectedExitGraceKill = state.exitGraceKillTriggered === true && !state.error?.trim() && !midSubagentParentExit && (state.summary.trim().length > 0 || state.iterations > 0 || Boolean(state.resultReceived));
39895
- const failed = !expectedExitGraceKill && (exitCode !== 0 || exitSignal !== null) || hasStructuredError || midSubagentParentExit;
39901
+ const failed = !expectedExitGraceKill && (exitCode !== 0 || exitSignal !== null) || hasStructuredError || midSubagentParentExit || exitedWithoutResponse;
39896
39902
  if (cursorResumeSilentlyFailed && !failed) {
39897
39903
  const problem = createCliProblem(
39898
39904
  {
@@ -39945,6 +39951,10 @@ function createGenericCliBackend(options) {
39945
39951
  classifiedError = midExit.message;
39946
39952
  classifiedErrorKind = midExit.errorKind;
39947
39953
  classifiedRecoveryClass = midExit.recoveryClass;
39954
+ } else if (exitedWithoutResponse) {
39955
+ classifiedError = "The agent exited without producing a response. Send your message again to retry.";
39956
+ classifiedErrorKind = "provider_error";
39957
+ classifiedRecoveryClass = "retry";
39948
39958
  } else {
39949
39959
  const detailed = classifyCliErrorDetailed(
39950
39960
  state.error?.trim() || stderrText || "",
@@ -39967,7 +39977,7 @@ function createGenericCliBackend(options) {
39967
39977
  harness: options.kind,
39968
39978
  phase: classifiedErrorKind === "resume_failed" ? "resume" : "shutdown",
39969
39979
  finality: "terminal",
39970
- outcomeCertainty: "effect_unknown",
39980
+ outcomeCertainty: cursorRetrievalResourceExhaustedBeforeTurn ? "no_effect" : "effect_unknown",
39971
39981
  scope: {
39972
39982
  ...context.config.conversationId ? { conversationId: context.config.conversationId } : {}
39973
39983
  },
@@ -48847,16 +48857,40 @@ var DurablePendingRunStarts = class extends Map {
48847
48857
  }
48848
48858
  startedAtByRunId = /* @__PURE__ */ new Map();
48849
48859
  set(runId, conversationId) {
48850
- if (!this.startedAtByRunId.has(runId)) this.startedAtByRunId.set(runId, Date.now());
48860
+ const previousConversationId = super.get(runId);
48861
+ const previousStartedAt = this.startedAtByRunId.get(runId);
48862
+ if (previousStartedAt === void 0) this.startedAtByRunId.set(runId, Date.now());
48851
48863
  super.set(runId, conversationId);
48852
- this.persist();
48864
+ try {
48865
+ this.persist();
48866
+ } catch (error61) {
48867
+ if (previousConversationId === void 0) {
48868
+ super.delete(runId);
48869
+ } else {
48870
+ super.set(runId, previousConversationId);
48871
+ }
48872
+ if (previousStartedAt === void 0) {
48873
+ this.startedAtByRunId.delete(runId);
48874
+ } else {
48875
+ this.startedAtByRunId.set(runId, previousStartedAt);
48876
+ }
48877
+ throw error61;
48878
+ }
48853
48879
  return this;
48854
48880
  }
48855
48881
  delete(runId) {
48882
+ const previousConversationId = super.get(runId);
48883
+ const previousStartedAt = this.startedAtByRunId.get(runId);
48856
48884
  const deleted = super.delete(runId);
48857
48885
  if (deleted) {
48858
48886
  this.startedAtByRunId.delete(runId);
48859
- this.persist();
48887
+ try {
48888
+ this.persist();
48889
+ } catch (error61) {
48890
+ if (previousConversationId !== void 0) super.set(runId, previousConversationId);
48891
+ if (previousStartedAt !== void 0) this.startedAtByRunId.set(runId, previousStartedAt);
48892
+ throw error61;
48893
+ }
48860
48894
  }
48861
48895
  return deleted;
48862
48896
  }
@@ -48917,10 +48951,10 @@ function buildAbortResult(reason) {
48917
48951
  }
48918
48952
  function abortActiveAgent(entry, options) {
48919
48953
  const awaitingAsk = (entry.presenter.pendingAskUserToolIds?.size ?? 0) > 0;
48920
- if (awaitingAsk && !options?.userInitiated) {
48954
+ const reason = options?.reason ?? (options?.userInitiated ? "user" : "runner_stalled");
48955
+ if (awaitingAsk && !options?.userInitiated && reason !== "runtime_shutdown") {
48921
48956
  return;
48922
48957
  }
48923
- const reason = options?.reason ?? (options?.userInitiated ? "user" : "runner_stalled");
48924
48958
  entry.presenter.onComplete(buildAbortResult(reason));
48925
48959
  entry.agent.kill();
48926
48960
  }
@@ -48937,7 +48971,8 @@ function buildActiveRunSlots(activeAgents, nowMs = Date.now()) {
48937
48971
  return [...activeAgents.entries()].map(([runId, entry]) => {
48938
48972
  const staleByGrace = nowMs - entry.lastActivityAtMs >= RUNNER_RECOVERY_GRACE_MS_LOCAL;
48939
48973
  const staleByDeadPid = entry.providerPid !== null && !isProviderProcessAlive(entry.providerPid);
48940
- const stale = staleByGrace || staleByDeadPid;
48974
+ const awaitingAsk = (entry.presenter.pendingAskUserToolIds?.size ?? 0) > 0;
48975
+ const stale = staleByDeadPid || staleByGrace && !awaitingAsk;
48941
48976
  return {
48942
48977
  runId,
48943
48978
  conversationId: entry.conversationId,
@@ -48945,6 +48980,7 @@ function buildActiveRunSlots(activeAgents, nowMs = Date.now()) {
48945
48980
  providerPid: entry.providerPid,
48946
48981
  acceptedAtMs: entry.acceptedAtMs,
48947
48982
  lastActivityAtMs: entry.lastActivityAtMs,
48983
+ awaitingUser: awaitingAsk,
48948
48984
  stale
48949
48985
  };
48950
48986
  });
@@ -48980,7 +49016,8 @@ function buildRunnerStatusPayload(input2) {
48980
49016
  providerAvailable: input2.providerAvailable,
48981
49017
  protocolCompatible: true
48982
49018
  });
48983
- const computerReady = isComputerReady(computerReadiness, { allowWarn: true });
49019
+ const admissionReadiness = computerReadiness.filter((check3) => check3.key !== "workspace_ready");
49020
+ const computerReady = isComputerReady(admissionReadiness, { allowWarn: true });
48984
49021
  const pastDisconnectGrace = input2.disconnectedSinceMs !== null && nowMs - input2.disconnectedSinceMs >= RUNNER_RECOVERY_GRACE_MS_LOCAL;
48985
49022
  const restartRecommended = !input2.connected && activeRunCount === 0 && staleRunCount === 0 && pastDisconnectGrace;
48986
49023
  const recovering = !input2.connected && !restartRecommended;
@@ -49139,6 +49176,9 @@ async function collectRuntimeMetadataWithProviderLimits() {
49139
49176
  }
49140
49177
 
49141
49178
  // src/daemon-local-control.ts
49179
+ function isNativeTaskLinkingEnabled(config2) {
49180
+ return config2.nativeTaskLinkingEnabled === true;
49181
+ }
49142
49182
  var LOCAL_SERVICE_OWNER_VERSION = 1;
49143
49183
  var LOCAL_SERVICE_CHALLENGE_TTL_MS = 5e3;
49144
49184
  function localServiceOwnerPayload(owner) {
@@ -55539,13 +55579,13 @@ function ensureProviderCliInstalled(backendKind, options) {
55539
55579
  }
55540
55580
 
55541
55581
  // src/core-agent.ts
55542
- var import_node_os10 = require("os");
55582
+ var import_node_os11 = require("os");
55543
55583
 
55544
55584
  // src/mcp-registration.ts
55545
55585
  var import_node_crypto8 = require("crypto");
55546
- var import_node_fs16 = require("fs");
55547
- var import_node_os9 = require("os");
55548
- var import_node_path14 = require("path");
55586
+ var import_node_fs17 = require("fs");
55587
+ var import_node_os10 = require("os");
55588
+ var import_node_path15 = require("path");
55549
55589
 
55550
55590
  // ../../node_modules/smol-toml/dist/error.js
55551
55591
  function getLineColFromPtr(string4, ptr) {
@@ -56378,6 +56418,72 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
56378
56418
  return str;
56379
56419
  }
56380
56420
 
56421
+ // src/provider-startup-isolation.ts
56422
+ var import_node_fs16 = require("fs");
56423
+ var import_node_os9 = require("os");
56424
+ var import_node_path14 = require("path");
56425
+ function resolveProviderStartupIsolation(backendKind, _runtimePlatform) {
56426
+ switch (backendKind) {
56427
+ case "claude_cli":
56428
+ return { mode: "shared_config", lockKey: "claude_cli" };
56429
+ case "supatest_cli":
56430
+ return { mode: "shared_config", lockKey: "supatest_cli" };
56431
+ case "codex_app_server":
56432
+ return {
56433
+ mode: "run_scoped_home",
56434
+ envForRunRoot: (runRoot) => ({
56435
+ CODEX_HOME: (0, import_node_path14.join)(runRoot, ".codex")
56436
+ }),
56437
+ // Keep host authentication and session history visible inside the
56438
+ // per-run CODEX_HOME while leaving Alan's MCP config run-scoped.
56439
+ hostStateLinks: [".codex/auth.json", ".codex/.credentials.json", ".codex/sessions"]
56440
+ };
56441
+ case "opencode_cli":
56442
+ case "opencode_serve":
56443
+ return { mode: "shared_config", lockKey: backendKind };
56444
+ default: {
56445
+ const key = backendKind?.trim() || "unknown";
56446
+ return { mode: "shared_config", lockKey: key };
56447
+ }
56448
+ }
56449
+ }
56450
+ function runScopedHomePath(runId, baseDir = (0, import_node_os9.tmpdir)()) {
56451
+ return (0, import_node_path14.join)(baseDir, "alan-runs", runId);
56452
+ }
56453
+ function prepareRunScopedProviderHome(input2) {
56454
+ const hostHome = input2.hostHome ?? (0, import_node_os9.homedir)();
56455
+ const runRoot = runScopedHomePath(input2.runId, input2.baseDir);
56456
+ (0, import_node_fs16.mkdirSync)(runRoot, { recursive: true, mode: 448 });
56457
+ for (const relative6 of input2.isolation.hostStateLinks) {
56458
+ const hostPath = (0, import_node_path14.join)(hostHome, relative6);
56459
+ const linkPath = (0, import_node_path14.join)(runRoot, relative6);
56460
+ if (!(0, import_node_fs16.existsSync)(hostPath)) {
56461
+ if (relative6 !== ".codex/sessions") continue;
56462
+ try {
56463
+ (0, import_node_fs16.mkdirSync)(hostPath, { recursive: true, mode: 448 });
56464
+ } catch {
56465
+ continue;
56466
+ }
56467
+ }
56468
+ (0, import_node_fs16.mkdirSync)((0, import_node_path14.dirname)(linkPath), { recursive: true, mode: 448 });
56469
+ if ((0, import_node_fs16.existsSync)(linkPath)) continue;
56470
+ try {
56471
+ const hostStat = (0, import_node_fs16.lstatSync)(hostPath);
56472
+ (0, import_node_fs16.symlinkSync)(hostPath, linkPath, hostStat.isDirectory() ? "dir" : "file");
56473
+ } catch {
56474
+ }
56475
+ }
56476
+ const mcpHome = runRoot;
56477
+ return {
56478
+ runRoot,
56479
+ mcpHome,
56480
+ env: input2.isolation.envForRunRoot(mcpHome),
56481
+ cleanup: () => {
56482
+ (0, import_node_fs16.rmSync)(runRoot, { recursive: true, force: true });
56483
+ }
56484
+ };
56485
+ }
56486
+
56381
56487
  // src/mcp-registration.ts
56382
56488
  var CONFIG_LOCK_STALE_MS = 3e4;
56383
56489
  var CONFIG_LOCK_WAIT_MS = 2e3;
@@ -56402,10 +56508,10 @@ var inspectAlanMcpThroughProviderCli = async (backendKind, expectedUrl, home) =>
56402
56508
  if (cached2 && cached2.expiresAt > Date.now()) {
56403
56509
  return cached2.result;
56404
56510
  }
56511
+ const startupIsolation = resolveProviderStartupIsolation(backendKind);
56405
56512
  const env = {
56406
56513
  ...getDaemonCliEnvironment(),
56407
- HOME: home,
56408
- USERPROFILE: home
56514
+ ...startupIsolation.mode === "run_scoped_home" ? startupIsolation.envForRunRoot(home) : { HOME: home, USERPROFILE: home }
56409
56515
  };
56410
56516
  const executable = resolveBackendRuntimeCommand(backendKind, env);
56411
56517
  const command = [plan.command, ...plan.args].join(" ");
@@ -56486,18 +56592,18 @@ var inspectAlanMcpThroughProviderCli = async (backendKind, expectedUrl, home) =>
56486
56592
  return result;
56487
56593
  };
56488
56594
  async function waitForConfigLock(lockPath) {
56489
- (0, import_node_fs16.mkdirSync)((0, import_node_path14.dirname)(lockPath), { recursive: true });
56595
+ (0, import_node_fs17.mkdirSync)((0, import_node_path15.dirname)(lockPath), { recursive: true });
56490
56596
  const startedAt = Date.now();
56491
56597
  while (true) {
56492
56598
  try {
56493
- (0, import_node_fs16.mkdirSync)(lockPath);
56494
- return () => (0, import_node_fs16.rmSync)(lockPath, { recursive: true, force: true });
56599
+ (0, import_node_fs17.mkdirSync)(lockPath);
56600
+ return () => (0, import_node_fs17.rmSync)(lockPath, { recursive: true, force: true });
56495
56601
  } catch (error61) {
56496
56602
  const code = error61 && typeof error61 === "object" && "code" in error61 ? error61.code : void 0;
56497
56603
  if (code !== "EEXIST") throw error61;
56498
56604
  try {
56499
- if (Date.now() - (0, import_node_fs16.statSync)(lockPath).mtimeMs > CONFIG_LOCK_STALE_MS) {
56500
- (0, import_node_fs16.rmSync)(lockPath, { recursive: true, force: true });
56605
+ if (Date.now() - (0, import_node_fs17.statSync)(lockPath).mtimeMs > CONFIG_LOCK_STALE_MS) {
56606
+ (0, import_node_fs17.rmSync)(lockPath, { recursive: true, force: true });
56501
56607
  continue;
56502
56608
  }
56503
56609
  } catch {
@@ -56513,7 +56619,7 @@ async function waitForConfigLock(lockPath) {
56513
56619
  function saveMalformedBackup(path2, content) {
56514
56620
  const hash2 = (0, import_node_crypto8.createHash)("sha256").update(content).digest("hex").slice(0, 12);
56515
56621
  const backupPath = `${path2}.alan-backup-${hash2}`;
56516
- if (!(0, import_node_fs16.existsSync)(backupPath)) (0, import_node_fs16.copyFileSync)(path2, backupPath);
56622
+ if (!(0, import_node_fs17.existsSync)(backupPath)) (0, import_node_fs17.copyFileSync)(path2, backupPath);
56517
56623
  return backupPath;
56518
56624
  }
56519
56625
  function parseJsonObject2(path2, content) {
@@ -56561,17 +56667,17 @@ function mergeCodexAlanSection(path2, existingContent, desiredContent) {
56561
56667
  function atomicWriteManagedConfig(path2, content) {
56562
56668
  const pendingPath = `${path2}.alan-pending-${process.pid}-${(0, import_node_crypto8.randomBytes)(6).toString("hex")}`;
56563
56669
  try {
56564
- (0, import_node_fs16.writeFileSync)(pendingPath, content, { encoding: "utf8", mode: 384, flag: "wx" });
56565
- (0, import_node_fs16.renameSync)(pendingPath, path2);
56670
+ (0, import_node_fs17.writeFileSync)(pendingPath, content, { encoding: "utf8", mode: 384, flag: "wx" });
56671
+ (0, import_node_fs17.renameSync)(pendingPath, path2);
56566
56672
  } finally {
56567
- (0, import_node_fs16.rmSync)(pendingPath, { force: true });
56673
+ (0, import_node_fs17.rmSync)(pendingPath, { force: true });
56568
56674
  }
56569
56675
  }
56570
- async function configureAntigravityApiKeyMode(home = (0, import_node_os9.homedir)()) {
56571
- const path2 = (0, import_node_path14.join)(home, ".gemini", "antigravity-cli", "settings.json");
56676
+ async function configureAntigravityApiKeyMode(home = (0, import_node_os10.homedir)()) {
56677
+ const path2 = (0, import_node_path15.join)(home, ".gemini", "antigravity-cli", "settings.json");
56572
56678
  const releaseLock = await waitForConfigLock(`${path2}.alan-lock`);
56573
56679
  try {
56574
- const existingContent = (0, import_node_fs16.existsSync)(path2) ? (0, import_node_fs16.readFileSync)(path2, "utf8") : "";
56680
+ const existingContent = (0, import_node_fs17.existsSync)(path2) ? (0, import_node_fs17.readFileSync)(path2, "utf8") : "";
56575
56681
  const settings = existingContent.trim() ? parseJsonObject2(path2, existingContent) : {};
56576
56682
  if (settings.modelProvider === "gemini") return false;
56577
56683
  settings.modelProvider = "gemini";
@@ -56581,16 +56687,16 @@ async function configureAntigravityApiKeyMode(home = (0, import_node_os9.homedir
56581
56687
  releaseLock();
56582
56688
  }
56583
56689
  }
56584
- async function ensureAlanMcpRegistered(backendKind, registration, home = (0, import_node_os9.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
56690
+ async function ensureAlanMcpRegistered(backendKind, registration, home = (0, import_node_os10.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
56585
56691
  try {
56586
56692
  const mcpServers = buildAlanMcpServers(registration);
56587
56693
  const files = alanMcpConfigFilesForBackend(backendKind, mcpServers, home);
56588
56694
  const paths = [];
56589
56695
  for (const file2 of files) {
56590
- (0, import_node_fs16.mkdirSync)((0, import_node_path14.dirname)(file2.path), { recursive: true });
56696
+ (0, import_node_fs17.mkdirSync)((0, import_node_path15.dirname)(file2.path), { recursive: true });
56591
56697
  const releaseLock = await waitForConfigLock(`${file2.path}.alan-lock`);
56592
56698
  try {
56593
- const current = (0, import_node_fs16.existsSync)(file2.path) ? (0, import_node_fs16.readFileSync)(file2.path, "utf8") : null;
56699
+ const current = (0, import_node_fs17.existsSync)(file2.path) ? (0, import_node_fs17.readFileSync)(file2.path, "utf8") : null;
56594
56700
  const content = file2.path.endsWith(".toml") ? mergeCodexAlanSection(file2.path, current, file2.content) : mergeJsonConfig(file2.path, current, file2.content);
56595
56701
  if (current !== content) atomicWriteManagedConfig(file2.path, content);
56596
56702
  paths.push(file2.path);
@@ -56652,7 +56758,7 @@ async function ensureAlanMcpRegistered(backendKind, registration, home = (0, imp
56652
56758
  return { ok: false, paths: [], error: err instanceof Error ? err.message : String(err) };
56653
56759
  }
56654
56760
  }
56655
- async function restoreStaticAlanMcp(backendKind, apiUrl, home = (0, import_node_os9.homedir)()) {
56761
+ async function restoreStaticAlanMcp(backendKind, apiUrl, home = (0, import_node_os10.homedir)()) {
56656
56762
  let url3;
56657
56763
  try {
56658
56764
  url3 = new URL("/mcp", apiUrl).toString();
@@ -56668,13 +56774,13 @@ async function restoreStaticAlanMcp(backendKind, apiUrl, home = (0, import_node_
56668
56774
  verification: { method: "file" }
56669
56775
  }));
56670
56776
  }
56671
- async function verifyAlanMcpRegistered(backendKind, home = (0, import_node_os9.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
56777
+ async function verifyAlanMcpRegistered(backendKind, home = (0, import_node_os10.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
56672
56778
  const files = alanMcpConfigFilesForBackend(backendKind, {}, home);
56673
- const missing = files.map((f) => f.path).filter((p) => !(0, import_node_fs16.existsSync)(p));
56779
+ const missing = files.map((f) => f.path).filter((p) => !(0, import_node_fs17.existsSync)(p));
56674
56780
  const presentEntries = files.map((file2) => ({
56675
56781
  path: file2.path,
56676
- registration: (0, import_node_fs16.existsSync)(file2.path) ? readAlanMcpRegistration(file2.path) : null
56677
- })).filter((entry) => (0, import_node_fs16.existsSync)(entry.path));
56782
+ registration: (0, import_node_fs17.existsSync)(file2.path) ? readAlanMcpRegistration(file2.path) : null
56783
+ })).filter((entry) => (0, import_node_fs17.existsSync)(entry.path));
56678
56784
  let invalid = presentEntries.filter(
56679
56785
  (entry) => !entry.registration || !hasUsableRegistrationCredential(entry.registration.headers)
56680
56786
  ).map((entry) => entry.path);
@@ -56775,7 +56881,7 @@ function hasUsableRegistrationCredential(headers) {
56775
56881
  return Boolean(normalized.get("x-alan-run-reference") || normalized.get("authorization"));
56776
56882
  }
56777
56883
  function readAlanMcpRegistration(path2) {
56778
- return parseAlanMcpRegistration(path2, (0, import_node_fs16.readFileSync)(path2, "utf8"));
56884
+ return parseAlanMcpRegistration(path2, (0, import_node_fs17.readFileSync)(path2, "utf8"));
56779
56885
  }
56780
56886
  function parseAlanMcpRegistration(path2, content) {
56781
56887
  if (path2.endsWith(".toml")) {
@@ -56985,7 +57091,7 @@ var CoreAgent = class _CoreAgent extends BaseMachineAgent {
56985
57091
  if (backendKind === "antigravity_cli" && augmented.GEMINI_API_KEY?.trim()) {
56986
57092
  await configureAntigravityApiKeyMode(augmented.HOME ?? augmented.USERPROFILE);
56987
57093
  }
56988
- if ((0, import_node_os10.platform)() !== "win32") {
57094
+ if ((0, import_node_os11.platform)() !== "win32") {
56989
57095
  const home = augmented.HOME ?? "/home/user";
56990
57096
  const extraPaths = [`${home}/.local/node/bin`, `${home}/.local/bin`];
56991
57097
  const separator = ":";
@@ -73874,90 +73980,6 @@ async function prepareAlanMcpForRun(backendKind, registration, options = {}) {
73874
73980
  return { ...probed, providerLoadStatus: registered.providerLoadStatus };
73875
73981
  }
73876
73982
 
73877
- // src/provider-startup-isolation.ts
73878
- var import_node_fs17 = require("fs");
73879
- var import_node_os11 = require("os");
73880
- var import_node_path15 = require("path");
73881
- function resolveProviderStartupIsolation(backendKind, runtimePlatform = (0, import_node_os11.platform)()) {
73882
- switch (backendKind) {
73883
- case "claude_cli":
73884
- if (runtimePlatform === "darwin") {
73885
- return { mode: "shared_config", lockKey: "claude_cli" };
73886
- }
73887
- return {
73888
- mode: "run_scoped_home",
73889
- envForRunRoot: (runRoot) => ({
73890
- HOME: runRoot,
73891
- USERPROFILE: runRoot
73892
- }),
73893
- // Auth + session state live under ~/.claude; MCP is ~/.claude.json in the run root.
73894
- hostStateLinks: [".claude"]
73895
- };
73896
- case "supatest_cli":
73897
- return {
73898
- mode: "run_scoped_home",
73899
- envForRunRoot: (runRoot) => ({
73900
- HOME: runRoot,
73901
- USERPROFILE: runRoot
73902
- }),
73903
- // Auth + session state live under ~/.claude; MCP is ~/.claude.json in the run root.
73904
- hostStateLinks: [".claude"]
73905
- };
73906
- case "codex_app_server":
73907
- return {
73908
- mode: "run_scoped_home",
73909
- envForRunRoot: (runRoot) => ({
73910
- CODEX_HOME: (0, import_node_path15.join)(runRoot, ".codex")
73911
- }),
73912
- // Auth tokens stay in the host Codex home; only config.toml is run-scoped.
73913
- hostStateLinks: [".codex/auth.json", ".codex/.credentials.json"]
73914
- };
73915
- case "opencode_cli":
73916
- case "opencode_serve":
73917
- return {
73918
- mode: "run_scoped_home",
73919
- envForRunRoot: (runRoot) => ({
73920
- HOME: runRoot,
73921
- USERPROFILE: runRoot,
73922
- XDG_CONFIG_HOME: (0, import_node_path15.join)(runRoot, ".config")
73923
- }),
73924
- hostStateLinks: []
73925
- };
73926
- default: {
73927
- const key = backendKind?.trim() || "unknown";
73928
- return { mode: "shared_config", lockKey: key };
73929
- }
73930
- }
73931
- }
73932
- function runScopedHomePath(runId, baseDir = (0, import_node_os11.tmpdir)()) {
73933
- return (0, import_node_path15.join)(baseDir, "alan-runs", runId);
73934
- }
73935
- function prepareRunScopedProviderHome(input2) {
73936
- const hostHome = input2.hostHome ?? (0, import_node_os11.homedir)();
73937
- const runRoot = runScopedHomePath(input2.runId, input2.baseDir);
73938
- (0, import_node_fs17.mkdirSync)(runRoot, { recursive: true, mode: 448 });
73939
- for (const relative6 of input2.isolation.hostStateLinks) {
73940
- const hostPath = (0, import_node_path15.join)(hostHome, relative6);
73941
- const linkPath = (0, import_node_path15.join)(runRoot, relative6);
73942
- if (!(0, import_node_fs17.existsSync)(hostPath)) continue;
73943
- (0, import_node_fs17.mkdirSync)((0, import_node_path15.dirname)(linkPath), { recursive: true, mode: 448 });
73944
- if ((0, import_node_fs17.existsSync)(linkPath)) continue;
73945
- try {
73946
- const hostStat = (0, import_node_fs17.lstatSync)(hostPath);
73947
- (0, import_node_fs17.symlinkSync)(hostPath, linkPath, hostStat.isDirectory() ? "dir" : "file");
73948
- } catch {
73949
- }
73950
- }
73951
- return {
73952
- runRoot,
73953
- mcpHome: runRoot,
73954
- env: input2.isolation.envForRunRoot(runRoot),
73955
- cleanup: () => {
73956
- (0, import_node_fs17.rmSync)(runRoot, { recursive: true, force: true });
73957
- }
73958
- };
73959
- }
73960
-
73961
73983
  // src/run-start-gate.ts
73962
73984
  var DEFAULT_STARTUP_CONFIG_LOCK_TIMEOUT_MS = 5e3;
73963
73985
  function startupConfigLockTimeoutMs() {
@@ -74636,7 +74658,16 @@ async function handleAgentExecute(ctx, payload) {
74636
74658
  runtimeCommand = revalidateBackendRuntimeCommand(backendKind);
74637
74659
  }
74638
74660
  if (!runtimeCommand && backendKind && canInstallProviderCli(backendKind)) {
74639
- pendingRunStarts.set(payload.runId, payload.conversationId);
74661
+ try {
74662
+ pendingRunStarts.set(payload.runId, payload.conversationId);
74663
+ } catch (error61) {
74664
+ socket.emit("agent.rejected", {
74665
+ runId: payload.runId,
74666
+ message: `Unable to reserve local runtime capacity: ${error61 instanceof Error ? error61.message : String(error61)}`,
74667
+ code: "runner_reservation_failed"
74668
+ });
74669
+ return;
74670
+ }
74640
74671
  try {
74641
74672
  const installed = await ensureProviderCliInstalled(backendKind, {
74642
74673
  notify: (message) => {
@@ -74777,7 +74808,16 @@ async function handleAgentExecute(ctx, payload) {
74777
74808
  });
74778
74809
  return;
74779
74810
  }
74780
- pendingRunStarts.set(payload.runId, payload.conversationId);
74811
+ try {
74812
+ pendingRunStarts.set(payload.runId, payload.conversationId);
74813
+ } catch (error61) {
74814
+ socket.emit("agent.rejected", {
74815
+ runId: payload.runId,
74816
+ message: `Unable to reserve local runtime capacity: ${error61 instanceof Error ? error61.message : String(error61)}`,
74817
+ code: "runner_reservation_failed"
74818
+ });
74819
+ return;
74820
+ }
74781
74821
  publishCapacityChange();
74782
74822
  const releaseCapacity = () => {
74783
74823
  if (!pendingRunStarts.delete(payload.runId)) return;
@@ -76969,7 +77009,7 @@ var LocalSkillSource = class {
76969
77009
  try {
76970
77010
  entries = await (0, import_promises2.readdir)(resolvedRoot.directory, { withFileTypes: true });
76971
77011
  } catch (error61) {
76972
- if (isMissingPath(error61)) return { candidates: [], diagnostics: [], incomplete: false };
77012
+ if (isAbsentDirectory(error61)) return { candidates: [], diagnostics: [], incomplete: false };
76973
77013
  return {
76974
77014
  candidates: [],
76975
77015
  diagnostics: [
@@ -77305,8 +77345,8 @@ async function isDirectory(path2) {
77305
77345
  return false;
77306
77346
  }
77307
77347
  }
77308
- function isMissingPath(error61) {
77309
- return typeof error61 === "object" && error61 !== null && "code" in error61 && error61.code === "ENOENT";
77348
+ function isAbsentDirectory(error61) {
77349
+ return typeof error61 === "object" && error61 !== null && "code" in error61 && ["ENOENT", "ENOTDIR"].includes(String(error61.code));
77310
77350
  }
77311
77351
  function isAlreadyPresent(error61) {
77312
77352
  return typeof error61 === "object" && error61 !== null && "code" in error61 && error61.code === "EEXIST";
@@ -77499,7 +77539,7 @@ var ManagedSkillStore = class _ManagedSkillStore {
77499
77539
  const parsed = JSON.parse(await (0, import_promises3.readFile)((0, import_node_path22.join)(baseDirectory, "state.json"), "utf8"));
77500
77540
  return new _ManagedSkillStore(baseDirectory, parseState(parsed), "verified");
77501
77541
  } catch (error61) {
77502
- if (isMissingPath2(error61)) {
77542
+ if (isMissingPath(error61)) {
77503
77543
  return new _ManagedSkillStore(baseDirectory, EMPTY_STATE, "verified");
77504
77544
  }
77505
77545
  return new _ManagedSkillStore(baseDirectory, EMPTY_STATE, "rebuilt");
@@ -77621,7 +77661,7 @@ function isSha256(value2) {
77621
77661
  function isRecord5(value2) {
77622
77662
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
77623
77663
  }
77624
- function isMissingPath2(error61) {
77664
+ function isMissingPath(error61) {
77625
77665
  return typeof error61 === "object" && error61 !== null && "code" in error61 && error61.code === "ENOENT";
77626
77666
  }
77627
77667
 
@@ -78688,7 +78728,7 @@ async function pathExists2(path2) {
78688
78728
  await (0, import_promises5.lstat)(path2);
78689
78729
  return true;
78690
78730
  } catch (error61) {
78691
- if (isMissingPath3(error61)) return false;
78731
+ if (isMissingPath2(error61)) return false;
78692
78732
  throw error61;
78693
78733
  }
78694
78734
  }
@@ -78714,7 +78754,7 @@ function errorCode(error61) {
78714
78754
  }
78715
78755
  return "SKILL_RECONCILE_FAILED";
78716
78756
  }
78717
- function isMissingPath3(error61) {
78757
+ function isMissingPath2(error61) {
78718
78758
  return typeof error61 === "object" && error61 !== null && "code" in error61 && error61.code === "ENOENT";
78719
78759
  }
78720
78760
  function isAlreadyPresent2(error61) {
@@ -78786,7 +78826,7 @@ async function startDaemon(args) {
78786
78826
  const runtimeId = argValue(args, "--runtime-id") ?? process.env.ALAN_RUNTIME_ID ?? stored.runtimeId;
78787
78827
  const runtimeTokenOverride = argValue(args, "--token") ?? process.env.ALAN_RUNTIME_TOKEN;
78788
78828
  let runtimeToken = runtimeTokenOverride ?? stored.runtimeToken;
78789
- const runtimeRenewalToken = runtimeTokenOverride ? void 0 : stored.runtimeRenewalToken;
78829
+ let runtimeRenewalToken = runtimeTokenOverride ? void 0 : stored.runtimeRenewalToken;
78790
78830
  const wsUrlOverride = argValue(args, "--ws-url") ?? process.env.ALAN_WS_URL;
78791
78831
  const endpointMismatch = wsUrlOverride ? null : checkStoredEndpointConsistency(stored, readEndpointDefaults());
78792
78832
  let wsUrl = wsUrlOverride ?? stored.wsUrl;
@@ -78920,6 +78960,24 @@ async function startDaemon(args) {
78920
78960
  let disconnectedSinceMs = null;
78921
78961
  let lastConnectError = null;
78922
78962
  let lastConnectErrorCode = null;
78963
+ const TERMINAL_RUNTIME_AUTH_CODES = /* @__PURE__ */ new Set([
78964
+ "invalid_runtime_token",
78965
+ "runtime_renewal_rejected",
78966
+ "runtime_deleted",
78967
+ "runtime_disabled"
78968
+ ]);
78969
+ let terminalAuthFailureCode = null;
78970
+ const rememberConnectErrorCode = (code) => {
78971
+ if (code && TERMINAL_RUNTIME_AUTH_CODES.has(code)) {
78972
+ terminalAuthFailureCode = code;
78973
+ }
78974
+ lastConnectErrorCode = terminalAuthFailureCode ?? code;
78975
+ };
78976
+ const clearConnectErrors = () => {
78977
+ lastConnectError = null;
78978
+ lastConnectErrorCode = null;
78979
+ terminalAuthFailureCode = null;
78980
+ };
78923
78981
  const pendingDeliveryLost = [];
78924
78982
  const currentCapabilities = () => discoverCapabilities();
78925
78983
  const currentMetadata = async () => ({
@@ -79135,7 +79193,29 @@ async function startDaemon(args) {
79135
79193
  const renewRuntimeLease = () => {
79136
79194
  if (runtimeRenewalInFlight) return runtimeRenewalInFlight;
79137
79195
  const attempt = (async () => {
79138
- if (!stored.apiUrl || !runtimeRenewalToken) return false;
79196
+ const adoptRewrittenCredentials = () => {
79197
+ const current2 = readConfig();
79198
+ if (current2.runtimeId !== runtimeId) return false;
79199
+ const nextToken = current2.runtimeToken;
79200
+ const nextRenewal = current2.runtimeRenewalToken;
79201
+ if (typeof nextToken !== "string" || !nextToken.startsWith("alan_runtime_") || typeof nextRenewal !== "string" || !nextRenewal.startsWith("alan_runtime_renew_")) {
79202
+ return false;
79203
+ }
79204
+ if (nextToken === runtimeToken && nextRenewal === runtimeRenewalToken) {
79205
+ return false;
79206
+ }
79207
+ runtimeToken = nextToken;
79208
+ runtimeRenewalToken = nextRenewal;
79209
+ socket.auth = { token: nextToken };
79210
+ clearConnectErrors();
79211
+ pushLog("runtime-credentials-reloaded-from-config");
79212
+ socket.connect();
79213
+ return true;
79214
+ };
79215
+ if (!stored.apiUrl || !runtimeRenewalToken) {
79216
+ if (adoptRewrittenCredentials()) return true;
79217
+ return false;
79218
+ }
79139
79219
  let response = null;
79140
79220
  let transportError = null;
79141
79221
  for (let retry = 1; retry <= 3; retry += 1) {
@@ -79159,27 +79239,32 @@ async function startDaemon(args) {
79159
79239
  await sleep(retry * 250);
79160
79240
  }
79161
79241
  if (!response) {
79162
- lastConnectErrorCode = "backend_unreachable";
79242
+ rememberConnectErrorCode("backend_unreachable");
79163
79243
  lastConnectError = `Runtime renewal could not reach Alan: ${transportError instanceof Error ? transportError.message : String(transportError)}`;
79164
79244
  pushLog(`runtime-renewal-transport-failed ${lastConnectError}`);
79165
79245
  return false;
79166
79246
  }
79167
79247
  if (!response.ok) {
79168
- lastConnectErrorCode = response.status === 401 ? "runtime_renewal_rejected" : response.status === 403 ? "runtime_disabled" : response.status === 410 ? "runtime_deleted" : response.status >= 500 ? "backend_unreachable" : "runtime_renewal_failed";
79248
+ if (response.status === 401 && adoptRewrittenCredentials()) {
79249
+ return true;
79250
+ }
79251
+ const code = response.status === 401 ? "runtime_renewal_rejected" : response.status === 403 ? "runtime_disabled" : response.status === 410 ? "runtime_deleted" : response.status >= 500 ? "backend_unreachable" : "runtime_renewal_failed";
79252
+ rememberConnectErrorCode(code);
79169
79253
  lastConnectError = `Runtime renewal failed: ${response.status} ${await response.text()}`;
79170
79254
  pushLog(`runtime-renewal-rejected ${lastConnectError}`);
79171
79255
  return false;
79172
79256
  }
79173
79257
  const body = await response.json();
79174
79258
  if (typeof body.runtimeToken !== "string" || !body.runtimeToken.startsWith("alan_runtime_")) {
79175
- lastConnectErrorCode = "runtime_renewal_failed";
79259
+ rememberConnectErrorCode("runtime_renewal_failed");
79176
79260
  lastConnectError = "Runtime renewal returned an invalid access token";
79177
79261
  pushLog("runtime-renewal-invalid-response");
79178
79262
  return false;
79179
79263
  }
79180
79264
  const current = readConfig();
79181
79265
  if (current.runtimeId !== runtimeId || current.runtimeRenewalToken !== runtimeRenewalToken) {
79182
- lastConnectErrorCode = "runtime_renewal_superseded";
79266
+ if (adoptRewrittenCredentials()) return true;
79267
+ rememberConnectErrorCode("runtime_renewal_superseded");
79183
79268
  lastConnectError = "Runtime credentials changed while renewal was in progress";
79184
79269
  pushLog("runtime-renewal-superseded");
79185
79270
  return false;
@@ -79187,15 +79272,14 @@ async function startDaemon(args) {
79187
79272
  try {
79188
79273
  writeConfig({ ...current, runtimeToken: body.runtimeToken });
79189
79274
  } catch (error61) {
79190
- lastConnectErrorCode = "config_write_failed";
79275
+ rememberConnectErrorCode("config_write_failed");
79191
79276
  lastConnectError = `Runtime renewal could not save its replacement: ${error61.message}`;
79192
79277
  pushLog(`runtime-renewal-config-write-failed ${error61.message}`);
79193
79278
  return false;
79194
79279
  }
79195
79280
  runtimeToken = body.runtimeToken;
79196
79281
  socket.auth = { token: body.runtimeToken };
79197
- lastConnectError = null;
79198
- lastConnectErrorCode = null;
79282
+ clearConnectErrors();
79199
79283
  pushLog("runtime-renewal-succeeded");
79200
79284
  socket.connect();
79201
79285
  return true;
@@ -79346,8 +79430,7 @@ async function startDaemon(args) {
79346
79430
  workspaceLeaseMonitor.unref?.();
79347
79431
  socket.on("connect", () => {
79348
79432
  disconnectedSinceMs = null;
79349
- lastConnectError = null;
79350
- lastConnectErrorCode = null;
79433
+ clearConnectErrors();
79351
79434
  setConnectedRuntimeSocket(socket);
79352
79435
  pushLog(`connected runtime=${runtimeId}`);
79353
79436
  console.info("[alan-agent] Daemon connected", { runtimeId, wsUrl, version: AGENT_VERSION });
@@ -79395,13 +79478,15 @@ async function startDaemon(args) {
79395
79478
  if (!socket.connected && disconnectedSinceMs === null) disconnectedSinceMs = Date.now();
79396
79479
  lastConnectError = error61.message;
79397
79480
  const errorCode2 = error61?.data?.code;
79398
- lastConnectErrorCode = typeof errorCode2 === "string" ? errorCode2 : classifyTransportFailure(error61);
79481
+ rememberConnectErrorCode(
79482
+ typeof errorCode2 === "string" ? errorCode2 : classifyTransportFailure(error61)
79483
+ );
79399
79484
  pushLog(
79400
79485
  `connect_error ${error61.message}${lastConnectErrorCode ? ` code=${lastConnectErrorCode}` : ""}`
79401
79486
  );
79402
- if (lastConnectErrorCode === "invalid_runtime_token" && runtimeRenewalToken) {
79487
+ if ((lastConnectErrorCode === "invalid_runtime_token" || terminalAuthFailureCode === "invalid_runtime_token") && runtimeRenewalToken) {
79403
79488
  void renewRuntimeLease().catch((renewalError) => {
79404
- lastConnectErrorCode = "runtime_renewal_failed";
79489
+ rememberConnectErrorCode("runtime_renewal_failed");
79405
79490
  lastConnectError = `Runtime renewal failed unexpectedly: ${renewalError.message}`;
79406
79491
  pushLog(`runtime-renewal-unexpected-failure ${renewalError.message}`);
79407
79492
  });
@@ -79620,7 +79705,11 @@ async function startDaemon(args) {
79620
79705
  lastConnectError = v;
79621
79706
  },
79622
79707
  setLastConnectErrorCode: (v) => {
79623
- lastConnectErrorCode = v;
79708
+ if (v === null) {
79709
+ lastConnectErrorCode = terminalAuthFailureCode;
79710
+ return;
79711
+ }
79712
+ rememberConnectErrorCode(v);
79624
79713
  },
79625
79714
  workspaceAccessTracker,
79626
79715
  recentLogs,
@@ -79722,6 +79811,7 @@ async function startDaemon(args) {
79722
79811
  const stop = async () => {
79723
79812
  if (stopped) return;
79724
79813
  stopped = true;
79814
+ let providersExited = true;
79725
79815
  try {
79726
79816
  clearInterval(heartbeat);
79727
79817
  clearInterval(versionRefresh);
@@ -79730,9 +79820,16 @@ async function startDaemon(args) {
79730
79820
  clearInterval(skillAuditInterval);
79731
79821
  clearInterval(nativeHookDrainInterval);
79732
79822
  suspensionDetector.stop();
79733
- for (const entry of activeAgents.values()) {
79823
+ const stoppingEntries = [...activeAgents.values()];
79824
+ for (const entry of stoppingEntries) {
79734
79825
  abortActiveAgent(entry, { reason: "runtime_shutdown" });
79735
79826
  }
79827
+ const providerPids = stoppingEntries.map((entry) => entry.providerPid).filter((pid) => pid !== null && pid > 0 && pid !== process.pid);
79828
+ const gracefulDeadline = Date.now() + 250;
79829
+ while (providerPids.some((pid) => isProviderProcessAlive(pid)) && Date.now() < gracefulDeadline) {
79830
+ await new Promise((resolve15) => setTimeout(resolve15, 25));
79831
+ }
79832
+ providersExited = providerPids.every((pid) => !isProviderProcessAlive(pid));
79736
79833
  activeAgents.clear();
79737
79834
  socket.disconnect();
79738
79835
  await new Promise((resolve15) => {
@@ -79740,7 +79837,7 @@ async function startDaemon(args) {
79740
79837
  });
79741
79838
  } finally {
79742
79839
  sleepInhibitor.dispose();
79743
- releaseOwnerLease();
79840
+ if (providersExited) releaseOwnerLease();
79744
79841
  }
79745
79842
  };
79746
79843
  const controller = {
@@ -81231,7 +81328,7 @@ function nativeHookCommand(input2) {
81231
81328
  timeout: 5
81232
81329
  };
81233
81330
  }
81234
- function nativeShellCommand(runtime, provider, event, platform7 = runtime.platform) {
81331
+ function nativeShellCommand(runtime, provider, event, platform6 = runtime.platform) {
81235
81332
  const args = hookArgs({
81236
81333
  configPath: runtime.configPath,
81237
81334
  cliEntry: runtime.cliEntry,
@@ -81239,7 +81336,7 @@ function nativeShellCommand(runtime, provider, event, platform7 = runtime.platfo
81239
81336
  event
81240
81337
  });
81241
81338
  const environment = checkedEnvironment(runtime.environment);
81242
- if (platform7 === "win32") {
81339
+ if (platform6 === "win32") {
81243
81340
  const prefix2 = environment.map(([key, value2]) => `$env:${key}=${powershellQuote(value2)}`).join("; ");
81244
81341
  const command2 = `& ${[runtime.nodeExecutable, ...args].map(powershellQuote).join(" ")}`;
81245
81342
  return prefix2 ? `${prefix2}; ${command2}` : command2;
@@ -82273,10 +82370,12 @@ function enqueueNativeHookFromConfig(input2) {
82273
82370
  function runNativeHookCommand(args) {
82274
82371
  try {
82275
82372
  const payload = readBoundedHookPayload();
82276
- const enqueued = enqueueNativeHookFromConfig({ args, payload });
82373
+ bindConfigPath(args);
82374
+ const config2 = readConfig();
82375
+ const enqueued = enqueueNativeHookFromConfig({ args, payload, config: config2 });
82277
82376
  const hookEvent = argumentValue(args, "--event");
82278
82377
  const normalizedEvent = normalizeHookEvent(hookEvent ?? "notification");
82279
- if (enqueued && (normalizedEvent === "user_prompt" || normalizedEvent === "session_start")) {
82378
+ if (enqueued && isNativeTaskLinkingEnabled(config2) && (normalizedEvent === "user_prompt" || normalizedEvent === "session_start")) {
82280
82379
  const providerKind = argumentValue(args, "--provider");
82281
82380
  const externalSessionId = stringField4(
82282
82381
  payload,
@@ -84178,10 +84277,12 @@ WantedBy=default.target
84178
84277
  environmentPrefix ? `-NoProfile -NonInteractive -WindowStyle Hidden -Command "${environmentPrefix}; & ${powershellLiteral(input2.nodeExecutable)} ${powershellLiteral(input2.cliEntry)} daemon --profile ${input2.profile}"` : directArgument
84179
84278
  );
84180
84279
  const registerScript = [
84280
+ "$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name",
84181
84281
  `$action = New-ScheduledTaskAction -Execute ${executable} -Argument ${argument}`,
84182
- "$trigger = New-ScheduledTaskTrigger -AtLogOn",
84282
+ "$trigger = New-ScheduledTaskTrigger -AtLogOn -User $currentUser",
84283
+ "$principal = New-ScheduledTaskPrincipal -UserId $currentUser -LogonType Interactive -RunLevel Limited",
84183
84284
  "$settings = New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit ([TimeSpan]::Zero)",
84184
- `Register-ScheduledTask -TaskName ${powershellLiteral(WINDOWS_TASK)} -Action $action -Trigger $trigger -Settings $settings -Force | Out-Null`
84285
+ `Register-ScheduledTask -TaskName ${powershellLiteral(WINDOWS_TASK)} -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null`
84185
84286
  ].join("; ");
84186
84287
  return {
84187
84288
  platform: "win32",
@@ -84319,8 +84420,14 @@ function defaultSleep(ms) {
84319
84420
  });
84320
84421
  }
84321
84422
  function parseServiceHostState(servicePlatform, result) {
84322
- if (result.status !== 0) return "unknown";
84323
84423
  const output2 = result.output;
84424
+ if (servicePlatform === "linux") {
84425
+ const trimmed = output2.trim().toLowerCase();
84426
+ if (trimmed === "inactive" || trimmed === "failed" || trimmed === "dead" || /\binactive\b/i.test(output2) || /\bfailed\b/i.test(output2)) {
84427
+ return "stopped";
84428
+ }
84429
+ }
84430
+ if (result.status !== 0) return "unknown";
84324
84431
  if (servicePlatform === "darwin") {
84325
84432
  if (/\bstate\s*=\s*running\b/i.test(output2)) return "running";
84326
84433
  if (/\bstate\s*=\s*(not running|waiting|stopped)\b/i.test(output2)) return "stopped";
@@ -84332,9 +84439,6 @@ function parseServiceHostState(servicePlatform, result) {
84332
84439
  const trimmed = output2.trim().toLowerCase();
84333
84440
  if (trimmed === "active" || /\bactive\s*\(running\)/i.test(output2)) return "running";
84334
84441
  if (trimmed === "activating" || trimmed === "reloading") return "starting";
84335
- if (trimmed === "inactive" || trimmed === "failed" || trimmed === "dead" || /\binactive\b/i.test(output2) || /\bfailed\b/i.test(output2)) {
84336
- return "stopped";
84337
- }
84338
84442
  return "unknown";
84339
84443
  }
84340
84444
  const stateMatch = output2.match(/\b(?:State|state)\s*[:=]\s*(\w+)/);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiden-ade/sandbox-agent",
3
- "version": "0.1.84",
3
+ "version": "0.1.86",
4
4
  "type": "module",
5
5
  "description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
6
6
  "bin": {