@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.
- package/dist/index.cjs +266 -162
- 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.
|
|
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")
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
55547
|
-
var
|
|
55548
|
-
var
|
|
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,
|
|
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,
|
|
56494
|
-
return () => (0,
|
|
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,
|
|
56500
|
-
(0,
|
|
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,
|
|
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,
|
|
56565
|
-
(0,
|
|
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,
|
|
56673
|
+
(0, import_node_fs17.rmSync)(pendingPath, { force: true });
|
|
56568
56674
|
}
|
|
56569
56675
|
}
|
|
56570
|
-
async function configureAntigravityApiKeyMode(home = (0,
|
|
56571
|
-
const path2 = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
56677
|
-
})).filter((entry) => (0,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
|
77309
|
-
return typeof error61 === "object" && error61 !== null && "code" in error61 && error61.code
|
|
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 (
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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 (
|
|
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
|
-
|
|
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+)/);
|