@alan-ai-hq/agent-manager 0.1.122 → 0.1.123
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 +1204 -566
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -33429,6 +33429,13 @@ var activeRunSlotSchema = external_exports.object({
|
|
|
33429
33429
|
awaitingUser: external_exports.boolean().optional(),
|
|
33430
33430
|
stale: external_exports.boolean().optional()
|
|
33431
33431
|
});
|
|
33432
|
+
var MAX_REPORTED_TRANSCRIPT_SYNC_RUNS = 50;
|
|
33433
|
+
var transcriptSyncPendingRunSchema = external_exports.object({
|
|
33434
|
+
runId: external_exports.uuid(),
|
|
33435
|
+
conversationId: external_exports.uuid(),
|
|
33436
|
+
problemStatus: external_exports.number().int().optional(),
|
|
33437
|
+
problemPermanent: external_exports.boolean().optional()
|
|
33438
|
+
});
|
|
33432
33439
|
var RUNNER_CAPACITY_SOURCES = ["default", "config", "provider_limit"];
|
|
33433
33440
|
var DEFAULT_MAX_ACTIVE_RUNS = 4;
|
|
33434
33441
|
var MIN_MAX_ACTIVE_RUNS = 1;
|
|
@@ -33444,6 +33451,8 @@ var runtimeRunnerStatusSchema = external_exports.object({
|
|
|
33444
33451
|
restartRecommended: external_exports.boolean(),
|
|
33445
33452
|
activeRuns: external_exports.array(activeRunSlotSchema),
|
|
33446
33453
|
interruptedRunIds: external_exports.array(external_exports.uuid()).optional(),
|
|
33454
|
+
// A malformed backlog must not discard the rest of the heartbeat.
|
|
33455
|
+
transcriptSyncPending: external_exports.array(transcriptSyncPendingRunSchema).max(MAX_REPORTED_TRANSCRIPT_SYNC_RUNS).optional().catch(void 0),
|
|
33447
33456
|
activeRunCount: external_exports.number().int().nonnegative(),
|
|
33448
33457
|
staleRunCount: external_exports.number().int().nonnegative(),
|
|
33449
33458
|
/**
|
|
@@ -34913,10 +34922,28 @@ function resolveWindowsCodexNativeExecutable(executable) {
|
|
|
34913
34922
|
}
|
|
34914
34923
|
return executable;
|
|
34915
34924
|
}
|
|
34925
|
+
function promoteAheadOfVersionManagers(path2, promoted, versionManagerDirs) {
|
|
34926
|
+
const managed = new Set(versionManagerDirs);
|
|
34927
|
+
const firstManaged = path2.findIndex((dir) => managed.has(dir));
|
|
34928
|
+
if (firstManaged === -1) return path2;
|
|
34929
|
+
const before = path2.slice(0, firstManaged);
|
|
34930
|
+
const tail = path2.slice(firstManaged);
|
|
34931
|
+
const moved = tail.filter((dir) => promoted.has(dir));
|
|
34932
|
+
if (moved.length === 0) return path2;
|
|
34933
|
+
return [...before, ...moved, ...tail.filter((dir) => !promoted.has(dir))];
|
|
34934
|
+
}
|
|
34935
|
+
function promotedUserBinDirs(home) {
|
|
34936
|
+
return /* @__PURE__ */ new Set([
|
|
34937
|
+
(0, import_node_path5.join)(home, ".local", "bin"),
|
|
34938
|
+
(0, import_node_path5.join)(home, ".bun", "bin"),
|
|
34939
|
+
(0, import_node_path5.join)(home, ".cargo", "bin")
|
|
34940
|
+
]);
|
|
34941
|
+
}
|
|
34916
34942
|
function augmentCliPath2(env, includeSystemPaths = true) {
|
|
34917
34943
|
const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
|
|
34918
34944
|
const isWin = (0, import_node_os4.platform)() === "win32";
|
|
34919
34945
|
const windowsLocalAppData = env.LOCALAPPDATA || (0, import_node_path5.join)(home, "AppData", "Local");
|
|
34946
|
+
const versionManagerDirs = isWin ? [] : resolveVersionManagerBinDirs(home);
|
|
34920
34947
|
const userPaths = isWin ? [
|
|
34921
34948
|
(0, import_node_path5.join)(home, "AppData", "Roaming", "npm"),
|
|
34922
34949
|
(0, import_node_path5.join)(windowsLocalAppData, "Programs", "OpenAI", "Codex", "bin"),
|
|
@@ -34930,18 +34957,17 @@ function augmentCliPath2(env, includeSystemPaths = true) {
|
|
|
34930
34957
|
// nvm/fnm/volta/asdf/mise live behind shell functions and leave nothing
|
|
34931
34958
|
// on a non-interactive PATH, so resolve them from disk. Without this a
|
|
34932
34959
|
// degraded shell probe hides node entirely and `env node` hooks die 127.
|
|
34933
|
-
...
|
|
34960
|
+
...versionManagerDirs
|
|
34934
34961
|
];
|
|
34935
34962
|
const systemPaths = isWin ? ["C:\\Program Files\\nodejs", "C:\\Program Files\\Git\\cmd"] : ["/opt/homebrew/bin", "/usr/local/bin"];
|
|
34936
34963
|
const extraPaths = includeSystemPaths ? [...userPaths, ...systemPaths] : userPaths;
|
|
34937
34964
|
const basePath = env.PATH ?? "";
|
|
34938
34965
|
const existing = new Set(splitPath3(basePath));
|
|
34939
34966
|
const missing = extraPaths.filter((dir) => !existing.has(dir));
|
|
34940
|
-
|
|
34941
|
-
|
|
34942
|
-
|
|
34943
|
-
|
|
34944
|
-
};
|
|
34967
|
+
const combined = missing.length > 0 ? [...missing, ...splitPath3(basePath)] : splitPath3(basePath);
|
|
34968
|
+
const ordered = isWin ? combined : promoteAheadOfVersionManagers(combined, promotedUserBinDirs(home), versionManagerDirs);
|
|
34969
|
+
if (ordered === combined && missing.length === 0) return env;
|
|
34970
|
+
return { ...env, PATH: ordered.join(pathSeparator()) };
|
|
34945
34971
|
}
|
|
34946
34972
|
function resolveCliExecutable(command, env) {
|
|
34947
34973
|
const trimmed4 = command.trim();
|
|
@@ -35245,7 +35271,7 @@ function buildComputerReadiness(input2) {
|
|
|
35245
35271
|
}
|
|
35246
35272
|
|
|
35247
35273
|
// src/version.ts
|
|
35248
|
-
var AGENT_VERSION = "0.1.
|
|
35274
|
+
var AGENT_VERSION = "0.1.123";
|
|
35249
35275
|
|
|
35250
35276
|
// src/daemon/status.ts
|
|
35251
35277
|
var PENDING_RUN_START_TTL_MS = 10 * 6e4;
|
|
@@ -35348,6 +35374,10 @@ function buildAbortResult(reason) {
|
|
|
35348
35374
|
errorKind: reason
|
|
35349
35375
|
};
|
|
35350
35376
|
}
|
|
35377
|
+
function abortResultFor(reason, sessionId) {
|
|
35378
|
+
const result = buildAbortResult(reason);
|
|
35379
|
+
return sessionId ? { ...result, providerSessionId: sessionId, runtimeSessionId: sessionId } : result;
|
|
35380
|
+
}
|
|
35351
35381
|
function abortActiveAgent(entry, options) {
|
|
35352
35382
|
const awaitingAsk = entry.runHost.pendingAskUserToolIds.size > 0;
|
|
35353
35383
|
const reason = options?.reason ?? (options?.userInitiated ? "user" : "runner_stalled");
|
|
@@ -35355,7 +35385,7 @@ function abortActiveAgent(entry, options) {
|
|
|
35355
35385
|
return;
|
|
35356
35386
|
}
|
|
35357
35387
|
entry.cleanupState = "stopping";
|
|
35358
|
-
entry.runHost.onComplete(
|
|
35388
|
+
entry.runHost.onComplete(abortResultFor(reason, entry.runHost.sessionId));
|
|
35359
35389
|
entry.agent.kill();
|
|
35360
35390
|
}
|
|
35361
35391
|
function isProviderProcessAlive(pid) {
|
|
@@ -35444,6 +35474,7 @@ function buildRunnerStatusPayload(input2) {
|
|
|
35444
35474
|
restartRecommended: false,
|
|
35445
35475
|
activeRuns,
|
|
35446
35476
|
interruptedRunIds: input2.interruptedRunIds ?? [],
|
|
35477
|
+
transcriptSyncPending: input2.transcriptSyncPending ?? [],
|
|
35447
35478
|
activeRunCount,
|
|
35448
35479
|
staleRunCount,
|
|
35449
35480
|
maxActiveRuns,
|
|
@@ -35512,7 +35543,7 @@ function reconcileActiveRuns(input2) {
|
|
|
35512
35543
|
const verdict = reconcileVerdict(entry, nowMs);
|
|
35513
35544
|
if (verdict.action === "keep") continue;
|
|
35514
35545
|
if (verdict.action === "finalize_for_resume") {
|
|
35515
|
-
entry.runHost.onComplete(
|
|
35546
|
+
entry.runHost.onComplete(abortResultFor("provider_exited", entry.runHost.sessionId));
|
|
35516
35547
|
entry.agent.kill();
|
|
35517
35548
|
releaseAfterCleanup(input2.activeAgents, runId, entry);
|
|
35518
35549
|
input2.pushLog?.(
|
|
@@ -35570,7 +35601,8 @@ function runnerStateFingerprint(summary) {
|
|
|
35570
35601
|
summary.staleRunCount,
|
|
35571
35602
|
summary.runnerStatus.primaryMessage ?? "",
|
|
35572
35603
|
readiness,
|
|
35573
|
-
[...summary.activeRunIds].sort().join(",")
|
|
35604
|
+
[...summary.activeRunIds].sort().join(","),
|
|
35605
|
+
(summary.runnerStatus.transcriptSyncPending ?? []).map((run) => `${run.runId}:${run.problemStatus ?? ""}`).sort().join(",")
|
|
35574
35606
|
].join("|");
|
|
35575
35607
|
}
|
|
35576
35608
|
|
|
@@ -40153,20 +40185,36 @@ function providerModelCacheKey(provider, executable) {
|
|
|
40153
40185
|
return `${provider}:${executable}`;
|
|
40154
40186
|
}
|
|
40155
40187
|
var providerVersionCache = /* @__PURE__ */ new Map();
|
|
40188
|
+
var providerRunCache = /* @__PURE__ */ new Map();
|
|
40156
40189
|
var providerModelCache = /* @__PURE__ */ new Map();
|
|
40157
40190
|
var providerAvailabilitySeen = /* @__PURE__ */ new Set();
|
|
40158
40191
|
var providerProbesInFlight = /* @__PURE__ */ new Map();
|
|
40159
40192
|
var providerModelProbesInFlight = /* @__PURE__ */ new Map();
|
|
40160
40193
|
var VERSION_REFRESH_INTERVAL_MS = 20 * 60 * 1e3;
|
|
40194
|
+
function firstNonEmptyLine(text2) {
|
|
40195
|
+
return text2.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
|
|
40196
|
+
}
|
|
40161
40197
|
function refreshSingleProviderVersion(provider, executable, env) {
|
|
40162
40198
|
const inFlight = providerProbesInFlight.get(provider);
|
|
40163
40199
|
if (inFlight) return inFlight;
|
|
40164
40200
|
const probe = (async () => {
|
|
40165
40201
|
try {
|
|
40166
40202
|
const result = await runCliVersionProbeAsync(executable, env);
|
|
40167
|
-
if (result.error || result.status !==
|
|
40168
|
-
|
|
40169
|
-
|
|
40203
|
+
if (result.error || result.signal || typeof result.status !== "number") {
|
|
40204
|
+
providerRunCache.delete(provider);
|
|
40205
|
+
return;
|
|
40206
|
+
}
|
|
40207
|
+
const firstLine3 = firstNonEmptyLine(result.stdout) ?? firstNonEmptyLine(result.stderr);
|
|
40208
|
+
if (result.status !== 0) {
|
|
40209
|
+
providerRunCache.set(provider, {
|
|
40210
|
+
status: "cannot_start",
|
|
40211
|
+
...firstLine3 ? { message: firstLine3 } : {},
|
|
40212
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
40213
|
+
});
|
|
40214
|
+
return;
|
|
40215
|
+
}
|
|
40216
|
+
if (firstLine3) providerVersionCache.set(provider, firstLine3);
|
|
40217
|
+
providerRunCache.set(provider, { status: "ready", checkedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
40170
40218
|
} finally {
|
|
40171
40219
|
providerProbesInFlight.delete(provider);
|
|
40172
40220
|
}
|
|
@@ -40278,10 +40326,12 @@ function discoverCapabilities() {
|
|
|
40278
40326
|
void refreshSingleProviderVersion(provider, executable, env);
|
|
40279
40327
|
} else if (!available) {
|
|
40280
40328
|
providerAvailabilitySeen.delete(provider);
|
|
40329
|
+
providerRunCache.delete(provider);
|
|
40281
40330
|
}
|
|
40282
40331
|
const version2 = providerVersionCache.get(provider);
|
|
40283
40332
|
const modelDiscovery = executable ? providerModelCache.get(providerModelCacheKey(provider, executable)) : void 0;
|
|
40284
40333
|
const auth = !available ? void 0 : provider === ALAN_CODE_PROVIDER_KIND ? { status: "ready", checkedAt: now } : providerAuthCache.get(provider);
|
|
40334
|
+
const run = available ? providerRunCache.get(provider) : void 0;
|
|
40285
40335
|
return {
|
|
40286
40336
|
provider,
|
|
40287
40337
|
available,
|
|
@@ -40297,6 +40347,11 @@ function discoverCapabilities() {
|
|
|
40297
40347
|
authStatus: auth.status,
|
|
40298
40348
|
...auth.message ? { authMessage: auth.message } : {},
|
|
40299
40349
|
authCheckedAt: auth.checkedAt
|
|
40350
|
+
} : {},
|
|
40351
|
+
...run ? {
|
|
40352
|
+
runStatus: run.status,
|
|
40353
|
+
...run.message ? { runMessage: run.message } : {},
|
|
40354
|
+
runCheckedAt: run.checkedAt
|
|
40300
40355
|
} : {}
|
|
40301
40356
|
};
|
|
40302
40357
|
}),
|
|
@@ -43410,21 +43465,23 @@ var import_os3 = require("os");
|
|
|
43410
43465
|
var import_path7 = require("path");
|
|
43411
43466
|
var import_promises3 = require("fs/promises");
|
|
43412
43467
|
var import_path8 = require("path");
|
|
43468
|
+
var import_promises4 = require("fs/promises");
|
|
43469
|
+
var import_path9 = require("path");
|
|
43413
43470
|
var import_crypto4 = require("crypto");
|
|
43414
43471
|
var import_crypto5 = require("crypto");
|
|
43415
43472
|
var import_fs9 = require("fs");
|
|
43416
43473
|
var import_os4 = require("os");
|
|
43417
|
-
var
|
|
43474
|
+
var import_path10 = require("path");
|
|
43418
43475
|
var import_url2 = require("url");
|
|
43419
43476
|
var import_child_process6 = require("child_process");
|
|
43420
43477
|
var import_util14 = require("util");
|
|
43421
43478
|
var import_os5 = require("os");
|
|
43422
|
-
var
|
|
43479
|
+
var import_path11 = require("path");
|
|
43423
43480
|
var import_url3 = require("url");
|
|
43424
43481
|
var import_fs10 = require("fs");
|
|
43425
43482
|
var import_fs11 = require("fs");
|
|
43426
43483
|
var import_fs12 = require("fs");
|
|
43427
|
-
var
|
|
43484
|
+
var import_path12 = require("path");
|
|
43428
43485
|
var import_crypto6 = require("crypto");
|
|
43429
43486
|
|
|
43430
43487
|
// ../shared/dist/constants/local-workspace.js
|
|
@@ -43437,16 +43494,19 @@ function isAlanDefaultWorkspace(value2) {
|
|
|
43437
43494
|
var import_crypto7 = require("crypto");
|
|
43438
43495
|
var import_fs13 = require("fs");
|
|
43439
43496
|
var import_os6 = require("os");
|
|
43440
|
-
var import_path12 = require("path");
|
|
43441
|
-
var import_fs14 = require("fs");
|
|
43442
43497
|
var import_path13 = require("path");
|
|
43498
|
+
var import_fs14 = require("fs");
|
|
43499
|
+
var import_path14 = require("path");
|
|
43443
43500
|
var import_fs15 = require("fs");
|
|
43444
43501
|
var import_os7 = require("os");
|
|
43445
|
-
var
|
|
43446
|
-
var import_child_process7 = require("child_process");
|
|
43502
|
+
var import_path15 = require("path");
|
|
43447
43503
|
var import_fs16 = require("fs");
|
|
43448
43504
|
var import_os8 = require("os");
|
|
43449
|
-
var
|
|
43505
|
+
var import_path16 = require("path");
|
|
43506
|
+
var import_child_process7 = require("child_process");
|
|
43507
|
+
var import_fs17 = require("fs");
|
|
43508
|
+
var import_os9 = require("os");
|
|
43509
|
+
var import_path17 = require("path");
|
|
43450
43510
|
function createGrammarState() {
|
|
43451
43511
|
return { seenToolCallIds: /* @__PURE__ */ new Set(), counter: 0, scratch: {} };
|
|
43452
43512
|
}
|
|
@@ -43891,6 +43951,7 @@ var CLI_PROBLEM_CODE_BY_ERROR_KIND = {
|
|
|
43891
43951
|
network: "cli.unknown",
|
|
43892
43952
|
provider_timeout: "cli.process.timeout",
|
|
43893
43953
|
resume_failed: "cli.resume_failed",
|
|
43954
|
+
history_rejected: "cli.resume_failed",
|
|
43894
43955
|
permission_denied: "cli.tool.failed",
|
|
43895
43956
|
interpreter_missing: "cli.process.not_found",
|
|
43896
43957
|
out_of_memory: "cli.process.nonzero_exit",
|
|
@@ -43986,6 +44047,10 @@ var ERROR_SPECS = {
|
|
|
43986
44047
|
message: "The previous session could not be resumed \u2014 its stored session was missing or expired. The next message starts a fresh session without earlier context.",
|
|
43987
44048
|
recoveryClass: "retry"
|
|
43988
44049
|
},
|
|
44050
|
+
history_rejected: {
|
|
44051
|
+
message: "The provider rejected this session's stored history, so it could not be continued. The next message starts a fresh session with the recent conversation re-included.",
|
|
44052
|
+
recoveryClass: "retry"
|
|
44053
|
+
},
|
|
43989
44054
|
permission_denied: {
|
|
43990
44055
|
message: "Permission denied. Check file or command permissions on the runtime.",
|
|
43991
44056
|
recoveryClass: "needs_env"
|
|
@@ -44060,6 +44125,7 @@ function normalizeCodexCliErrorMessage(message) {
|
|
|
44060
44125
|
}
|
|
44061
44126
|
return message;
|
|
44062
44127
|
}
|
|
44128
|
+
var NAMED_SESSION_NOT_FOUND = /\b(?:session|chat|conversation)\s+(?:"[^"\n]{1,160}"|'[^'\n]{1,160}'|[\w-]{6,})\s+not found\b/;
|
|
44063
44129
|
function classifyCliErrorDetailed(stderr, exitCode, opts) {
|
|
44064
44130
|
const normalizedCodexError = normalizeCodexCliErrorMessage(stderr);
|
|
44065
44131
|
if (normalizedCodexError !== stderr) {
|
|
@@ -44088,7 +44154,28 @@ function classifyCliErrorDetailed(stderr, exitCode, opts) {
|
|
|
44088
44154
|
return specForErrorKind("usage_limit");
|
|
44089
44155
|
if (has("creditserror", "no payment method")) return specForErrorKind("subscription_required");
|
|
44090
44156
|
if (has("datapolicyerror", "requires explicit opt in")) return specForErrorKind("model_mismatch");
|
|
44091
|
-
if (has(
|
|
44157
|
+
if (has(
|
|
44158
|
+
"text content blocks must be non-empty",
|
|
44159
|
+
"content field in the message object",
|
|
44160
|
+
"ids were found without `tool_result` blocks",
|
|
44161
|
+
"ids were found without tool_result blocks",
|
|
44162
|
+
"unexpected `tool_use_id`",
|
|
44163
|
+
"unexpected tool_use_id",
|
|
44164
|
+
"tool use concurrency issues",
|
|
44165
|
+
"no tool output found for",
|
|
44166
|
+
"does not support assistant message prefill"
|
|
44167
|
+
))
|
|
44168
|
+
return specForErrorKind("history_rejected");
|
|
44169
|
+
if (has(
|
|
44170
|
+
"no chat found",
|
|
44171
|
+
"chat not found",
|
|
44172
|
+
"session not found",
|
|
44173
|
+
"could not resume",
|
|
44174
|
+
"no conversation found",
|
|
44175
|
+
"no rollout found",
|
|
44176
|
+
"no session, task, or name matched",
|
|
44177
|
+
"conversation not found"
|
|
44178
|
+
) || NAMED_SESSION_NOT_FOUND.test(haystack))
|
|
44092
44179
|
return specForErrorKind("resume_failed");
|
|
44093
44180
|
if (has("rate_limit", "rate limit", "resource_exhausted", "resource exhausted") || /\b429\b/.test(haystack))
|
|
44094
44181
|
return specForErrorKind("rate_limited");
|
|
@@ -44714,14 +44801,6 @@ function settleControlRequest(kind, state, requestId) {
|
|
|
44714
44801
|
}
|
|
44715
44802
|
}
|
|
44716
44803
|
function deferOrFinalizeStructuredResult(kind, _context, state) {
|
|
44717
|
-
const pendingAsks = state.pendingAskUserToolIds?.size ?? 0;
|
|
44718
|
-
if (pendingAsks > 0) {
|
|
44719
|
-
console.info(
|
|
44720
|
-
`[${kind}] Keeping stdin open \u2014 ${pendingAsks} interactive question(s) awaiting user response`
|
|
44721
|
-
);
|
|
44722
|
-
state.resultDeferredOnPendingAnswer = true;
|
|
44723
|
-
return "deferred_pending_answer";
|
|
44724
|
-
}
|
|
44725
44804
|
const activeBackgroundTasks = state.activeBackgroundTaskIds?.size ?? 0;
|
|
44726
44805
|
if (activeBackgroundTasks > 0) {
|
|
44727
44806
|
console.info(
|
|
@@ -44734,17 +44813,12 @@ function deferOrFinalizeStructuredResult(kind, _context, state) {
|
|
|
44734
44813
|
return "finalized";
|
|
44735
44814
|
}
|
|
44736
44815
|
function maybeFinalizeDeferredResult(kind, _context, state) {
|
|
44737
|
-
if (!state.resultDeferredOnBackgroundWork
|
|
44738
|
-
if (state.
|
|
44739
|
-
|
|
44740
|
-
|
|
44741
|
-
|
|
44742
|
-
|
|
44743
|
-
);
|
|
44744
|
-
return;
|
|
44745
|
-
}
|
|
44746
|
-
state.resultDeferredOnPendingAnswer = false;
|
|
44747
|
-
finalizeStructuredResult(kind, state);
|
|
44816
|
+
if (!state.resultDeferredOnBackgroundWork) return;
|
|
44817
|
+
if (state.activeBackgroundTaskIds?.size) return;
|
|
44818
|
+
state.awaitingPostBackgroundSynthesis = true;
|
|
44819
|
+
console.info(
|
|
44820
|
+
`[${kind}] Background work drained \u2014 awaiting post-subagent synthesis before stdin close`
|
|
44821
|
+
);
|
|
44748
44822
|
}
|
|
44749
44823
|
function logResumeObservability(event, fields) {
|
|
44750
44824
|
console.info(`[agent-resume] ${event}`, { event, ...fields });
|
|
@@ -44771,12 +44845,6 @@ function buildCliResult(facts, identity, state) {
|
|
|
44771
44845
|
function cliProblemScope(context) {
|
|
44772
44846
|
return context.config.conversationId ? { conversationId: context.config.conversationId } : {};
|
|
44773
44847
|
}
|
|
44774
|
-
var IDLE_TIMEOUT_MESSAGES = {
|
|
44775
|
-
background_task: "Agent timed out waiting for a background task to finish \u2014 no terminal event arrived, so the run was stopped. Send your message again to continue.",
|
|
44776
|
-
post_subagent_synthesis: "Agent timed out waiting for a post-subagent summary \u2014 synthesis did not finish, so the run was stopped. Send your message again to continue.",
|
|
44777
|
-
post_startup_silence: "The agent went silent and stopped responding, so the run was stopped. Send your message again to retry.",
|
|
44778
|
-
pending_user_answer: "Agent timed out waiting for your answer to its question \u2014 no response arrived, so the run was stopped. Send your reply as a new message to continue."
|
|
44779
|
-
};
|
|
44780
44848
|
function timeoutProblem(closing, message, phase) {
|
|
44781
44849
|
const { options, context, observed } = closing;
|
|
44782
44850
|
return createCliProblem(
|
|
@@ -44874,44 +44942,6 @@ function startupTimeoutResult(closing) {
|
|
|
44874
44942
|
state
|
|
44875
44943
|
);
|
|
44876
44944
|
}
|
|
44877
|
-
async function idleTimeoutResult(closing) {
|
|
44878
|
-
const { options, context, state, observed } = closing;
|
|
44879
|
-
if (!observed.idleTimedOut) return null;
|
|
44880
|
-
console.error(`[${options.kind}] Process force-killed after idle timeout`, {
|
|
44881
|
-
stderrLines: observed.recentStderrLines,
|
|
44882
|
-
summaryPreview: state.summary.slice(0, 200),
|
|
44883
|
-
runtimeSessionId: state.runtimeSessionId
|
|
44884
|
-
});
|
|
44885
|
-
await options.afterExit?.(context, state);
|
|
44886
|
-
if (hasRenderableTurn(state)) emitTurnEnd(context, state);
|
|
44887
|
-
const deferred = deferredBackgroundSummary(closing);
|
|
44888
|
-
if (deferred) {
|
|
44889
|
-
console.warn(
|
|
44890
|
-
`[${options.kind}] Finalizing deferred result after background-task idle timeout \u2014 turn content was already delivered`
|
|
44891
|
-
);
|
|
44892
|
-
return buildCliResult({ success: true, summary: deferred }, options, state);
|
|
44893
|
-
}
|
|
44894
|
-
const message = observed.idleTimeoutReason ? IDLE_TIMEOUT_MESSAGES[observed.idleTimeoutReason] : IDLE_TIMEOUT_MESSAGES.pending_user_answer;
|
|
44895
|
-
return buildCliResult(
|
|
44896
|
-
{
|
|
44897
|
-
success: false,
|
|
44898
|
-
summary: state.summary.trim() || "Agent execution timed out",
|
|
44899
|
-
error: message,
|
|
44900
|
-
errorKind: "provider_timeout",
|
|
44901
|
-
recoveryClass: "retry",
|
|
44902
|
-
problem: timeoutProblem(closing, message, "stream")
|
|
44903
|
-
},
|
|
44904
|
-
options,
|
|
44905
|
-
state
|
|
44906
|
-
);
|
|
44907
|
-
}
|
|
44908
|
-
function deferredBackgroundSummary(closing) {
|
|
44909
|
-
const { state, observed } = closing;
|
|
44910
|
-
const waitingOnBackground = observed.idleTimeoutReason === "background_task" || observed.idleTimeoutReason === "post_subagent_synthesis";
|
|
44911
|
-
if (!waitingOnBackground) return "";
|
|
44912
|
-
if (!state.resultDeferredOnBackgroundWork && !state.awaitingPostBackgroundSynthesis) return "";
|
|
44913
|
-
return state.summary.trim();
|
|
44914
|
-
}
|
|
44915
44945
|
function hasRenderableTurn(state) {
|
|
44916
44946
|
return state.summary.trim().length > 0 || state.iterations > 0;
|
|
44917
44947
|
}
|
|
@@ -44920,8 +44950,13 @@ function backgroundStillActive(state) {
|
|
|
44920
44950
|
}
|
|
44921
44951
|
function observeClose(closing) {
|
|
44922
44952
|
const { state, observed } = closing;
|
|
44953
|
+
const backgroundActive = backgroundStillActive(state);
|
|
44923
44954
|
return {
|
|
44924
|
-
|
|
44955
|
+
// A turn we ended because its result had already been delivered is cleanup, not a
|
|
44956
|
+
// parent that died on its subagents. The content reached the reader, so only a
|
|
44957
|
+
// provider that left on its own with work outstanding fails the run.
|
|
44958
|
+
midSubagentParentExit: backgroundActive && !observed.startupTimedOut && state.exitGraceKillTriggered !== true,
|
|
44959
|
+
abandonedBackgroundWork: backgroundActive,
|
|
44925
44960
|
activeBackgroundTaskCount: state.activeBackgroundTaskIds?.size ?? 0
|
|
44926
44961
|
};
|
|
44927
44962
|
}
|
|
@@ -44980,8 +45015,6 @@ function logProcessClose(closing, facts) {
|
|
|
44980
45015
|
activeBackgroundTaskCount: facts.activeBackgroundTaskCount,
|
|
44981
45016
|
activeBackgroundTaskIds: [...state.activeBackgroundTaskIds ?? []].slice(0, 8),
|
|
44982
45017
|
pendingAskCount: state.pendingAskUserToolIds?.size ?? 0,
|
|
44983
|
-
idleTimedOut: observed.idleTimedOut,
|
|
44984
|
-
idleTimeoutReason: observed.idleTimeoutReason,
|
|
44985
45018
|
startupTimedOut: observed.startupTimedOut,
|
|
44986
45019
|
midSubagentParentExit: facts.midSubagentParentExit,
|
|
44987
45020
|
runtimeSessionId: state.runtimeSessionId
|
|
@@ -45112,28 +45145,30 @@ function failureProblem(closing, verdict, failure2) {
|
|
|
45112
45145
|
}
|
|
45113
45146
|
);
|
|
45114
45147
|
}
|
|
45115
|
-
function summaryFor(state, verdict) {
|
|
45148
|
+
function summaryFor(state, verdict, failureMessage) {
|
|
45116
45149
|
const reported = state.summary.trim() || state.error?.trim();
|
|
45117
45150
|
if (reported) return reported;
|
|
45118
45151
|
if (!verdict.failed) return "Task completed";
|
|
45152
|
+
if (failureMessage?.trim()) return failureMessage.trim();
|
|
45119
45153
|
return verdict.midSubagentParentExit ? "Background agents interrupted" : "Task failed";
|
|
45120
45154
|
}
|
|
45121
45155
|
async function closedRunResult(closing, silentResumeFork) {
|
|
45122
45156
|
const { options, context, state } = closing;
|
|
45123
45157
|
const facts = observeClose(closing);
|
|
45124
45158
|
const diagnostics = logProcessClose(closing, facts);
|
|
45125
|
-
if (facts.
|
|
45159
|
+
if (facts.abandonedBackgroundWork) settleAbandonedSubagents(closing, diagnostics);
|
|
45126
45160
|
await options.afterExit?.(context, state);
|
|
45127
45161
|
if (hasRenderableTurn(state)) emitTurnEnd(context, state);
|
|
45128
45162
|
const verdict = judge(closing, facts);
|
|
45129
45163
|
if (silentResumeFork && !verdict.failed) return resumeFailedResult(closing);
|
|
45130
|
-
|
|
45131
|
-
|
|
45164
|
+
if (!verdict.failed) {
|
|
45165
|
+
return buildCliResult({ success: true, summary: summaryFor(state, verdict) }, options, state);
|
|
45166
|
+
}
|
|
45132
45167
|
const failure2 = withRequiredResumeId(explainFailure(closing, verdict), context);
|
|
45133
45168
|
return buildCliResult(
|
|
45134
45169
|
{
|
|
45135
45170
|
success: false,
|
|
45136
|
-
summary,
|
|
45171
|
+
summary: summaryFor(state, verdict, failure2.error),
|
|
45137
45172
|
error: failure2.error,
|
|
45138
45173
|
errorKind: failure2.errorKind,
|
|
45139
45174
|
recoveryClass: failure2.recoveryClass,
|
|
@@ -45525,9 +45560,7 @@ var TEXT_TIER_MESSAGE_ID = "cli-stdout";
|
|
|
45525
45560
|
var CLI_STDERR_TAIL_CHARS = 256 * 1024;
|
|
45526
45561
|
var SPAWN_OUTCOME_TIMEOUT_MS = 2e3;
|
|
45527
45562
|
var RESULT_EXIT_GRACE_MS = 5e3;
|
|
45528
|
-
var IDLE_KILL_EXIT_WAIT_MS = 5e3;
|
|
45529
45563
|
var DESCENDANT_CLEANUP_MS = 1e3;
|
|
45530
|
-
var DEFAULT_RESULT_IDLE_MS = 10 * 60 * 1e3;
|
|
45531
45564
|
var SPAWN_RETRY_DELAYS_BY_CODE = {
|
|
45532
45565
|
ETXTBSY: [250, 750, 1500, 3e3, 5e3],
|
|
45533
45566
|
ENOENT: [250, 750]
|
|
@@ -45668,24 +45701,6 @@ var StreamCapture = class {
|
|
|
45668
45701
|
emitSessionUpdate(logUpdate(this.options.kind, line), this.context, this.state);
|
|
45669
45702
|
}
|
|
45670
45703
|
};
|
|
45671
|
-
function idleTimeoutReasonNow(options, state, sawStdoutLine) {
|
|
45672
|
-
if (state.pendingAskUserToolIds?.size) return "pending_user_answer";
|
|
45673
|
-
if (state.awaitingPostBackgroundSynthesis) return "post_subagent_synthesis";
|
|
45674
|
-
if (state.resultDeferredOnBackgroundWork && state.activeBackgroundTaskIds?.size) {
|
|
45675
|
-
return "background_task";
|
|
45676
|
-
}
|
|
45677
|
-
const silenceMs = options.postStartupSilenceTimeoutMs;
|
|
45678
|
-
if (silenceMs && sawStdoutLine && typeof state.lastRawOutputAtMs === "number" && Date.now() - state.lastRawOutputAtMs >= silenceMs) {
|
|
45679
|
-
return "post_startup_silence";
|
|
45680
|
-
}
|
|
45681
|
-
return null;
|
|
45682
|
-
}
|
|
45683
|
-
var IDLE_WAIT_LABELS = {
|
|
45684
|
-
background_task: "a background task terminal event",
|
|
45685
|
-
post_subagent_synthesis: "post-subagent synthesis result",
|
|
45686
|
-
post_startup_silence: "any further output (silent hang)",
|
|
45687
|
-
pending_user_answer: "a pending user answer"
|
|
45688
|
-
};
|
|
45689
45704
|
var CliProcessSupervisor = class {
|
|
45690
45705
|
constructor(options, context, state) {
|
|
45691
45706
|
this.options = options;
|
|
@@ -45698,8 +45713,6 @@ var CliProcessSupervisor = class {
|
|
|
45698
45713
|
postExitTimer;
|
|
45699
45714
|
onAbort;
|
|
45700
45715
|
startupTimedOut = false;
|
|
45701
|
-
idleTimedOut = false;
|
|
45702
|
-
idleTimeoutReason = null;
|
|
45703
45716
|
async run(prompt, args) {
|
|
45704
45717
|
const child = await this.spawn(args);
|
|
45705
45718
|
this.streams = new StreamCapture(this.options, child, this.context, this.state);
|
|
@@ -45709,8 +45722,6 @@ var CliProcessSupervisor = class {
|
|
|
45709
45722
|
return {
|
|
45710
45723
|
exit: await this.awaitExit(child),
|
|
45711
45724
|
startupTimedOut: this.startupTimedOut,
|
|
45712
|
-
idleTimedOut: this.idleTimedOut,
|
|
45713
|
-
idleTimeoutReason: this.idleTimeoutReason,
|
|
45714
45725
|
stderrTail: this.streams.stderrTail,
|
|
45715
45726
|
recentStderrLines: this.streams.recentStderrLines
|
|
45716
45727
|
};
|
|
@@ -45795,51 +45806,26 @@ var CliProcessSupervisor = class {
|
|
|
45795
45806
|
const exit = this.exitPromise(child);
|
|
45796
45807
|
return this.options.keepStdinOpen ? this.raceExitAgainstResult(child, exit) : exit;
|
|
45797
45808
|
}
|
|
45809
|
+
/**
|
|
45810
|
+
* A structured CLI that holds stdin open ends its turn with a `result` frame and exits
|
|
45811
|
+
* once stdin closes. The process exit still decides the run's terminal state, so a
|
|
45812
|
+
* result only sets how long that exit is worth waiting for.
|
|
45813
|
+
*/
|
|
45798
45814
|
async raceExitAgainstResult(child, exit) {
|
|
45799
45815
|
const resultPromise = new Promise((resolve52) => {
|
|
45800
45816
|
this.state.onResultReceived = () => resolve52("result_received");
|
|
45801
45817
|
if (this.state.resultReceived) resolve52("result_received");
|
|
45802
45818
|
});
|
|
45803
|
-
const
|
|
45804
|
-
|
|
45805
|
-
|
|
45806
|
-
const armIdleTimer = () => {
|
|
45807
|
-
if (idleTimer) clearTimeout(idleTimer);
|
|
45808
|
-
idleTimer = setTimeout(() => {
|
|
45809
|
-
const reason = idleTimeoutReasonNow(
|
|
45810
|
-
this.options,
|
|
45811
|
-
this.state,
|
|
45812
|
-
this.streams?.sawStdoutLine === true
|
|
45813
|
-
);
|
|
45814
|
-
if (!reason) return armIdleTimer();
|
|
45815
|
-
this.idleTimeoutReason = reason;
|
|
45816
|
-
resolve52("idle_timeout");
|
|
45817
|
-
}, idleMs);
|
|
45818
|
-
};
|
|
45819
|
-
this.state.onNewOutput = armIdleTimer;
|
|
45820
|
-
armIdleTimer();
|
|
45821
|
-
});
|
|
45822
|
-
const outcome = await Promise.race([exit, resultPromise, idlePromise]);
|
|
45823
|
-
if (idleTimer) clearTimeout(idleTimer);
|
|
45824
|
-
if (outcome === "idle_timeout") return this.killAfterIdleTimeout(child, exit, idleMs);
|
|
45825
|
-
if (outcome === "result_received") return this.killAfterResult(child, exit);
|
|
45826
|
-
return outcome;
|
|
45827
|
-
}
|
|
45828
|
-
async killAfterIdleTimeout(child, exit, idleMs) {
|
|
45829
|
-
this.idleTimedOut = true;
|
|
45830
|
-
const waiting = this.idleTimeoutReason ? IDLE_WAIT_LABELS[this.idleTimeoutReason] : "the CLI";
|
|
45831
|
-
console.warn(
|
|
45832
|
-
`[${this.options.kind}] Idle timeout (${idleMs}ms) waiting for ${waiting} \u2014 force-killing orphaned process`
|
|
45833
|
-
);
|
|
45834
|
-
killProcessTree(child.pid, { signal: "SIGKILL", child });
|
|
45835
|
-
return Promise.race([
|
|
45836
|
-
exit,
|
|
45837
|
-
new Promise(
|
|
45838
|
-
(resolve52) => setTimeout(() => resolve52({ exitCode: null, signal: "SIGKILL" }), IDLE_KILL_EXIT_WAIT_MS)
|
|
45839
|
-
)
|
|
45840
|
-
]);
|
|
45819
|
+
const outcome = await Promise.race([exit, resultPromise]);
|
|
45820
|
+
if (outcome !== "result_received") return outcome;
|
|
45821
|
+
return this.closeAfterResult(child, exit);
|
|
45841
45822
|
}
|
|
45842
|
-
|
|
45823
|
+
/**
|
|
45824
|
+
* The turn is already delivered by the time this runs, so a process that will not leave
|
|
45825
|
+
* is cleanup rather than a verdict. Termination is awaited and verified, and recorded as
|
|
45826
|
+
* an expected grace kill so it cannot turn a delivered turn into a failure.
|
|
45827
|
+
*/
|
|
45828
|
+
async closeAfterResult(child, exit) {
|
|
45843
45829
|
const gracedExit = await Promise.race([
|
|
45844
45830
|
exit,
|
|
45845
45831
|
new Promise((resolve52) => setTimeout(() => resolve52(null), RESULT_EXIT_GRACE_MS))
|
|
@@ -45847,9 +45833,14 @@ var CliProcessSupervisor = class {
|
|
|
45847
45833
|
if (gracedExit) return gracedExit;
|
|
45848
45834
|
if (child.exitCode === null && !child.killed) {
|
|
45849
45835
|
console.warn(
|
|
45850
|
-
`[${this.options.kind}] Process still alive ${RESULT_EXIT_GRACE_MS}ms after result event
|
|
45836
|
+
`[${this.options.kind}] Process still alive ${RESULT_EXIT_GRACE_MS}ms after result event \u2014 terminating the process tree`
|
|
45851
45837
|
);
|
|
45852
|
-
|
|
45838
|
+
this.state.exitGraceKillTriggered = true;
|
|
45839
|
+
if (!await terminateProcessTree(child)) {
|
|
45840
|
+
console.error(
|
|
45841
|
+
`[${this.options.kind}] Process tree survived termination after result event`
|
|
45842
|
+
);
|
|
45843
|
+
}
|
|
45853
45844
|
}
|
|
45854
45845
|
return { exitCode: null, signal: null };
|
|
45855
45846
|
}
|
|
@@ -45891,7 +45882,7 @@ function createCliBackend(options) {
|
|
|
45891
45882
|
const observed = await supervisor.run(prompt, resolveArgs(options, context, prompt));
|
|
45892
45883
|
const closing = { options, context, state, observed };
|
|
45893
45884
|
const silentResumeFork = detectSilentResumeFork(closing);
|
|
45894
|
-
return abortedResult(closing) ?? startupTimeoutResult(closing) ?? await
|
|
45885
|
+
return abortedResult(closing) ?? startupTimeoutResult(closing) ?? await closedRunResult(closing, silentResumeFork);
|
|
45895
45886
|
}
|
|
45896
45887
|
};
|
|
45897
45888
|
}
|
|
@@ -46501,20 +46492,21 @@ function requireManagedBearerToken(registration) {
|
|
|
46501
46492
|
function requireManagedRunId(registration) {
|
|
46502
46493
|
return requiredHeader(registration, "x-alan-run-id");
|
|
46503
46494
|
}
|
|
46504
|
-
async function
|
|
46505
|
-
const path2 = (0, import_path8.join)(cwd, ".
|
|
46495
|
+
async function withCommandCodeProjectMcpEntry(cwd, url3, run) {
|
|
46496
|
+
const path2 = (0, import_path8.join)(cwd, ".mcp.json");
|
|
46506
46497
|
const original = await (0, import_promises3.readFile)(path2, "utf8").catch(() => null);
|
|
46507
46498
|
const config4 = parseConfig(original);
|
|
46508
|
-
const servers = config4.mcpServers
|
|
46509
|
-
config4.mcpServers = servers;
|
|
46499
|
+
const servers = asRecord2(config4.mcpServers);
|
|
46510
46500
|
servers.alan = {
|
|
46511
|
-
|
|
46501
|
+
transport: "http",
|
|
46502
|
+
enabled: true,
|
|
46512
46503
|
url: url3,
|
|
46513
46504
|
headers: {
|
|
46514
|
-
Authorization: `\${
|
|
46515
|
-
"x-alan-run-id": `\${
|
|
46505
|
+
Authorization: `\${${ALAN_MCP_AUTHORIZATION_ENV}}`,
|
|
46506
|
+
"x-alan-run-id": `\${${ALAN_RUN_ID_ENV}}`
|
|
46516
46507
|
}
|
|
46517
46508
|
};
|
|
46509
|
+
config4.mcpServers = servers;
|
|
46518
46510
|
await (0, import_promises3.mkdir)((0, import_path8.dirname)(path2), { recursive: true });
|
|
46519
46511
|
await (0, import_promises3.writeFile)(path2, `${JSON.stringify(config4, null, 2)}
|
|
46520
46512
|
`);
|
|
@@ -46526,6 +46518,42 @@ async function withCursorProjectMcpEntry(cwd, url3, run) {
|
|
|
46526
46518
|
}
|
|
46527
46519
|
}
|
|
46528
46520
|
function parseConfig(raw) {
|
|
46521
|
+
if (!raw) return {};
|
|
46522
|
+
try {
|
|
46523
|
+
const parsed = JSON.parse(raw);
|
|
46524
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
46525
|
+
} catch {
|
|
46526
|
+
return {};
|
|
46527
|
+
}
|
|
46528
|
+
}
|
|
46529
|
+
function asRecord2(value2) {
|
|
46530
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : {};
|
|
46531
|
+
}
|
|
46532
|
+
async function withCursorProjectMcpEntry(cwd, url3, run) {
|
|
46533
|
+
const path2 = (0, import_path9.join)(cwd, ".cursor", "mcp.json");
|
|
46534
|
+
const original = await (0, import_promises4.readFile)(path2, "utf8").catch(() => null);
|
|
46535
|
+
const config4 = parseConfig2(original);
|
|
46536
|
+
const servers = config4.mcpServers ?? {};
|
|
46537
|
+
config4.mcpServers = servers;
|
|
46538
|
+
servers.alan = {
|
|
46539
|
+
type: "http",
|
|
46540
|
+
url: url3,
|
|
46541
|
+
headers: {
|
|
46542
|
+
Authorization: `\${env:${ALAN_MCP_AUTHORIZATION_ENV}}`,
|
|
46543
|
+
"x-alan-run-id": `\${env:${ALAN_RUN_ID_ENV}}`
|
|
46544
|
+
}
|
|
46545
|
+
};
|
|
46546
|
+
await (0, import_promises4.mkdir)((0, import_path9.dirname)(path2), { recursive: true });
|
|
46547
|
+
await (0, import_promises4.writeFile)(path2, `${JSON.stringify(config4, null, 2)}
|
|
46548
|
+
`);
|
|
46549
|
+
try {
|
|
46550
|
+
return await run();
|
|
46551
|
+
} finally {
|
|
46552
|
+
if (original === null) await (0, import_promises4.rm)(path2, { force: true });
|
|
46553
|
+
else await (0, import_promises4.writeFile)(path2, original);
|
|
46554
|
+
}
|
|
46555
|
+
}
|
|
46556
|
+
function parseConfig2(raw) {
|
|
46529
46557
|
if (!raw) return {};
|
|
46530
46558
|
try {
|
|
46531
46559
|
const parsed = JSON.parse(raw);
|
|
@@ -47713,13 +47741,78 @@ async function createSession(baseUrl, context, signal) {
|
|
|
47713
47741
|
throw new Error(`${openCodeEngineLabel(context)} session create response had no id`);
|
|
47714
47742
|
return info.id;
|
|
47715
47743
|
}
|
|
47744
|
+
function storedPartOf(value2) {
|
|
47745
|
+
const record4 = asRecord(value2);
|
|
47746
|
+
const id = asString(record4?.id);
|
|
47747
|
+
const type = asString(record4?.type);
|
|
47748
|
+
return id && type ? { id, type, text: asString(record4?.text) } : null;
|
|
47749
|
+
}
|
|
47750
|
+
function storedMessageOf(value2) {
|
|
47751
|
+
const record4 = asRecord(value2);
|
|
47752
|
+
const info = asRecord(record4?.info);
|
|
47753
|
+
const id = asString(info?.id);
|
|
47754
|
+
if (!id || !Array.isArray(record4?.parts)) return null;
|
|
47755
|
+
const parts2 = record4.parts.flatMap((part) => storedPartOf(part) ?? []);
|
|
47756
|
+
return { id, role: asString(info?.role), parts: parts2 };
|
|
47757
|
+
}
|
|
47758
|
+
var TEXT_PART_TYPES = /* @__PURE__ */ new Set(["text", "reasoning"]);
|
|
47759
|
+
var STEP_PART_TYPES = /* @__PURE__ */ new Set(["step-start", "step-finish"]);
|
|
47760
|
+
function isBlankTextPart(part) {
|
|
47761
|
+
return TEXT_PART_TYPES.has(part.type) && !part.text.trim();
|
|
47762
|
+
}
|
|
47763
|
+
async function removeBlankAssistantContent(baseUrl, sessionId, signal) {
|
|
47764
|
+
const sessionUrl = `${baseUrl}/session/${encodeURIComponent(sessionId)}`;
|
|
47765
|
+
const response = await fetch(`${sessionUrl}/message`, { signal }).catch(() => null);
|
|
47766
|
+
if (!response?.ok) return 0;
|
|
47767
|
+
const body = await response.json().catch(() => null);
|
|
47768
|
+
if (!Array.isArray(body)) return 0;
|
|
47769
|
+
const deletions = [];
|
|
47770
|
+
for (const message of body.flatMap((entry) => storedMessageOf(entry) ?? [])) {
|
|
47771
|
+
if (message.role !== "assistant") continue;
|
|
47772
|
+
const messageUrl = `${sessionUrl}/message/${encodeURIComponent(message.id)}`;
|
|
47773
|
+
const holdsNothing = message.parts.every(
|
|
47774
|
+
(part) => isBlankTextPart(part) || STEP_PART_TYPES.has(part.type)
|
|
47775
|
+
);
|
|
47776
|
+
if (holdsNothing) {
|
|
47777
|
+
deletions.push(messageUrl);
|
|
47778
|
+
continue;
|
|
47779
|
+
}
|
|
47780
|
+
for (const part of message.parts.filter(isBlankTextPart)) {
|
|
47781
|
+
deletions.push(`${messageUrl}/part/${encodeURIComponent(part.id)}`);
|
|
47782
|
+
}
|
|
47783
|
+
}
|
|
47784
|
+
let removed = 0;
|
|
47785
|
+
for (const url3 of deletions) {
|
|
47786
|
+
const deleted = await fetch(url3, { method: "DELETE", signal }).catch(() => null);
|
|
47787
|
+
if (deleted?.ok) removed += 1;
|
|
47788
|
+
}
|
|
47789
|
+
return removed;
|
|
47790
|
+
}
|
|
47791
|
+
var SESSION_ABORT_TIMEOUT_MS = 1500;
|
|
47792
|
+
async function requestSessionAbort(baseUrl, sessionId) {
|
|
47793
|
+
if (!baseUrl || !sessionId) return;
|
|
47794
|
+
await fetch(`${baseUrl}/session/${encodeURIComponent(sessionId)}/abort`, {
|
|
47795
|
+
method: "POST",
|
|
47796
|
+
signal: AbortSignal.timeout(SESSION_ABORT_TIMEOUT_MS)
|
|
47797
|
+
}).catch(() => void 0);
|
|
47798
|
+
}
|
|
47716
47799
|
async function resolveSession(baseUrl, context, signal) {
|
|
47717
47800
|
const resumeId3 = context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim();
|
|
47718
47801
|
if (!resumeId3) {
|
|
47719
47802
|
return { id: await createSession(baseUrl, context, signal), resumed: false };
|
|
47720
47803
|
}
|
|
47721
47804
|
const existing = await fetch(`${baseUrl}/session/${encodeURIComponent(resumeId3)}`, { signal });
|
|
47722
|
-
if (existing.ok)
|
|
47805
|
+
if (existing.ok) {
|
|
47806
|
+
const removed = await removeBlankAssistantContent(baseUrl, resumeId3, signal);
|
|
47807
|
+
if (removed > 0) {
|
|
47808
|
+
logResumeObservability("agent_resume_history_repaired", {
|
|
47809
|
+
backendKind: context.config.backendKind ?? "opencode_serve",
|
|
47810
|
+
requestedResumeId: resumeId3,
|
|
47811
|
+
removedBlankEntries: removed
|
|
47812
|
+
});
|
|
47813
|
+
}
|
|
47814
|
+
return { id: resumeId3, resumed: true };
|
|
47815
|
+
}
|
|
47723
47816
|
if (existing.status !== 404) {
|
|
47724
47817
|
throw new Error(
|
|
47725
47818
|
`Failed to look up ${openCodeEngineLabel(context)} session ${resumeId3}: HTTP ${existing.status}`
|
|
@@ -47932,8 +48025,8 @@ function buildAgentResult(state, sessionId, aborted2, backendKind = "opencode_se
|
|
|
47932
48025
|
usage: state.usage
|
|
47933
48026
|
};
|
|
47934
48027
|
}
|
|
48028
|
+
const producedOutput = Boolean(state.summary.trim()) || [...state.opencodePartTypeById?.values() ?? []].some((type) => OUTPUT_PART_TYPES.has(type));
|
|
47935
48029
|
if (!state.error?.trim()) {
|
|
47936
|
-
const producedOutput = Boolean(state.summary.trim()) || [...state.opencodePartTypeById?.values() ?? []].some((type) => OUTPUT_PART_TYPES.has(type));
|
|
47937
48030
|
if (state.opencodeFinishReason === "length") {
|
|
47938
48031
|
state.error = "The model's response was cut off because it hit the output token limit.";
|
|
47939
48032
|
state.errorKind = "context_length";
|
|
@@ -47973,7 +48066,8 @@ function buildAgentResult(state, sessionId, aborted2, backendKind = "opencode_se
|
|
|
47973
48066
|
// Failures arrive via the SSE stream, never a CLI exit.
|
|
47974
48067
|
phase: "stream",
|
|
47975
48068
|
finality: "terminal",
|
|
47976
|
-
|
|
48069
|
+
// A rejected history fails the first request, so with no output nothing ran.
|
|
48070
|
+
outcomeCertainty: errorKind === "history_rejected" && !producedOutput ? "no_effect" : "effect_unknown"
|
|
47977
48071
|
}
|
|
47978
48072
|
);
|
|
47979
48073
|
}
|
|
@@ -48045,17 +48139,19 @@ function createOpencodeServeBackend(command = "opencode", options = PLAIN_OPENCO
|
|
|
48045
48139
|
}));
|
|
48046
48140
|
let sseClose = null;
|
|
48047
48141
|
let sessionId = "";
|
|
48142
|
+
let serverBaseUrl = null;
|
|
48048
48143
|
let aborted2 = false;
|
|
48049
48144
|
const onAbort = () => {
|
|
48050
48145
|
aborted2 = true;
|
|
48051
48146
|
sseClose?.();
|
|
48052
48147
|
if (leaseKey) serveLeases.delete(leaseKey);
|
|
48053
|
-
void terminateProcessTree(child);
|
|
48148
|
+
void requestSessionAbort(serverBaseUrl, sessionId).then(() => terminateProcessTree(child));
|
|
48054
48149
|
};
|
|
48055
48150
|
context.abortController.signal.addEventListener("abort", onAbort, { once: true });
|
|
48056
48151
|
if (context.abortController.signal.aborted) onAbort();
|
|
48057
48152
|
try {
|
|
48058
48153
|
const server = await ready;
|
|
48154
|
+
serverBaseUrl = server.baseUrl;
|
|
48059
48155
|
state.lastRawOutputAtMs = Date.now();
|
|
48060
48156
|
context.registerBackgroundTaskStopper?.(
|
|
48061
48157
|
(taskId) => stopBackgroundTaskInRun(
|
|
@@ -48184,6 +48280,7 @@ var ALAN_CODE_ENGINE_PROVIDER_ID = "alan";
|
|
|
48184
48280
|
var ALAN_CODE_API_KEY_ENV = "ALAN_CODE_API_KEY";
|
|
48185
48281
|
var ALAN_CODE_RUN_ID_ENV = "ALAN_CODE_RUN_ID";
|
|
48186
48282
|
var ALAN_CODE_PROXY_PATH = "/public/harness/v1";
|
|
48283
|
+
var ALAN_CODE_WEBSEARCH_PATH = "/public/harness/v1/websearch";
|
|
48187
48284
|
var ALAN_CODE_CATALOG_PATH = "/public/harness/models";
|
|
48188
48285
|
var CATALOG_TIMEOUT_MS = 5e3;
|
|
48189
48286
|
function seedAlanCodeModels() {
|
|
@@ -48243,21 +48340,133 @@ function resolveAlanCodeModelId(selectedModel2, models) {
|
|
|
48243
48340
|
if (requested && models.some((model2) => model2.id === requested)) return requested;
|
|
48244
48341
|
return models.find((model2) => model2.isDefault)?.id ?? models[0]?.id ?? (requested || DEFAULT_HARNESS_MODEL_ID);
|
|
48245
48342
|
}
|
|
48246
|
-
|
|
48247
|
-
|
|
48343
|
+
function enginePluginSource(apiOrigin) {
|
|
48344
|
+
return `
|
|
48345
|
+
const WEB_SEARCH_URL = ${JSON.stringify(`${apiOrigin}${ALAN_CODE_WEBSEARCH_PATH}`)};
|
|
48346
|
+
const API_KEY_ENV = ${JSON.stringify(ALAN_CODE_API_KEY_ENV)};
|
|
48347
|
+
const RUN_ID_ENV = ${JSON.stringify(ALAN_CODE_RUN_ID_ENV)};
|
|
48348
|
+
const PROVIDER_ID = ${JSON.stringify(ALAN_CODE_ENGINE_PROVIDER_ID)};
|
|
48349
|
+
const INCLUDED_RESULTS = 8;
|
|
48350
|
+
const MAX_AUTO_RETRIES = 2;
|
|
48351
|
+
const MAX_AUTO_RETRY_WAIT_MS = 10_000;
|
|
48352
|
+
|
|
48353
|
+
function truncate(text, max) {
|
|
48354
|
+
const trimmed = String(text == null ? "" : text).trim();
|
|
48355
|
+
return trimmed.length <= max ? trimmed : trimmed.slice(0, max - 1) + "\u2026";
|
|
48356
|
+
}
|
|
48357
|
+
|
|
48358
|
+
function formatResults(results) {
|
|
48359
|
+
const lines = [];
|
|
48360
|
+
results.slice(0, INCLUDED_RESULTS).forEach(function (item, index) {
|
|
48361
|
+
const title = (item.title || "").trim() || (item.url || "").trim() || "Result " + (index + 1);
|
|
48362
|
+
lines.push(index + 1 + ". " + title);
|
|
48363
|
+
if (item.url) lines.push(" " + item.url);
|
|
48364
|
+
const excerpt = Array.isArray(item.excerpts)
|
|
48365
|
+
? item.excerpts.find(function (part) { return part && part.trim(); })
|
|
48366
|
+
: "";
|
|
48367
|
+
if (excerpt) lines.push(" " + truncate(excerpt, 400));
|
|
48368
|
+
});
|
|
48369
|
+
return lines.join("\\n");
|
|
48370
|
+
}
|
|
48371
|
+
|
|
48372
|
+
/** Mirrors the harness CLI: say what the agent can do next instead of just failing. */
|
|
48373
|
+
function describeRefusal(refusal, status, text) {
|
|
48374
|
+
const code = refusal && typeof refusal.error === "string" ? refusal.error : "";
|
|
48375
|
+
const message = refusal && typeof refusal.message === "string" ? refusal.message : truncate(text, 300);
|
|
48376
|
+
const reset = refusal && typeof refusal.resetsAt === "string" ? refusal.resetsAt.slice(0, 10) : "";
|
|
48377
|
+
if (code === "quota_exceeded") {
|
|
48378
|
+
return "Web search allowance exhausted" + (reset ? "; it resets " + reset : "") + ". Do not retry \u2014 continue without search or tell the user.";
|
|
48379
|
+
}
|
|
48380
|
+
if (code === "search_daily_limit") {
|
|
48381
|
+
return "Daily web search limit reached; it resets at 00:00 UTC. Continue without search rather than retrying.";
|
|
48382
|
+
}
|
|
48383
|
+
if (code === "billing_review_required" || code === "not_a_member" || code === "seat_required" || code.indexOf("entitlement") === 0) {
|
|
48384
|
+
return "Web search is not available for this account (" + message + "). Do not retry \u2014 report it to the user.";
|
|
48385
|
+
}
|
|
48386
|
+
if (refusal && refusal.retryable === true) {
|
|
48387
|
+
return "Web search is temporarily unavailable (" + message + "). Retry shortly.";
|
|
48388
|
+
}
|
|
48389
|
+
return "Web search failed (" + status + "): " + message;
|
|
48390
|
+
}
|
|
48391
|
+
|
|
48392
|
+
async function callWebSearch(query, signal) {
|
|
48393
|
+
const apiKey = process.env[API_KEY_ENV];
|
|
48394
|
+
if (!apiKey) {
|
|
48395
|
+
return { title: "web_search unavailable", output: "Web search is unavailable: this run has no Alan credential." };
|
|
48396
|
+
}
|
|
48397
|
+
const headers = { Authorization: "Bearer " + apiKey, "Content-Type": "application/json" };
|
|
48398
|
+
if (process.env[RUN_ID_ENV]) headers["x-alan-run-id"] = process.env[RUN_ID_ENV];
|
|
48399
|
+
|
|
48400
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
48401
|
+
const response = await fetch(WEB_SEARCH_URL, {
|
|
48402
|
+
method: "POST",
|
|
48403
|
+
headers: headers,
|
|
48404
|
+
body: JSON.stringify({ query: query }),
|
|
48405
|
+
signal: signal,
|
|
48406
|
+
});
|
|
48407
|
+
const text = await response.text();
|
|
48408
|
+
if (response.ok) {
|
|
48409
|
+
let parsed;
|
|
48410
|
+
try {
|
|
48411
|
+
parsed = JSON.parse(text);
|
|
48412
|
+
} catch {
|
|
48413
|
+
return { title: "web_search", output: "Web search returned an unreadable response." };
|
|
48414
|
+
}
|
|
48415
|
+
const results = Array.isArray(parsed.results) ? parsed.results : [];
|
|
48416
|
+
if (results.length === 0) {
|
|
48417
|
+
return { title: "web_search: " + query, output: 'No results for "' + query + '". Try a tighter query, then webfetch promising URLs.' };
|
|
48418
|
+
}
|
|
48419
|
+
return {
|
|
48420
|
+
title: "web_search: " + query,
|
|
48421
|
+
output: [
|
|
48422
|
+
'Web search (Alan) for "' + query + '":',
|
|
48423
|
+
formatResults(results),
|
|
48424
|
+
"",
|
|
48425
|
+
"Next: pick the best URL(s) and call webfetch to read the page. Cite title + URL.",
|
|
48426
|
+
].join("\\n"),
|
|
48427
|
+
metadata: { resultCount: results.length, searchId: parsed.search_id },
|
|
48428
|
+
};
|
|
48429
|
+
}
|
|
48430
|
+
|
|
48431
|
+
let refusal;
|
|
48432
|
+
try { refusal = JSON.parse(text); } catch { refusal = undefined; }
|
|
48433
|
+
const waitMs = refusal && typeof refusal.retryAfterSeconds === "number" ? refusal.retryAfterSeconds * 1000 : 0;
|
|
48434
|
+
if (refusal && refusal.retryable === true && waitMs > 0 && waitMs <= MAX_AUTO_RETRY_WAIT_MS && attempt < MAX_AUTO_RETRIES) {
|
|
48435
|
+
await new Promise(function (resolve) { setTimeout(resolve, waitMs); });
|
|
48436
|
+
continue;
|
|
48437
|
+
}
|
|
48438
|
+
return { title: "web_search " + response.status, output: describeRefusal(refusal, response.status, text) };
|
|
48439
|
+
}
|
|
48440
|
+
}
|
|
48441
|
+
|
|
48442
|
+
export const AlanEnginePlugin = async () => ({
|
|
48248
48443
|
"chat.headers": async (input, output) => {
|
|
48249
|
-
if (input.model.providerID ===
|
|
48444
|
+
if (input.model.providerID === PROVIDER_ID) {
|
|
48250
48445
|
output.headers["x-alan-operation-key"] = Date.now() + "-" + crypto.randomUUID()
|
|
48251
48446
|
}
|
|
48252
48447
|
},
|
|
48448
|
+
tool: {
|
|
48449
|
+
web_search: {
|
|
48450
|
+
description: "web_search: Search the public web via Alan's Parallel proxy. Use when you do not already have a URL. Follow up with webfetch on the best result(s).",
|
|
48451
|
+
args: {
|
|
48452
|
+
query: { type: "string", description: "Search query / objective" },
|
|
48453
|
+
},
|
|
48454
|
+
async execute(args, context) {
|
|
48455
|
+
const query = String((args && args.query) || "").trim();
|
|
48456
|
+
if (!query) return { title: "web_search", output: "web_search requires a non-empty query." };
|
|
48457
|
+
return callWebSearch(query, context && context.abort);
|
|
48458
|
+
},
|
|
48459
|
+
},
|
|
48460
|
+
},
|
|
48253
48461
|
})
|
|
48254
48462
|
`;
|
|
48255
|
-
|
|
48256
|
-
|
|
48257
|
-
const
|
|
48463
|
+
}
|
|
48464
|
+
function materializeEnginePlugin(directory = (0, import_os4.tmpdir)(), apiOrigin) {
|
|
48465
|
+
const dir = (0, import_path10.join)(directory, "alan-code");
|
|
48466
|
+
const target = (0, import_path10.join)(dir, "engine-plugin-v1.mjs");
|
|
48258
48467
|
const temporary = `${target}.${process.pid}.${(0, import_crypto5.randomUUID)()}.tmp`;
|
|
48259
48468
|
(0, import_fs9.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
48260
|
-
(0, import_fs9.writeFileSync)(temporary,
|
|
48469
|
+
(0, import_fs9.writeFileSync)(temporary, enginePluginSource(apiOrigin), { mode: 384 });
|
|
48261
48470
|
(0, import_fs9.renameSync)(temporary, target);
|
|
48262
48471
|
return (0, import_url2.pathToFileURL)(target).href;
|
|
48263
48472
|
}
|
|
@@ -48321,15 +48530,15 @@ function buildAlanCodeConfigContent(existing, input2) {
|
|
|
48321
48530
|
}
|
|
48322
48531
|
function alanCodeEngineDirectories(root) {
|
|
48323
48532
|
const directories = {
|
|
48324
|
-
XDG_DATA_HOME: (0,
|
|
48325
|
-
XDG_STATE_HOME: (0,
|
|
48326
|
-
XDG_CACHE_HOME: (0,
|
|
48533
|
+
XDG_DATA_HOME: (0, import_path10.join)(root, "share"),
|
|
48534
|
+
XDG_STATE_HOME: (0, import_path10.join)(root, "state"),
|
|
48535
|
+
XDG_CACHE_HOME: (0, import_path10.join)(root, "cache")
|
|
48327
48536
|
};
|
|
48328
48537
|
for (const directory of Object.values(directories)) (0, import_fs9.mkdirSync)(directory, { recursive: true });
|
|
48329
48538
|
return directories;
|
|
48330
48539
|
}
|
|
48331
48540
|
function defaultEngineRoot(env) {
|
|
48332
|
-
return (0,
|
|
48541
|
+
return (0, import_path10.join)(env.HOME?.trim() || (0, import_os4.homedir)(), ".alan", "alan-code", "engine");
|
|
48333
48542
|
}
|
|
48334
48543
|
async function withAlanCodeEngine(context, dependencies = {}) {
|
|
48335
48544
|
const registration = context.config.alanMcp;
|
|
@@ -48356,7 +48565,7 @@ async function withAlanCodeEngine(context, dependencies = {}) {
|
|
|
48356
48565
|
baseURL: `${apiOrigin}${ALAN_CODE_PROXY_PATH}`,
|
|
48357
48566
|
modelId,
|
|
48358
48567
|
models,
|
|
48359
|
-
pluginUrl:
|
|
48568
|
+
pluginUrl: materializeEnginePlugin(dependencies.pluginDirectory, apiOrigin)
|
|
48360
48569
|
})
|
|
48361
48570
|
}
|
|
48362
48571
|
};
|
|
@@ -49170,7 +49379,7 @@ var TranscriptTail = class {
|
|
|
49170
49379
|
const wanted = /* @__PURE__ */ new Set();
|
|
49171
49380
|
for (const path2 of this.options.transcriptPaths()) {
|
|
49172
49381
|
if (!path2) continue;
|
|
49173
|
-
wanted.add(this.armFile(path2) ? path2 : (0,
|
|
49382
|
+
wanted.add(this.armFile(path2) ? path2 : (0, import_path12.dirname)(path2));
|
|
49174
49383
|
}
|
|
49175
49384
|
for (const target of wanted) this.arm(target, false);
|
|
49176
49385
|
for (const target of this.watchers.keys()) {
|
|
@@ -49223,10 +49432,10 @@ var ANTIGRAVITY_TOOL_RESULT_TYPES = /* @__PURE__ */ new Set([
|
|
|
49223
49432
|
]);
|
|
49224
49433
|
function antigravityTranscriptRoot(context) {
|
|
49225
49434
|
const home = context.env.HOME || process.env.HOME || (0, import_os5.homedir)();
|
|
49226
|
-
return (0,
|
|
49435
|
+
return (0, import_path11.resolve)(home, ".gemini", "antigravity-cli", "brain");
|
|
49227
49436
|
}
|
|
49228
49437
|
function parentTranscriptPath(conversationId, context) {
|
|
49229
|
-
return (0,
|
|
49438
|
+
return (0, import_path11.resolve)(
|
|
49230
49439
|
antigravityTranscriptRoot(context),
|
|
49231
49440
|
conversationId,
|
|
49232
49441
|
".system_generated",
|
|
@@ -49241,10 +49450,10 @@ function childTranscriptPath(event, context) {
|
|
|
49241
49450
|
try {
|
|
49242
49451
|
const url3 = new URL(logUri);
|
|
49243
49452
|
if (url3.protocol !== "file:") return void 0;
|
|
49244
|
-
const transcriptPath2 = (0,
|
|
49245
|
-
const pathFromRoot = (0,
|
|
49246
|
-
const segments = pathFromRoot.split(
|
|
49247
|
-
if (!pathFromRoot || pathFromRoot === ".." || pathFromRoot.startsWith(`..${
|
|
49453
|
+
const transcriptPath2 = (0, import_path11.resolve)((0, import_url3.fileURLToPath)(url3));
|
|
49454
|
+
const pathFromRoot = (0, import_path11.relative)(antigravityTranscriptRoot(context), transcriptPath2);
|
|
49455
|
+
const segments = pathFromRoot.split(import_path11.sep);
|
|
49456
|
+
if (!pathFromRoot || pathFromRoot === ".." || pathFromRoot.startsWith(`..${import_path11.sep}`) || (0, import_path11.isAbsolute)(pathFromRoot) || segments[0] !== conversationId || segments.at(-1) !== "transcript.jsonl" || segments.at(-2) !== "logs" || segments.at(-3) !== ".system_generated") {
|
|
49248
49457
|
return void 0;
|
|
49249
49458
|
}
|
|
49250
49459
|
return transcriptPath2;
|
|
@@ -49260,7 +49469,7 @@ function parseTranscriptEntry(text2) {
|
|
|
49260
49469
|
}
|
|
49261
49470
|
}
|
|
49262
49471
|
function fullTranscriptPath(transcriptPath2) {
|
|
49263
|
-
return (0,
|
|
49472
|
+
return (0, import_path11.resolve)((0, import_path11.dirname)(transcriptPath2), FULL_TRANSCRIPT_FILENAME);
|
|
49264
49473
|
}
|
|
49265
49474
|
function resolveTruncatedEntry(entry, lineIndex, transcriptPath2, full) {
|
|
49266
49475
|
const truncated = Array.isArray(entry.truncated_fields) ? entry.truncated_fields : [];
|
|
@@ -51244,18 +51453,18 @@ function recoverCodexFileChange(state, item) {
|
|
|
51244
51453
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
51245
51454
|
var MAX_HEADER_BYTES = 1024 * 1024;
|
|
51246
51455
|
function workerDirectories(rootLog) {
|
|
51247
|
-
const directory = (0,
|
|
51248
|
-
const monthDirectory = (0,
|
|
51249
|
-
const yearDirectory = (0,
|
|
51250
|
-
const date5 = `${(0,
|
|
51456
|
+
const directory = (0, import_path14.dirname)(rootLog);
|
|
51457
|
+
const monthDirectory = (0, import_path14.dirname)(directory);
|
|
51458
|
+
const yearDirectory = (0, import_path14.dirname)(monthDirectory);
|
|
51459
|
+
const date5 = `${(0, import_path14.basename)(yearDirectory)}-${(0, import_path14.basename)(monthDirectory)}-${(0, import_path14.basename)(directory)}`;
|
|
51251
51460
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date5)) return [directory];
|
|
51252
51461
|
const timestamp = Date.parse(`${date5}T00:00:00Z`);
|
|
51253
51462
|
if (!Number.isFinite(timestamp) || new Date(timestamp).toISOString().slice(0, 10) !== date5)
|
|
51254
51463
|
return [directory];
|
|
51255
|
-
const sessionsDirectory2 = (0,
|
|
51464
|
+
const sessionsDirectory2 = (0, import_path14.dirname)(yearDirectory);
|
|
51256
51465
|
return [0, 1, -1].map((offset2) => {
|
|
51257
51466
|
const day = new Date(timestamp + offset2 * DAY_MS).toISOString().slice(0, 10);
|
|
51258
|
-
return (0,
|
|
51467
|
+
return (0, import_path14.join)(sessionsDirectory2, ...day.split("-"));
|
|
51259
51468
|
});
|
|
51260
51469
|
}
|
|
51261
51470
|
function firstLine(path2) {
|
|
@@ -51292,7 +51501,7 @@ function findCodexWorkerLogs(rootLog, parentThreadId) {
|
|
|
51292
51501
|
}
|
|
51293
51502
|
for (const entry of entries) {
|
|
51294
51503
|
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
51295
|
-
const path2 = (0,
|
|
51504
|
+
const path2 = (0, import_path14.join)(directory, entry.name);
|
|
51296
51505
|
if (path2 === rootLog) continue;
|
|
51297
51506
|
try {
|
|
51298
51507
|
const line = firstLine(path2);
|
|
@@ -51320,7 +51529,7 @@ function findCodexWorkerLogs(rootLog, parentThreadId) {
|
|
|
51320
51529
|
return workers;
|
|
51321
51530
|
}
|
|
51322
51531
|
function resolveCodexHome(env) {
|
|
51323
|
-
return env.CODEX_HOME || process.env.CODEX_HOME || (0,
|
|
51532
|
+
return env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path13.join)((0, import_os6.homedir)(), ".codex");
|
|
51324
51533
|
}
|
|
51325
51534
|
function mtimeOf(path2) {
|
|
51326
51535
|
try {
|
|
@@ -51334,11 +51543,11 @@ function newestMatchIn(dir, entries, sessionId) {
|
|
|
51334
51543
|
(entry) => entry.isFile() && entry.name.endsWith(".jsonl") && entry.name.includes(sessionId)
|
|
51335
51544
|
);
|
|
51336
51545
|
if (matches.length === 0) return null;
|
|
51337
|
-
if (matches.length === 1) return (0,
|
|
51546
|
+
if (matches.length === 1) return (0, import_path13.join)(dir, matches[0].name);
|
|
51338
51547
|
let best = "";
|
|
51339
51548
|
let bestMtime = -1;
|
|
51340
51549
|
for (const entry of matches) {
|
|
51341
|
-
const path2 = (0,
|
|
51550
|
+
const path2 = (0, import_path13.join)(dir, entry.name);
|
|
51342
51551
|
const mtime = mtimeOf(path2);
|
|
51343
51552
|
if (mtime > bestMtime) {
|
|
51344
51553
|
best = path2;
|
|
@@ -51349,7 +51558,7 @@ function newestMatchIn(dir, entries, sessionId) {
|
|
|
51349
51558
|
}
|
|
51350
51559
|
function findCodexSessionLog(runtimeSessionId, codexHome) {
|
|
51351
51560
|
if (!runtimeSessionId) return null;
|
|
51352
|
-
const stack = [(0,
|
|
51561
|
+
const stack = [(0, import_path13.join)(codexHome, "sessions")];
|
|
51353
51562
|
while (stack.length > 0) {
|
|
51354
51563
|
const dir = stack.pop();
|
|
51355
51564
|
let entries;
|
|
@@ -51362,7 +51571,7 @@ function findCodexSessionLog(runtimeSessionId, codexHome) {
|
|
|
51362
51571
|
if (match) return match;
|
|
51363
51572
|
const subdirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
51364
51573
|
subdirs.sort();
|
|
51365
|
-
for (const name of subdirs) stack.push((0,
|
|
51574
|
+
for (const name of subdirs) stack.push((0, import_path13.join)(dir, name));
|
|
51366
51575
|
}
|
|
51367
51576
|
return null;
|
|
51368
51577
|
}
|
|
@@ -53028,6 +53237,7 @@ var COMMAND_CODE_GRAMMAR_NAME = "command_code_cli";
|
|
|
53028
53237
|
var TEXT_MESSAGE_KEY = "commandCode.textMessageId";
|
|
53029
53238
|
var THINKING_MESSAGE_KEY = "commandCode.thinkingMessageId";
|
|
53030
53239
|
var ANONYMOUS_TOOL_KEY2 = "commandCode.lastAnonymousToolCallId";
|
|
53240
|
+
var ANSWER_MESSAGE_KEY = "commandCode.answerMessageId";
|
|
53031
53241
|
function commandCodeString(value2) {
|
|
53032
53242
|
return typeof value2 === "string" && value2.trim().length > 0 ? value2.trim() : "";
|
|
53033
53243
|
}
|
|
@@ -53116,10 +53326,12 @@ function parseEvent2(event, state) {
|
|
|
53116
53326
|
case "text_delta": {
|
|
53117
53327
|
const delta = typeof event.delta === "string" ? event.delta : "";
|
|
53118
53328
|
if (!delta) return [];
|
|
53329
|
+
const messageId = latchedMessageId(state, TEXT_MESSAGE_KEY, "command-code-msg");
|
|
53330
|
+
state.scratch[ANSWER_MESSAGE_KEY] = messageId;
|
|
53119
53331
|
return [
|
|
53120
53332
|
{
|
|
53121
53333
|
sessionUpdate: "agent_message_chunk",
|
|
53122
|
-
messageId
|
|
53334
|
+
messageId,
|
|
53123
53335
|
content: textBlock(delta)
|
|
53124
53336
|
}
|
|
53125
53337
|
];
|
|
@@ -53127,6 +53339,7 @@ function parseEvent2(event, state) {
|
|
|
53127
53339
|
case "message_update":
|
|
53128
53340
|
return parseMessageUpdate(event, state);
|
|
53129
53341
|
case "tool_running":
|
|
53342
|
+
delete state.scratch[ANSWER_MESSAGE_KEY];
|
|
53130
53343
|
return [
|
|
53131
53344
|
toolCallStart(
|
|
53132
53345
|
resolveToolCallId(commandCodeString(event.toolCallId), state),
|
|
@@ -53209,13 +53422,22 @@ function parseResult2(event, state) {
|
|
|
53209
53422
|
const sessionId = commandCodeString(event.sessionId);
|
|
53210
53423
|
if (sessionId) state.sessionId = sessionId;
|
|
53211
53424
|
const subtype = commandCodeString(event.subtype);
|
|
53212
|
-
|
|
53213
|
-
|
|
53214
|
-
|
|
53215
|
-
|
|
53216
|
-
|
|
53217
|
-
|
|
53218
|
-
|
|
53425
|
+
const updates = [];
|
|
53426
|
+
const finalText = commandCodeString(event.finalText);
|
|
53427
|
+
const answerId = state.scratch[ANSWER_MESSAGE_KEY];
|
|
53428
|
+
if (finalText && typeof answerId === "string" && answerId) {
|
|
53429
|
+
updates.push({
|
|
53430
|
+
sessionUpdate: "agent_message",
|
|
53431
|
+
messageId: answerId,
|
|
53432
|
+
content: [textBlock(finalText)]
|
|
53433
|
+
});
|
|
53434
|
+
}
|
|
53435
|
+
updates.push({
|
|
53436
|
+
sessionUpdate: "state_update",
|
|
53437
|
+
state: "idle",
|
|
53438
|
+
...subtype === "error" ? {} : { stopReason: "end_turn" }
|
|
53439
|
+
});
|
|
53440
|
+
return updates;
|
|
53219
53441
|
}
|
|
53220
53442
|
var backgroundStates = /* @__PURE__ */ new WeakMap();
|
|
53221
53443
|
function backgroundStateFor(state) {
|
|
@@ -53483,39 +53705,49 @@ function createCommandCodeCliBackend(command = "command-code", defaultArgs = [])
|
|
|
53483
53705
|
context.config.images,
|
|
53484
53706
|
context.cwd
|
|
53485
53707
|
);
|
|
53708
|
+
const managed = context.config.alanMcp;
|
|
53709
|
+
const runContext = managed ? {
|
|
53710
|
+
...context,
|
|
53711
|
+
env: {
|
|
53712
|
+
...context.env,
|
|
53713
|
+
[ALAN_MCP_AUTHORIZATION_ENV]: requireManagedAuthorization(managed),
|
|
53714
|
+
[ALAN_RUN_ID_ENV]: requireManagedRunId(managed)
|
|
53715
|
+
}
|
|
53716
|
+
} : context;
|
|
53717
|
+
const runBackend = () => createCliBackend({
|
|
53718
|
+
kind: "command_code_cli",
|
|
53719
|
+
supportTier: "structured",
|
|
53720
|
+
command,
|
|
53721
|
+
args: [],
|
|
53722
|
+
buildArgs: (ctx, prompt) => {
|
|
53723
|
+
const args = [
|
|
53724
|
+
"-p",
|
|
53725
|
+
"--output-format",
|
|
53726
|
+
"json",
|
|
53727
|
+
"--skip-onboarding",
|
|
53728
|
+
"--trust",
|
|
53729
|
+
"--no-auto-update",
|
|
53730
|
+
...commandCodePermissionArgs(ctx.config),
|
|
53731
|
+
...defaultArgs
|
|
53732
|
+
];
|
|
53733
|
+
const resumeId3 = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
|
|
53734
|
+
if (resumeId3) args.push("--resume", resumeId3);
|
|
53735
|
+
const model2 = ctx.config.selectedModel?.trim();
|
|
53736
|
+
if (model2) args.push("--model", model2);
|
|
53737
|
+
const effort3 = ctx.config.selectedEffortLevel?.trim();
|
|
53738
|
+
if (effort3) args.push("--effort", effort3);
|
|
53739
|
+
args.push(prompt);
|
|
53740
|
+
return args;
|
|
53741
|
+
},
|
|
53742
|
+
augmentPrompt: (ctx) => buildPromptWithImagePathReferences(ctx, imageFiles),
|
|
53743
|
+
parseStructuredLine: grammarAsStructuredLineParser(
|
|
53744
|
+
commandCodeGrammar,
|
|
53745
|
+
commandCodeEffects
|
|
53746
|
+
),
|
|
53747
|
+
keepStdinOpen: true
|
|
53748
|
+
}).run(runContext);
|
|
53486
53749
|
try {
|
|
53487
|
-
return await
|
|
53488
|
-
kind: "command_code_cli",
|
|
53489
|
-
supportTier: "structured",
|
|
53490
|
-
command,
|
|
53491
|
-
args: [],
|
|
53492
|
-
buildArgs: (ctx, prompt) => {
|
|
53493
|
-
const args = [
|
|
53494
|
-
"-p",
|
|
53495
|
-
"--output-format",
|
|
53496
|
-
"json",
|
|
53497
|
-
"--skip-onboarding",
|
|
53498
|
-
"--trust",
|
|
53499
|
-
"--no-auto-update",
|
|
53500
|
-
...commandCodePermissionArgs(ctx.config),
|
|
53501
|
-
...defaultArgs
|
|
53502
|
-
];
|
|
53503
|
-
const resumeId3 = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
|
|
53504
|
-
if (resumeId3) args.push("--resume", resumeId3);
|
|
53505
|
-
const model2 = ctx.config.selectedModel?.trim();
|
|
53506
|
-
if (model2) args.push("--model", model2);
|
|
53507
|
-
const effort3 = ctx.config.selectedEffortLevel?.trim();
|
|
53508
|
-
if (effort3) args.push("--effort", effort3);
|
|
53509
|
-
args.push(prompt);
|
|
53510
|
-
return args;
|
|
53511
|
-
},
|
|
53512
|
-
augmentPrompt: (ctx) => buildPromptWithImagePathReferences(ctx, imageFiles),
|
|
53513
|
-
parseStructuredLine: grammarAsStructuredLineParser(
|
|
53514
|
-
commandCodeGrammar,
|
|
53515
|
-
commandCodeEffects
|
|
53516
|
-
),
|
|
53517
|
-
keepStdinOpen: true
|
|
53518
|
-
}).run(context);
|
|
53750
|
+
return await (managed ? withCommandCodeProjectMcpEntry(context.cwd, managed.url, runBackend) : runBackend());
|
|
53519
53751
|
} finally {
|
|
53520
53752
|
cleanup();
|
|
53521
53753
|
}
|
|
@@ -54001,7 +54233,27 @@ function activeTaskIdNamedIn(state, content) {
|
|
|
54001
54233
|
}
|
|
54002
54234
|
return void 0;
|
|
54003
54235
|
}
|
|
54004
|
-
function
|
|
54236
|
+
function writeCopilotMcpConfig(registration) {
|
|
54237
|
+
if (!registration) return null;
|
|
54238
|
+
const dir = (0, import_fs15.mkdtempSync)((0, import_path15.join)((0, import_os7.tmpdir)(), "alan-copilot-mcp-"));
|
|
54239
|
+
const path2 = (0, import_path15.join)(dir, "mcp-config.json");
|
|
54240
|
+
(0, import_fs15.writeFileSync)(
|
|
54241
|
+
path2,
|
|
54242
|
+
JSON.stringify({
|
|
54243
|
+
mcpServers: {
|
|
54244
|
+
[MANAGED_MCP_SERVER_NAME]: {
|
|
54245
|
+
type: "http",
|
|
54246
|
+
url: registration.url,
|
|
54247
|
+
tools: ["*"],
|
|
54248
|
+
headers: registration.headers
|
|
54249
|
+
}
|
|
54250
|
+
}
|
|
54251
|
+
}),
|
|
54252
|
+
{ mode: 384 }
|
|
54253
|
+
);
|
|
54254
|
+
return { path: path2, cleanup: () => (0, import_fs15.rmSync)(dir, { recursive: true, force: true }) };
|
|
54255
|
+
}
|
|
54256
|
+
function buildCopilotCliArgs(context, prompt, defaultArgs = [], options = {}) {
|
|
54005
54257
|
const args = [
|
|
54006
54258
|
"--yolo",
|
|
54007
54259
|
"-s",
|
|
@@ -54029,6 +54281,9 @@ function buildCopilotCliArgs(context, prompt, defaultArgs = []) {
|
|
|
54029
54281
|
args.push("--effort", effort3);
|
|
54030
54282
|
}
|
|
54031
54283
|
}
|
|
54284
|
+
if (options.additionalMcpConfigPath) {
|
|
54285
|
+
args.push("--additional-mcp-config", `@${options.additionalMcpConfigPath}`);
|
|
54286
|
+
}
|
|
54032
54287
|
args.push("-p", prompt);
|
|
54033
54288
|
return [...args, ...defaultArgs];
|
|
54034
54289
|
}
|
|
@@ -54041,19 +54296,23 @@ function createCopilotCliBackend(command = "copilot", defaultArgs = []) {
|
|
|
54041
54296
|
context.config.images,
|
|
54042
54297
|
context.cwd
|
|
54043
54298
|
);
|
|
54299
|
+
const mcpConfig = writeCopilotMcpConfig(context.config.alanMcp);
|
|
54044
54300
|
try {
|
|
54045
54301
|
return await createCliBackend({
|
|
54046
54302
|
kind: "copilot_cli",
|
|
54047
54303
|
supportTier: "structured",
|
|
54048
54304
|
command,
|
|
54049
54305
|
args: [],
|
|
54050
|
-
buildArgs: (ctx, prompt) => buildCopilotCliArgs(ctx, prompt, defaultArgs
|
|
54306
|
+
buildArgs: (ctx, prompt) => buildCopilotCliArgs(ctx, prompt, defaultArgs, {
|
|
54307
|
+
additionalMcpConfigPath: mcpConfig?.path
|
|
54308
|
+
}),
|
|
54051
54309
|
augmentPrompt: (ctx) => buildPromptWithImagePathReferences(ctx, imageFiles),
|
|
54052
54310
|
parseStructuredLine: grammarAsStructuredLineParser(copilotGrammar, copilotEffects),
|
|
54053
54311
|
// Held open so a deferred `result` can wait for background work to drain.
|
|
54054
54312
|
keepStdinOpen: true
|
|
54055
54313
|
}).run(context);
|
|
54056
54314
|
} finally {
|
|
54315
|
+
mcpConfig?.cleanup();
|
|
54057
54316
|
cleanup();
|
|
54058
54317
|
}
|
|
54059
54318
|
}
|
|
@@ -54600,11 +54859,11 @@ function cursorConversationStepText(steps) {
|
|
|
54600
54859
|
}
|
|
54601
54860
|
function cursorTranscriptsRoot(context) {
|
|
54602
54861
|
const projectKey = context.cwd.replace(/^[/\\]+/, "").replace(/[/\\]+/g, "-");
|
|
54603
|
-
const home = context.env.HOME || process.env.HOME || (0,
|
|
54604
|
-
return (0,
|
|
54862
|
+
const home = context.env.HOME || process.env.HOME || (0, import_os8.homedir)();
|
|
54863
|
+
return (0, import_path16.join)(home, ".cursor", "projects", projectKey, "agent-transcripts");
|
|
54605
54864
|
}
|
|
54606
54865
|
function cursorTranscriptPathForAgent(context, agentId) {
|
|
54607
|
-
return (0,
|
|
54866
|
+
return (0, import_path16.join)(cursorTranscriptsRoot(context), agentId, `${agentId}.jsonl`);
|
|
54608
54867
|
}
|
|
54609
54868
|
function resolveCursorSubagentTranscriptPath(success2, context) {
|
|
54610
54869
|
const explicit = success2?.transcriptPath ?? success2?.transcript_path;
|
|
@@ -54629,13 +54888,13 @@ function cursorTranscriptUserText(transcriptPath2) {
|
|
|
54629
54888
|
}
|
|
54630
54889
|
function discoverCursorSubagentTranscript(context, state, task) {
|
|
54631
54890
|
const root = cursorTranscriptsRoot(context);
|
|
54632
|
-
if (!(0,
|
|
54891
|
+
if (!(0, import_fs16.existsSync)(root)) return void 0;
|
|
54633
54892
|
const prompt = task.prompt?.trim();
|
|
54634
54893
|
const description = task.description?.trim().toLowerCase();
|
|
54635
54894
|
const candidates = [];
|
|
54636
54895
|
let entries;
|
|
54637
54896
|
try {
|
|
54638
|
-
entries = (0,
|
|
54897
|
+
entries = (0, import_fs16.readdirSync)(root, { withFileTypes: true });
|
|
54639
54898
|
} catch {
|
|
54640
54899
|
return void 0;
|
|
54641
54900
|
}
|
|
@@ -54644,7 +54903,7 @@ function discoverCursorSubagentTranscript(context, state, task) {
|
|
|
54644
54903
|
const path2 = cursorTranscriptPathForAgent(context, entry.name);
|
|
54645
54904
|
let mtimeMs;
|
|
54646
54905
|
try {
|
|
54647
|
-
mtimeMs = (0,
|
|
54906
|
+
mtimeMs = (0, import_fs16.statSync)(path2).mtimeMs;
|
|
54648
54907
|
} catch {
|
|
54649
54908
|
continue;
|
|
54650
54909
|
}
|
|
@@ -55072,10 +55331,6 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
|
|
|
55072
55331
|
closeStdinAfterPrompt: true,
|
|
55073
55332
|
// cursor-agent headless can hang at startup with zero output.
|
|
55074
55333
|
startupTimeoutMs: 18e4,
|
|
55075
|
-
// Its asks never fire the idle timer's conditions, so silence after output
|
|
55076
|
-
// is otherwise bounded only by the ~30-min external reaper.
|
|
55077
|
-
resultIdleTimeoutMs: 5 * 6e4,
|
|
55078
|
-
postStartupSilenceTimeoutMs: 15 * 6e4,
|
|
55079
55334
|
augmentPrompt: (ctx) => {
|
|
55080
55335
|
const isResume = Boolean(
|
|
55081
55336
|
ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim()
|
|
@@ -55893,6 +56148,17 @@ var GENERIC_GROK_RPC_ERRORS = /* @__PURE__ */ new Set([
|
|
|
55893
56148
|
"grok agent error",
|
|
55894
56149
|
"grok build run failed"
|
|
55895
56150
|
]);
|
|
56151
|
+
function buildGrokAcpMcpServers(registration) {
|
|
56152
|
+
if (!registration) return [];
|
|
56153
|
+
return [
|
|
56154
|
+
{
|
|
56155
|
+
name: MANAGED_MCP_SERVER_NAME,
|
|
56156
|
+
type: "http",
|
|
56157
|
+
url: registration.url,
|
|
56158
|
+
headers: Object.entries(registration.headers).map(([name, value2]) => ({ name, value: value2 }))
|
|
56159
|
+
}
|
|
56160
|
+
];
|
|
56161
|
+
}
|
|
55896
56162
|
function resumeSessionId(context) {
|
|
55897
56163
|
return context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim() || "";
|
|
55898
56164
|
}
|
|
@@ -55941,8 +56207,9 @@ function toolSettlement(toolCallId, state) {
|
|
|
55941
56207
|
return hasUntrackedBackgroundWork(state) ? "drain" : "self";
|
|
55942
56208
|
}
|
|
55943
56209
|
var GrokAcpSession = class {
|
|
55944
|
-
constructor(imageFiles) {
|
|
56210
|
+
constructor(imageFiles, alanMcp) {
|
|
55945
56211
|
this.imageFiles = imageFiles;
|
|
56212
|
+
this.alanMcp = alanMcp;
|
|
55946
56213
|
}
|
|
55947
56214
|
stdin = null;
|
|
55948
56215
|
nextId = 0;
|
|
@@ -55983,7 +56250,10 @@ var GrokAcpSession = class {
|
|
|
55983
56250
|
}
|
|
55984
56251
|
newSession(context) {
|
|
55985
56252
|
this.attemptedNewSession = true;
|
|
55986
|
-
this.sessionOpId = this.request("session/new", {
|
|
56253
|
+
this.sessionOpId = this.request("session/new", {
|
|
56254
|
+
cwd: context.cwd,
|
|
56255
|
+
mcpServers: buildGrokAcpMcpServers(this.alanMcp)
|
|
56256
|
+
});
|
|
55987
56257
|
}
|
|
55988
56258
|
beginSession(context, state) {
|
|
55989
56259
|
const resume = resumeSessionId(context);
|
|
@@ -55995,7 +56265,7 @@ var GrokAcpSession = class {
|
|
|
55995
56265
|
this.sessionOpId = this.request("session/load", {
|
|
55996
56266
|
sessionId: resume,
|
|
55997
56267
|
cwd: context.cwd,
|
|
55998
|
-
mcpServers:
|
|
56268
|
+
mcpServers: buildGrokAcpMcpServers(this.alanMcp)
|
|
55999
56269
|
});
|
|
56000
56270
|
}
|
|
56001
56271
|
sendPrompt(context, state) {
|
|
@@ -56316,8 +56586,8 @@ var GrokAcpSession = class {
|
|
|
56316
56586
|
});
|
|
56317
56587
|
}
|
|
56318
56588
|
};
|
|
56319
|
-
function createGrokAcpRuntime(imageFiles) {
|
|
56320
|
-
const session = new GrokAcpSession(imageFiles);
|
|
56589
|
+
function createGrokAcpRuntime(imageFiles, alanMcp) {
|
|
56590
|
+
const session = new GrokAcpSession(imageFiles, alanMcp);
|
|
56321
56591
|
const effects = { lifecycle: session.lifecycle };
|
|
56322
56592
|
return {
|
|
56323
56593
|
start: (stdinStream) => session.start(stdinStream),
|
|
@@ -56353,7 +56623,7 @@ function createGrokCliBackend(command = "grok", defaultArgs = []) {
|
|
|
56353
56623
|
context.config.images,
|
|
56354
56624
|
context.cwd
|
|
56355
56625
|
);
|
|
56356
|
-
const runtime = createGrokAcpRuntime(imageFiles);
|
|
56626
|
+
const runtime = createGrokAcpRuntime(imageFiles, context.config.alanMcp);
|
|
56357
56627
|
try {
|
|
56358
56628
|
return await createCliBackend({
|
|
56359
56629
|
kind: "grok_cli",
|
|
@@ -56922,10 +57192,10 @@ function createKimiCliBackend(command = "kimi", defaultArgs = []) {
|
|
|
56922
57192
|
async run(context) {
|
|
56923
57193
|
const dialect = await detectKimiCliDialect(command, context);
|
|
56924
57194
|
const registration = dialect === "kimi-cli" ? context.config.alanMcp : void 0;
|
|
56925
|
-
const mcpDirectory = registration ? (0,
|
|
56926
|
-
const mcpConfigPath = mcpDirectory ? (0,
|
|
57195
|
+
const mcpDirectory = registration ? (0, import_fs17.mkdtempSync)((0, import_path17.join)((0, import_os9.tmpdir)(), "alan-kimi-mcp-")) : null;
|
|
57196
|
+
const mcpConfigPath = mcpDirectory ? (0, import_path17.join)(mcpDirectory, "mcp.json") : null;
|
|
56927
57197
|
if (registration && mcpConfigPath) {
|
|
56928
|
-
(0,
|
|
57198
|
+
(0, import_fs17.writeFileSync)(
|
|
56929
57199
|
mcpConfigPath,
|
|
56930
57200
|
JSON.stringify(
|
|
56931
57201
|
buildKimiMcpConfig(registration, selectExternalMcpServers(context.config))
|
|
@@ -56960,7 +57230,7 @@ function createKimiCliBackend(command = "kimi", defaultArgs = []) {
|
|
|
56960
57230
|
}).run(context);
|
|
56961
57231
|
} finally {
|
|
56962
57232
|
cleanup();
|
|
56963
|
-
if (mcpDirectory) (0,
|
|
57233
|
+
if (mcpDirectory) (0, import_fs17.rmSync)(mcpDirectory, { recursive: true, force: true });
|
|
56964
57234
|
}
|
|
56965
57235
|
}
|
|
56966
57236
|
};
|
|
@@ -58723,6 +58993,56 @@ var RunLedger = class {
|
|
|
58723
58993
|
}
|
|
58724
58994
|
};
|
|
58725
58995
|
|
|
58996
|
+
// src/events/inline-media.ts
|
|
58997
|
+
var MIN_INLINE_MEDIA_CHARS = 8 * 1024;
|
|
58998
|
+
var DATA_URL_PREFIX = /^data:([\w.+-]+\/[\w.+-]+);base64,/;
|
|
58999
|
+
var BASE64_BODY = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
59000
|
+
function omittedMedia(value2) {
|
|
59001
|
+
if (value2.length < MIN_INLINE_MEDIA_CHARS) return null;
|
|
59002
|
+
const dataUrl = DATA_URL_PREFIX.exec(value2);
|
|
59003
|
+
if (dataUrl) {
|
|
59004
|
+
return `[${dataUrl[1]} omitted: ${value2.length - dataUrl[0].length} base64 chars]`;
|
|
59005
|
+
}
|
|
59006
|
+
return BASE64_BODY.test(value2) ? `[base64 omitted: ${value2.length} chars]` : null;
|
|
59007
|
+
}
|
|
59008
|
+
function withoutMedia(value2) {
|
|
59009
|
+
if (typeof value2 === "string") return omittedMedia(value2) ?? value2;
|
|
59010
|
+
if (Array.isArray(value2)) {
|
|
59011
|
+
let changed = false;
|
|
59012
|
+
const items = value2.map((item) => {
|
|
59013
|
+
const next = withoutMedia(item);
|
|
59014
|
+
if (next !== item) changed = true;
|
|
59015
|
+
return next;
|
|
59016
|
+
});
|
|
59017
|
+
return changed ? items : value2;
|
|
59018
|
+
}
|
|
59019
|
+
if (value2 !== null && typeof value2 === "object") {
|
|
59020
|
+
let changed = false;
|
|
59021
|
+
const entries = Object.entries(value2).map(([key, item]) => {
|
|
59022
|
+
const next = withoutMedia(item);
|
|
59023
|
+
if (next !== item) changed = true;
|
|
59024
|
+
return [key, next];
|
|
59025
|
+
});
|
|
59026
|
+
return changed ? Object.fromEntries(entries) : value2;
|
|
59027
|
+
}
|
|
59028
|
+
return value2;
|
|
59029
|
+
}
|
|
59030
|
+
function isMeta(value2) {
|
|
59031
|
+
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
59032
|
+
}
|
|
59033
|
+
function withoutInlineMedia(event) {
|
|
59034
|
+
const { update } = event;
|
|
59035
|
+
const currentMeta = isMeta(update._meta) ? update._meta : void 0;
|
|
59036
|
+
const payload = currentMeta?.[PROVIDER_PAYLOAD_META];
|
|
59037
|
+
const nextPayload = withoutMedia(payload);
|
|
59038
|
+
const rawOutput = update.sessionUpdate === "tool_call_update" ? update.rawOutput : void 0;
|
|
59039
|
+
const nextRawOutput = withoutMedia(rawOutput);
|
|
59040
|
+
if (nextPayload === payload && nextRawOutput === rawOutput) return event;
|
|
59041
|
+
const meta4 = currentMeta && nextPayload !== payload ? { ...currentMeta, [PROVIDER_PAYLOAD_META]: nextPayload } : currentMeta;
|
|
59042
|
+
const next = update.sessionUpdate === "tool_call_update" ? { ...update, _meta: meta4, rawOutput: nextRawOutput } : { ...update, _meta: meta4 };
|
|
59043
|
+
return { ...event, update: next };
|
|
59044
|
+
}
|
|
59045
|
+
|
|
58726
59046
|
// src/events/stream.ts
|
|
58727
59047
|
var listeners = /* @__PURE__ */ new Map();
|
|
58728
59048
|
var FINISHED_LIMIT = 256;
|
|
@@ -58741,9 +59061,10 @@ function subscribeSessionEvents(key, listener, options = {}) {
|
|
|
58741
59061
|
function publishSessionEvent(runId, event, conversationId) {
|
|
58742
59062
|
const sets = [listeners.get(runId), conversationId ? listeners.get(conversationId) : void 0];
|
|
58743
59063
|
if (!sets.some((set2) => set2 && set2.size > 0)) return;
|
|
59064
|
+
const outgoing = withoutInlineMedia(event);
|
|
58744
59065
|
let serialized;
|
|
58745
59066
|
try {
|
|
58746
|
-
serialized = JSON.stringify(
|
|
59067
|
+
serialized = JSON.stringify(outgoing);
|
|
58747
59068
|
} catch {
|
|
58748
59069
|
return;
|
|
58749
59070
|
}
|
|
@@ -58754,7 +59075,7 @@ function publishSessionEvent(runId, event, conversationId) {
|
|
|
58754
59075
|
if (delivered.has(subscriber)) continue;
|
|
58755
59076
|
delivered.add(subscriber);
|
|
58756
59077
|
try {
|
|
58757
|
-
subscriber.listener(
|
|
59078
|
+
subscriber.listener(outgoing, serialized);
|
|
58758
59079
|
} catch {
|
|
58759
59080
|
set2.delete(subscriber);
|
|
58760
59081
|
}
|
|
@@ -59949,7 +60270,7 @@ var Polling = class extends Transport {
|
|
|
59949
60270
|
*/
|
|
59950
60271
|
pause(onPause) {
|
|
59951
60272
|
this.readyState = "pausing";
|
|
59952
|
-
const
|
|
60273
|
+
const pause2 = () => {
|
|
59953
60274
|
debug2("paused");
|
|
59954
60275
|
this.readyState = "paused";
|
|
59955
60276
|
onPause();
|
|
@@ -59961,7 +60282,7 @@ var Polling = class extends Transport {
|
|
|
59961
60282
|
total++;
|
|
59962
60283
|
this.once("pollComplete", function() {
|
|
59963
60284
|
debug2("pre-pause polling complete");
|
|
59964
|
-
--total ||
|
|
60285
|
+
--total || pause2();
|
|
59965
60286
|
});
|
|
59966
60287
|
}
|
|
59967
60288
|
if (!this.writable) {
|
|
@@ -59969,11 +60290,11 @@ var Polling = class extends Transport {
|
|
|
59969
60290
|
total++;
|
|
59970
60291
|
this.once("drain", function() {
|
|
59971
60292
|
debug2("pre-pause writing complete");
|
|
59972
|
-
--total ||
|
|
60293
|
+
--total || pause2();
|
|
59973
60294
|
});
|
|
59974
60295
|
}
|
|
59975
60296
|
} else {
|
|
59976
|
-
|
|
60297
|
+
pause2();
|
|
59977
60298
|
}
|
|
59978
60299
|
}
|
|
59979
60300
|
/**
|
|
@@ -63040,11 +63361,11 @@ function removeNativeHooks(homeDir = (0, import_node_os13.homedir)()) {
|
|
|
63040
63361
|
}
|
|
63041
63362
|
|
|
63042
63363
|
// src/events/runtime-command-reply.ts
|
|
63043
|
-
var
|
|
63364
|
+
var import_promises5 = require("timers/promises");
|
|
63044
63365
|
async function publishRuntimeCommandReply(path2, reply, credentials) {
|
|
63045
63366
|
const body = JSON.stringify(reply);
|
|
63046
63367
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
63047
|
-
if (attempt > 0) await (0,
|
|
63368
|
+
if (attempt > 0) await (0, import_promises5.setTimeout)(250, void 0, { signal: credentials.signal });
|
|
63048
63369
|
credentials.signal.throwIfAborted();
|
|
63049
63370
|
let response;
|
|
63050
63371
|
try {
|
|
@@ -63076,18 +63397,17 @@ async function publishModelScanReply(reply, credentials) {
|
|
|
63076
63397
|
}
|
|
63077
63398
|
|
|
63078
63399
|
// src/events/replay.ts
|
|
63079
|
-
var
|
|
63080
|
-
var import_promises8 = require("fs/promises");
|
|
63400
|
+
var import_node_fs19 = require("fs");
|
|
63081
63401
|
|
|
63082
63402
|
// src/events/live.ts
|
|
63083
63403
|
var import_node_crypto8 = require("crypto");
|
|
63084
63404
|
var import_node_fs17 = require("fs");
|
|
63085
|
-
var
|
|
63405
|
+
var import_promises8 = require("fs/promises");
|
|
63086
63406
|
|
|
63087
63407
|
// src/events/http-retry.ts
|
|
63088
63408
|
var TranscriptRequestError = class extends Error {
|
|
63089
|
-
retryAfterMs;
|
|
63090
63409
|
status;
|
|
63410
|
+
retryAfterMs;
|
|
63091
63411
|
constructor(response) {
|
|
63092
63412
|
super(`Transcript request failed (${response.status})`);
|
|
63093
63413
|
this.status = response.status;
|
|
@@ -63097,18 +63417,53 @@ var TranscriptRequestError = class extends Error {
|
|
|
63097
63417
|
this.retryAfterMs = Number.isFinite(seconds) ? Math.max(0, seconds * 1e3) : Number.isFinite(date5) ? Math.max(0, date5 - Date.now()) : 0;
|
|
63098
63418
|
}
|
|
63099
63419
|
};
|
|
63420
|
+
var PERMANENT_STATUSES = /* @__PURE__ */ new Set([400, 401, 403, 404, 410, 413, 415]);
|
|
63421
|
+
var TRANSIENT_BACKOFF_CAP_MS = 3e4;
|
|
63422
|
+
var PERMANENT_BACKOFF_BASE_MS = 6e4;
|
|
63423
|
+
var PERMANENT_BACKOFF_CAP_MS = 5 * 6e4;
|
|
63424
|
+
function isPermanentTranscriptError(error61) {
|
|
63425
|
+
return error61 instanceof TranscriptRequestError && PERMANENT_STATUSES.has(error61.status);
|
|
63426
|
+
}
|
|
63427
|
+
function transcriptSyncProblem(error61, at = Date.now()) {
|
|
63428
|
+
return {
|
|
63429
|
+
...error61 instanceof TranscriptRequestError ? { status: error61.status } : {},
|
|
63430
|
+
message: error61 instanceof Error ? error61.message : String(error61),
|
|
63431
|
+
permanent: isPermanentTranscriptError(error61),
|
|
63432
|
+
at
|
|
63433
|
+
};
|
|
63434
|
+
}
|
|
63100
63435
|
function transcriptRetryDeadline(failures, error61) {
|
|
63101
|
-
const
|
|
63436
|
+
const exponent = Math.min(failures - 1, 5);
|
|
63437
|
+
const backoff = isPermanentTranscriptError(error61) ? Math.min(PERMANENT_BACKOFF_BASE_MS * 2 ** exponent, PERMANENT_BACKOFF_CAP_MS) : Math.min(1e3 * 2 ** exponent, TRANSIENT_BACKOFF_CAP_MS);
|
|
63102
63438
|
return Date.now() + Math.max(
|
|
63103
63439
|
backoff + Math.floor(Math.random() * backoff * 0.2),
|
|
63104
63440
|
error61 instanceof TranscriptRequestError ? error61.retryAfterMs : 0
|
|
63105
63441
|
);
|
|
63106
63442
|
}
|
|
63443
|
+
function requestDeadline(timeoutMs, parent) {
|
|
63444
|
+
const controller = new AbortController();
|
|
63445
|
+
const timer = setTimeout(
|
|
63446
|
+
() => controller.abort(
|
|
63447
|
+
new DOMException("The operation was aborted due to timeout", "TimeoutError")
|
|
63448
|
+
),
|
|
63449
|
+
timeoutMs
|
|
63450
|
+
);
|
|
63451
|
+
const onAbort = () => controller.abort(parent?.reason);
|
|
63452
|
+
if (parent?.aborted) onAbort();
|
|
63453
|
+
else parent?.addEventListener("abort", onAbort, { once: true });
|
|
63454
|
+
return {
|
|
63455
|
+
signal: controller.signal,
|
|
63456
|
+
dispose() {
|
|
63457
|
+
clearTimeout(timer);
|
|
63458
|
+
parent?.removeEventListener("abort", onAbort);
|
|
63459
|
+
}
|
|
63460
|
+
};
|
|
63461
|
+
}
|
|
63107
63462
|
|
|
63108
63463
|
// src/events/push.ts
|
|
63109
63464
|
var import_node_crypto7 = require("crypto");
|
|
63110
63465
|
var import_node_fs16 = require("fs");
|
|
63111
|
-
var
|
|
63466
|
+
var import_promises7 = require("fs/promises");
|
|
63112
63467
|
|
|
63113
63468
|
// src/events/session.ts
|
|
63114
63469
|
var import_node_fs15 = require("fs");
|
|
@@ -63203,6 +63558,7 @@ function runState(value2) {
|
|
|
63203
63558
|
...offset(value2.liveFailures) ? { liveFailures: value2.liveFailures } : {},
|
|
63204
63559
|
...offset(value2.pushRetryAfter) ? { pushRetryAfter: value2.pushRetryAfter } : {},
|
|
63205
63560
|
...offset(value2.pushFailures) ? { pushFailures: value2.pushFailures } : {},
|
|
63561
|
+
...isSyncProblem(value2.syncProblem) ? { syncProblem: value2.syncProblem } : {},
|
|
63206
63562
|
...record2(sandbox) && typeof sandbox.sandboxId === "string" && typeof sandbox.taskId === "string" && typeof sandbox.agentSessionId === "string" ? {
|
|
63207
63563
|
sandbox: {
|
|
63208
63564
|
sandboxId: sandbox.sandboxId,
|
|
@@ -63212,6 +63568,9 @@ function runState(value2) {
|
|
|
63212
63568
|
} : {}
|
|
63213
63569
|
};
|
|
63214
63570
|
}
|
|
63571
|
+
function isSyncProblem(value2) {
|
|
63572
|
+
return record2(value2) && typeof value2.message === "string" && typeof value2.permanent === "boolean" && offset(value2.at) && (value2.status === void 0 || offset(value2.status));
|
|
63573
|
+
}
|
|
63215
63574
|
function readJson(path2) {
|
|
63216
63575
|
try {
|
|
63217
63576
|
return JSON.parse((0, import_node_fs14.readFileSync)(path2, "utf8"));
|
|
@@ -63313,7 +63672,7 @@ function writeRunTranscriptState(configPath, conversationId, runId, state) {
|
|
|
63313
63672
|
}
|
|
63314
63673
|
|
|
63315
63674
|
// src/events/transcript-buffer.ts
|
|
63316
|
-
var
|
|
63675
|
+
var import_promises6 = require("fs/promises");
|
|
63317
63676
|
var RETAINED_BYTES = 256 * 1024;
|
|
63318
63677
|
var MAX_PENDING_TRANSCRIPT_BYTES = 8 * 1024 * 1024;
|
|
63319
63678
|
var TranscriptBuffer = class {
|
|
@@ -63373,7 +63732,7 @@ function closeTranscriptBuffer(path2, buffer) {
|
|
|
63373
63732
|
async function retryTranscriptWrites(path2, runId) {
|
|
63374
63733
|
const buffer = active.get(path2);
|
|
63375
63734
|
if (!buffer || buffer.runId !== runId) return void 0;
|
|
63376
|
-
const file2 = await (0,
|
|
63735
|
+
const file2 = await (0, import_promises6.open)(path2, "r+");
|
|
63377
63736
|
try {
|
|
63378
63737
|
const stat4 = await file2.stat();
|
|
63379
63738
|
if (`${stat4.dev}.${stat4.ino}.${stat4.birthtimeMs}` !== buffer.generation)
|
|
@@ -63410,6 +63769,13 @@ var openTranscripts = /* @__PURE__ */ new Set();
|
|
|
63410
63769
|
function isSessionTranscriptOpen(runId) {
|
|
63411
63770
|
return openTranscripts.has(runId);
|
|
63412
63771
|
}
|
|
63772
|
+
function canonicalPromptMeta(message) {
|
|
63773
|
+
const meta4 = {
|
|
63774
|
+
...message.clientMessageId ? { "alan.dev/clientMessageId": message.clientMessageId } : {},
|
|
63775
|
+
...message.attachmentIds?.length ? { "alan.dev/attachmentIds": message.attachmentIds } : {}
|
|
63776
|
+
};
|
|
63777
|
+
return Object.keys(meta4).length > 0 ? { _meta: meta4 } : {};
|
|
63778
|
+
}
|
|
63413
63779
|
function requestTranscriptFinalization(configPath, conversationId, runId) {
|
|
63414
63780
|
const state = readRunTranscriptState(configPath, conversationId, runId);
|
|
63415
63781
|
if (state && state.endOffset !== void 0 && !state.interrupted)
|
|
@@ -63480,7 +63846,7 @@ function openSessionTranscript(input2) {
|
|
|
63480
63846
|
sessionUpdate: "user_message",
|
|
63481
63847
|
messageId: message.id,
|
|
63482
63848
|
content: [{ type: "text", text: message.content }],
|
|
63483
|
-
...message
|
|
63849
|
+
...canonicalPromptMeta(message)
|
|
63484
63850
|
}
|
|
63485
63851
|
};
|
|
63486
63852
|
const bytes = Buffer.from(`${JSON.stringify(event)}
|
|
@@ -63644,6 +64010,11 @@ function sizeOf(path2) {
|
|
|
63644
64010
|
var CHECKPOINT_MS = 5e3;
|
|
63645
64011
|
var MAX_RECEIPT_POLL_MS = 15e3;
|
|
63646
64012
|
var MAX_PUSH_BYTES = 512 * 1024;
|
|
64013
|
+
var MIN_PUSH_BYTES = 64 * 1024;
|
|
64014
|
+
var adaptivePushBytes = MAX_PUSH_BYTES;
|
|
64015
|
+
function isTimeout(error61) {
|
|
64016
|
+
return error61 instanceof Error && error61.name === "TimeoutError";
|
|
64017
|
+
}
|
|
63647
64018
|
var REQUEST_TIMEOUT_MS = 1e4;
|
|
63648
64019
|
function transcriptPushUrl(apiUrl, conversationId) {
|
|
63649
64020
|
return `${apiUrl.replace(/\/+$/, "")}/public/conversations/${encodeURIComponent(conversationId)}/transcript`;
|
|
@@ -63656,34 +64027,39 @@ function isReceipt(value2) {
|
|
|
63656
64027
|
async function exchange(target, body, offset2, final = false) {
|
|
63657
64028
|
const token = target.getRuntimeToken();
|
|
63658
64029
|
if (!token) throw new Error("Transcript token unavailable");
|
|
63659
|
-
const
|
|
63660
|
-
|
|
63661
|
-
|
|
63662
|
-
|
|
63663
|
-
|
|
63664
|
-
|
|
63665
|
-
|
|
63666
|
-
"x-alan-
|
|
63667
|
-
|
|
63668
|
-
|
|
63669
|
-
|
|
63670
|
-
|
|
63671
|
-
|
|
63672
|
-
|
|
63673
|
-
|
|
63674
|
-
|
|
63675
|
-
|
|
63676
|
-
|
|
63677
|
-
|
|
63678
|
-
|
|
63679
|
-
|
|
63680
|
-
|
|
63681
|
-
|
|
63682
|
-
|
|
63683
|
-
|
|
63684
|
-
|
|
63685
|
-
|
|
63686
|
-
|
|
64030
|
+
const deadline = requestDeadline(REQUEST_TIMEOUT_MS, target.signal);
|
|
64031
|
+
try {
|
|
64032
|
+
const response = await fetch(transcriptPushUrl(target.apiUrl, target.conversationId), {
|
|
64033
|
+
method: body ? "POST" : "GET",
|
|
64034
|
+
signal: deadline.signal,
|
|
64035
|
+
headers: {
|
|
64036
|
+
authorization: `Bearer ${token}`,
|
|
64037
|
+
"x-alan-run-id": target.runId,
|
|
64038
|
+
...target.sandbox ? {
|
|
64039
|
+
"x-alan-sandbox-id": target.sandbox.sandboxId,
|
|
64040
|
+
"x-alan-task-id": target.sandbox.taskId,
|
|
64041
|
+
"x-alan-agent-session-id": target.sandbox.agentSessionId
|
|
64042
|
+
} : {},
|
|
64043
|
+
...body ? {
|
|
64044
|
+
"content-type": "application/octet-stream",
|
|
64045
|
+
"x-alan-offset": String(offset2),
|
|
64046
|
+
"x-alan-revision": "0",
|
|
64047
|
+
"x-alan-sha256": (0, import_node_crypto7.createHash)("sha256").update(body).digest("hex"),
|
|
64048
|
+
...final ? { "x-alan-final": "1" } : {}
|
|
64049
|
+
} : {}
|
|
64050
|
+
},
|
|
64051
|
+
...body ? { body: new Uint8Array(body) } : {}
|
|
64052
|
+
});
|
|
64053
|
+
if (!response.ok) throw new TranscriptRequestError(response);
|
|
64054
|
+
const result = await response.json();
|
|
64055
|
+
if (!result || typeof result !== "object" || !("receipt" in result))
|
|
64056
|
+
throw new Error("Invalid transcript receipt");
|
|
64057
|
+
if (result.receipt === null && !body) return null;
|
|
64058
|
+
if (!isReceipt(result.receipt)) throw new Error("Invalid transcript receipt");
|
|
64059
|
+
return result.receipt;
|
|
64060
|
+
} finally {
|
|
64061
|
+
deadline.dispose();
|
|
64062
|
+
}
|
|
63687
64063
|
}
|
|
63688
64064
|
function readTranscriptReceipt(target) {
|
|
63689
64065
|
return exchange(target);
|
|
@@ -63755,8 +64131,8 @@ function startTranscriptPush(target, onProblem) {
|
|
|
63755
64131
|
while (!stopped && uploadDue && admitted < boundary) {
|
|
63756
64132
|
const current = state();
|
|
63757
64133
|
if (!current) throw new Error("Transcript run range disappeared");
|
|
63758
|
-
const end = Math.min(boundary, admitted +
|
|
63759
|
-
const file2 = await (0,
|
|
64134
|
+
const end = Math.min(boundary, admitted + adaptivePushBytes);
|
|
64135
|
+
const file2 = await (0, import_promises7.open)(path2, "r");
|
|
63760
64136
|
let bytes;
|
|
63761
64137
|
try {
|
|
63762
64138
|
bytes = Buffer.alloc(end - admitted);
|
|
@@ -63770,6 +64146,7 @@ function startTranscriptPush(target, onProblem) {
|
|
|
63770
64146
|
const next = accept(receipt);
|
|
63771
64147
|
if (next <= admitted) throw new Error("Transcript admission did not advance");
|
|
63772
64148
|
admitted = next;
|
|
64149
|
+
adaptivePushBytes = Math.min(MAX_PUSH_BYTES, adaptivePushBytes * 2);
|
|
63773
64150
|
checkpointAt = Date.now() + CHECKPOINT_MS;
|
|
63774
64151
|
}
|
|
63775
64152
|
if (stopped) return;
|
|
@@ -63795,15 +64172,17 @@ function startTranscriptPush(target, onProblem) {
|
|
|
63795
64172
|
failures = 0;
|
|
63796
64173
|
retryNotBefore = 0;
|
|
63797
64174
|
const current = state();
|
|
63798
|
-
if (current?.pushRetryAfter !== void 0 || current?.pushFailures !== void 0) {
|
|
64175
|
+
if (current?.pushRetryAfter !== void 0 || current?.pushFailures !== void 0 || current?.syncProblem !== void 0) {
|
|
63799
64176
|
writeRunTranscriptState(target.configPath, target.conversationId, target.runId, {
|
|
63800
64177
|
...current,
|
|
63801
64178
|
pushRetryAfter: void 0,
|
|
63802
|
-
pushFailures: void 0
|
|
64179
|
+
pushFailures: void 0,
|
|
64180
|
+
syncProblem: void 0
|
|
63803
64181
|
});
|
|
63804
64182
|
}
|
|
63805
64183
|
}).catch((error61) => {
|
|
63806
64184
|
if (target.signal?.aborted) return;
|
|
64185
|
+
if (isTimeout(error61)) adaptivePushBytes = Math.max(MIN_PUSH_BYTES, adaptivePushBytes / 2);
|
|
63807
64186
|
failures += 1;
|
|
63808
64187
|
pending = true;
|
|
63809
64188
|
cached2 = void 0;
|
|
@@ -63814,7 +64193,8 @@ function startTranscriptPush(target, onProblem) {
|
|
|
63814
64193
|
writeRunTranscriptState(target.configPath, target.conversationId, target.runId, {
|
|
63815
64194
|
...current,
|
|
63816
64195
|
pushRetryAfter: retryNotBefore,
|
|
63817
|
-
pushFailures: failures
|
|
64196
|
+
pushFailures: failures,
|
|
64197
|
+
syncProblem: transcriptSyncProblem(error61)
|
|
63818
64198
|
});
|
|
63819
64199
|
} catch (stateError) {
|
|
63820
64200
|
onProblem(
|
|
@@ -63934,30 +64314,37 @@ function startTranscriptLive(target, onProblem) {
|
|
|
63934
64314
|
const exchange2 = async (body, offset2, epoch) => {
|
|
63935
64315
|
const token = target.getRuntimeToken();
|
|
63936
64316
|
if (!token) throw new Error("Live transcript token unavailable");
|
|
63937
|
-
const
|
|
63938
|
-
|
|
63939
|
-
|
|
63940
|
-
|
|
63941
|
-
|
|
63942
|
-
"
|
|
63943
|
-
|
|
63944
|
-
|
|
63945
|
-
|
|
63946
|
-
"x-alan-
|
|
63947
|
-
"
|
|
63948
|
-
|
|
63949
|
-
|
|
63950
|
-
|
|
63951
|
-
|
|
63952
|
-
|
|
63953
|
-
|
|
63954
|
-
|
|
63955
|
-
|
|
63956
|
-
|
|
63957
|
-
|
|
63958
|
-
|
|
63959
|
-
|
|
63960
|
-
|
|
64317
|
+
const deadline = requestDeadline(5e3, signal);
|
|
64318
|
+
let response;
|
|
64319
|
+
let result;
|
|
64320
|
+
try {
|
|
64321
|
+
response = await fetch(transcriptPushUrl(target.apiUrl, target.conversationId), {
|
|
64322
|
+
method: body ? "POST" : "GET",
|
|
64323
|
+
signal: deadline.signal,
|
|
64324
|
+
headers: {
|
|
64325
|
+
authorization: `Bearer ${token}`,
|
|
64326
|
+
"x-alan-run-id": target.runId,
|
|
64327
|
+
[TRANSCRIPT_LIVE_DELIVERY_HEADER]: "live",
|
|
64328
|
+
...target.sandbox ? {
|
|
64329
|
+
"x-alan-sandbox-id": target.sandbox.sandboxId,
|
|
64330
|
+
"x-alan-task-id": target.sandbox.taskId,
|
|
64331
|
+
"x-alan-agent-session-id": target.sandbox.agentSessionId
|
|
64332
|
+
} : {},
|
|
64333
|
+
...body ? {
|
|
64334
|
+
"content-type": "application/octet-stream",
|
|
64335
|
+
"x-alan-offset": String(offset2),
|
|
64336
|
+
"x-alan-revision": "0",
|
|
64337
|
+
"x-alan-sha256": (0, import_node_crypto8.createHash)("sha256").update(body).digest("hex"),
|
|
64338
|
+
"x-alan-live-epoch": epoch ?? ""
|
|
64339
|
+
} : {}
|
|
64340
|
+
},
|
|
64341
|
+
...body ? { body: new Uint8Array(body) } : {}
|
|
64342
|
+
});
|
|
64343
|
+
if (!response.ok) throw new TranscriptRequestError(response);
|
|
64344
|
+
result = await response.json();
|
|
64345
|
+
} finally {
|
|
64346
|
+
deadline.dispose();
|
|
64347
|
+
}
|
|
63961
64348
|
if (!record3(result) || !isReceipt2(result.receipt))
|
|
63962
64349
|
throw new Error("Invalid live transcript receipt");
|
|
63963
64350
|
const receipt = result.receipt;
|
|
@@ -63988,7 +64375,7 @@ function startTranscriptLive(target, onProblem) {
|
|
|
63988
64375
|
if (active2 && from < active2.retainedFrom)
|
|
63989
64376
|
length = Math.min(length, active2.retainedFrom - from);
|
|
63990
64377
|
bytes = Buffer.alloc(length);
|
|
63991
|
-
const file2 = await (0,
|
|
64378
|
+
const file2 = await (0, import_promises8.open)(path2, "r");
|
|
63992
64379
|
try {
|
|
63993
64380
|
const read = await file2.read(bytes, 0, length, from);
|
|
63994
64381
|
if (read.bytesRead !== length) throw new Error("Live transcript changed during read");
|
|
@@ -64094,19 +64481,104 @@ function startTranscriptLive(target, onProblem) {
|
|
|
64094
64481
|
};
|
|
64095
64482
|
}
|
|
64096
64483
|
|
|
64484
|
+
// src/events/sync-backlog.ts
|
|
64485
|
+
var import_node_fs18 = require("fs");
|
|
64486
|
+
function isTranscriptDelivered(state) {
|
|
64487
|
+
if (!state || state.endOffset === void 0) return true;
|
|
64488
|
+
const size = state.endOffset - state.startOffset;
|
|
64489
|
+
return state.syncedOffset === size && state.finalizedOffset === size;
|
|
64490
|
+
}
|
|
64491
|
+
function decodeConversationId(name) {
|
|
64492
|
+
try {
|
|
64493
|
+
const id = decodeURIComponent(name);
|
|
64494
|
+
return id.length > 0 ? id : void 0;
|
|
64495
|
+
} catch {
|
|
64496
|
+
return void 0;
|
|
64497
|
+
}
|
|
64498
|
+
}
|
|
64499
|
+
function listStoredConversationIds(configPath) {
|
|
64500
|
+
let entries;
|
|
64501
|
+
try {
|
|
64502
|
+
entries = (0, import_node_fs18.readdirSync)(sessionsDirectory(configPath), { withFileTypes: true });
|
|
64503
|
+
} catch (error61) {
|
|
64504
|
+
if (error61.code === "ENOENT") return [];
|
|
64505
|
+
throw error61;
|
|
64506
|
+
}
|
|
64507
|
+
const ids = /* @__PURE__ */ new Set();
|
|
64508
|
+
for (const entry of entries) {
|
|
64509
|
+
const name = entry.isDirectory() ? entry.name.replace(/\.runs$/, "") : entry.isFile() && entry.name.endsWith(".jsonl") ? entry.name.slice(0, -6) : void 0;
|
|
64510
|
+
const id = name === void 0 ? void 0 : decodeConversationId(name);
|
|
64511
|
+
if (id) ids.add(id);
|
|
64512
|
+
}
|
|
64513
|
+
return [...ids];
|
|
64514
|
+
}
|
|
64515
|
+
function readTranscriptSyncBacklog(configPath, isRunActive) {
|
|
64516
|
+
const backlog = [];
|
|
64517
|
+
for (const conversationId of listStoredConversationIds(configPath)) {
|
|
64518
|
+
let runs;
|
|
64519
|
+
try {
|
|
64520
|
+
runs = readConversationSyncState(configPath, conversationId).runs;
|
|
64521
|
+
} catch {
|
|
64522
|
+
continue;
|
|
64523
|
+
}
|
|
64524
|
+
for (const [runId, state] of Object.entries(runs)) {
|
|
64525
|
+
if (isRunActive(runId) || isTranscriptDelivered(state) || state.endOffset === void 0)
|
|
64526
|
+
continue;
|
|
64527
|
+
backlog.push({
|
|
64528
|
+
runId,
|
|
64529
|
+
conversationId,
|
|
64530
|
+
pendingBytes: Math.max(0, state.endOffset - state.startOffset - state.syncedOffset),
|
|
64531
|
+
failures: state.pushFailures ?? 0,
|
|
64532
|
+
...state.syncProblem ? { problem: state.syncProblem } : {}
|
|
64533
|
+
});
|
|
64534
|
+
}
|
|
64535
|
+
}
|
|
64536
|
+
return backlog.sort((a, b) => b.pendingBytes - a.pendingBytes);
|
|
64537
|
+
}
|
|
64538
|
+
function releasePermanentTranscriptCooldowns(configPath) {
|
|
64539
|
+
let released = 0;
|
|
64540
|
+
for (const conversationId of listStoredConversationIds(configPath)) {
|
|
64541
|
+
let runs;
|
|
64542
|
+
try {
|
|
64543
|
+
runs = readConversationSyncState(configPath, conversationId).runs;
|
|
64544
|
+
} catch {
|
|
64545
|
+
continue;
|
|
64546
|
+
}
|
|
64547
|
+
for (const [runId, state] of Object.entries(runs)) {
|
|
64548
|
+
if (!state.syncProblem?.permanent) continue;
|
|
64549
|
+
writeRunTranscriptState(configPath, conversationId, runId, {
|
|
64550
|
+
...state,
|
|
64551
|
+
pushRetryAfter: void 0,
|
|
64552
|
+
pushFailures: void 0,
|
|
64553
|
+
liveRetryAfter: void 0,
|
|
64554
|
+
liveFailures: void 0
|
|
64555
|
+
});
|
|
64556
|
+
released += 1;
|
|
64557
|
+
}
|
|
64558
|
+
}
|
|
64559
|
+
return released;
|
|
64560
|
+
}
|
|
64561
|
+
|
|
64097
64562
|
// src/events/replay.ts
|
|
64098
64563
|
function startTranscriptReplay(options) {
|
|
64099
64564
|
const controller = new AbortController();
|
|
64100
64565
|
const signal = AbortSignal.any([options.signal, controller.signal]);
|
|
64101
64566
|
let running;
|
|
64102
64567
|
let notifiedDuringReplay = false;
|
|
64568
|
+
let cooldownTimer;
|
|
64569
|
+
const retryAfterCooldown = (retryAt) => {
|
|
64570
|
+
if (retryAt === void 0 || signal.aborted) return;
|
|
64571
|
+
if (cooldownTimer) clearTimeout(cooldownTimer);
|
|
64572
|
+
cooldownTimer = setTimeout(notify, Math.max(0, retryAt - Date.now()));
|
|
64573
|
+
cooldownTimer.unref();
|
|
64574
|
+
};
|
|
64103
64575
|
const notify = () => {
|
|
64104
64576
|
if (signal.aborted) return;
|
|
64105
64577
|
if (running) {
|
|
64106
64578
|
notifiedDuringReplay = true;
|
|
64107
64579
|
return;
|
|
64108
64580
|
}
|
|
64109
|
-
running = replayClosedTranscripts({ ...options, signal }).catch((error61) => options.onProblem(`transcript-replay-failed ${String(error61)}`)).finally(() => {
|
|
64581
|
+
running = replayClosedTranscripts({ ...options, signal }).then(retryAfterCooldown).catch((error61) => options.onProblem(`transcript-replay-failed ${String(error61)}`)).finally(() => {
|
|
64110
64582
|
running = void 0;
|
|
64111
64583
|
if (notifiedDuringReplay) {
|
|
64112
64584
|
notifiedDuringReplay = false;
|
|
@@ -64120,6 +64592,7 @@ function startTranscriptReplay(options) {
|
|
|
64120
64592
|
notify,
|
|
64121
64593
|
async stop() {
|
|
64122
64594
|
clearInterval(timer);
|
|
64595
|
+
if (cooldownTimer) clearTimeout(cooldownTimer);
|
|
64123
64596
|
controller.abort();
|
|
64124
64597
|
await running;
|
|
64125
64598
|
}
|
|
@@ -64131,7 +64604,7 @@ function recoverInterruptedRange(options, conversationId, runId) {
|
|
|
64131
64604
|
if (!state) throw new Error("Transcript range disappeared");
|
|
64132
64605
|
if ((state.finalRequested || state.interrupted) && state.endOffset !== void 0) return state;
|
|
64133
64606
|
const path2 = transcriptPath(options.configPath, conversationId);
|
|
64134
|
-
const length = (0,
|
|
64607
|
+
const length = (0, import_node_fs19.statSync)(path2).size;
|
|
64135
64608
|
const nextStart = Object.values(conversation.runs).reduce(
|
|
64136
64609
|
(end2, range) => range.startOffset > state.startOffset ? Math.min(end2, range.startOffset) : end2,
|
|
64137
64610
|
length
|
|
@@ -64139,12 +64612,12 @@ function recoverInterruptedRange(options, conversationId, runId) {
|
|
|
64139
64612
|
let end = state.endOffset ?? nextStart;
|
|
64140
64613
|
if (end > length || end < state.startOffset)
|
|
64141
64614
|
throw new Error("Interrupted transcript range is outside its journal");
|
|
64142
|
-
const file2 = (0,
|
|
64615
|
+
const file2 = (0, import_node_fs19.openSync)(path2, "r");
|
|
64143
64616
|
try {
|
|
64144
64617
|
const buffer = Buffer.alloc(64 * 1024);
|
|
64145
64618
|
while (end > state.startOffset) {
|
|
64146
64619
|
const start = Math.max(state.startOffset, end - buffer.length);
|
|
64147
|
-
const count2 = (0,
|
|
64620
|
+
const count2 = (0, import_node_fs19.readSync)(file2, buffer, 0, end - start, start);
|
|
64148
64621
|
if (count2 !== end - start) throw new Error("Interrupted transcript changed during recovery");
|
|
64149
64622
|
const newline = buffer.subarray(0, count2).lastIndexOf(10);
|
|
64150
64623
|
if (newline >= 0) {
|
|
@@ -64154,7 +64627,7 @@ function recoverInterruptedRange(options, conversationId, runId) {
|
|
|
64154
64627
|
end = start;
|
|
64155
64628
|
}
|
|
64156
64629
|
} finally {
|
|
64157
|
-
(0,
|
|
64630
|
+
(0, import_node_fs19.closeSync)(file2);
|
|
64158
64631
|
}
|
|
64159
64632
|
if (end < state.startOffset + state.syncedOffset)
|
|
64160
64633
|
throw new Error("Interrupted transcript has committed incomplete bytes; repair required");
|
|
@@ -64170,114 +64643,121 @@ function recoverInterruptedRange(options, conversationId, runId) {
|
|
|
64170
64643
|
);
|
|
64171
64644
|
return recovered;
|
|
64172
64645
|
}
|
|
64173
|
-
|
|
64174
|
-
|
|
64175
|
-
const done = () => {
|
|
64176
|
-
signal.removeEventListener("abort", done);
|
|
64177
|
-
clearTimeout(timer);
|
|
64178
|
-
resolve16();
|
|
64179
|
-
};
|
|
64180
|
-
const timer = setTimeout(done, Math.max(0, at - Date.now()));
|
|
64181
|
-
signal.addEventListener("abort", done, { once: true });
|
|
64182
|
-
});
|
|
64183
|
-
}
|
|
64184
|
-
function isDelivered(state) {
|
|
64185
|
-
if (!state || state.endOffset === void 0) return true;
|
|
64186
|
-
const size = state.endOffset - state.startOffset;
|
|
64187
|
-
return state.syncedOffset === size && state.finalizedOffset === size;
|
|
64188
|
-
}
|
|
64189
|
-
function decodeId(name) {
|
|
64646
|
+
var REPLAY_CONCURRENCY = 3;
|
|
64647
|
+
function lastActivityMs(configPath, conversationId) {
|
|
64190
64648
|
try {
|
|
64191
|
-
|
|
64192
|
-
return id.length > 0 ? id : void 0;
|
|
64649
|
+
return (0, import_node_fs19.statSync)(syncStatePath(configPath, conversationId)).mtimeMs;
|
|
64193
64650
|
} catch {
|
|
64194
|
-
return
|
|
64651
|
+
return 0;
|
|
64195
64652
|
}
|
|
64196
64653
|
}
|
|
64197
64654
|
async function replayClosedTranscripts(options) {
|
|
64198
|
-
if (options.signal.aborted || !options.canReplay()) return;
|
|
64199
|
-
const
|
|
64200
|
-
const
|
|
64201
|
-
|
|
64202
|
-
|
|
64203
|
-
|
|
64204
|
-
|
|
64205
|
-
|
|
64206
|
-
|
|
64207
|
-
|
|
64208
|
-
|
|
64209
|
-
|
|
64210
|
-
conversations.
|
|
64211
|
-
|
|
64212
|
-
|
|
64213
|
-
|
|
64655
|
+
if (options.signal.aborted || !options.canReplay()) return void 0;
|
|
64656
|
+
const conversations = listStoredConversationIds(options.configPath).filter((id) => !options.conversationId || options.conversationId === id).map((id) => ({ id, activity: lastActivityMs(options.configPath, id) })).sort((a, b) => b.activity - a.activity).map((entry) => entry.id);
|
|
64657
|
+
const cooldowns = { earliest: void 0 };
|
|
64658
|
+
let next = 0;
|
|
64659
|
+
const worker = async () => {
|
|
64660
|
+
while (next < conversations.length) {
|
|
64661
|
+
if (options.signal.aborted || !options.canReplay()) return;
|
|
64662
|
+
const conversationId = conversations[next++];
|
|
64663
|
+
if (conversationId) await replayConversation(options, conversationId, cooldowns);
|
|
64664
|
+
}
|
|
64665
|
+
};
|
|
64666
|
+
await Promise.all(
|
|
64667
|
+
Array.from({ length: Math.min(REPLAY_CONCURRENCY, conversations.length) }, worker)
|
|
64668
|
+
);
|
|
64669
|
+
return cooldowns.earliest;
|
|
64670
|
+
}
|
|
64671
|
+
async function replayConversation(options, conversationId, cooldowns) {
|
|
64672
|
+
let conversation;
|
|
64673
|
+
try {
|
|
64674
|
+
migrateConversationStorage(options.configPath, conversationId);
|
|
64675
|
+
conversation = readConversationSyncState(options.configPath, conversationId);
|
|
64676
|
+
} catch (error61) {
|
|
64677
|
+
options.onProblem(`transcript-state-failed conversation=${conversationId}: ${String(error61)}`);
|
|
64678
|
+
return;
|
|
64679
|
+
}
|
|
64680
|
+
const runIds = Object.keys(conversation.runs).sort(
|
|
64681
|
+
(a, b) => (conversation.runs[b]?.startOffset ?? 0) - (conversation.runs[a]?.startOffset ?? 0)
|
|
64682
|
+
);
|
|
64683
|
+
for (const runId of runIds) {
|
|
64214
64684
|
if (options.signal.aborted || !options.canReplay()) return;
|
|
64215
|
-
|
|
64685
|
+
if (options.isRunActive(runId) || isSessionTranscriptOpen(runId)) continue;
|
|
64686
|
+
if (options.sandboxId && conversation.runs[runId]?.sandbox?.sandboxId !== options.sandboxId)
|
|
64687
|
+
continue;
|
|
64688
|
+
let state;
|
|
64216
64689
|
try {
|
|
64217
|
-
|
|
64218
|
-
|
|
64690
|
+
const recoveredEnd = await retryTranscriptWrites(
|
|
64691
|
+
transcriptPath(options.configPath, conversationId),
|
|
64692
|
+
runId
|
|
64693
|
+
);
|
|
64694
|
+
if (recoveredEnd !== void 0) {
|
|
64695
|
+
const current = readConversationSyncState(options.configPath, conversationId).runs[runId];
|
|
64696
|
+
if (!current) throw new Error("Transcript range disappeared during write recovery");
|
|
64697
|
+
writeRunTranscriptState(options.configPath, conversationId, runId, {
|
|
64698
|
+
...current,
|
|
64699
|
+
endOffset: recoveredEnd,
|
|
64700
|
+
interrupted: true,
|
|
64701
|
+
finalRequested: false
|
|
64702
|
+
});
|
|
64703
|
+
const path2 = transcriptPath(options.configPath, conversationId);
|
|
64704
|
+
const buffer = getTranscriptBuffer(path2);
|
|
64705
|
+
if (buffer) closeTranscriptBuffer(path2, buffer);
|
|
64706
|
+
}
|
|
64707
|
+
state = recoverInterruptedRange(options, conversationId, runId);
|
|
64219
64708
|
} catch (error61) {
|
|
64220
|
-
options.onProblem(`transcript-
|
|
64709
|
+
options.onProblem(`transcript-recovery-failed run=${runId}: ${String(error61)}`);
|
|
64221
64710
|
continue;
|
|
64222
64711
|
}
|
|
64223
|
-
|
|
64224
|
-
|
|
64225
|
-
|
|
64226
|
-
|
|
64227
|
-
|
|
64228
|
-
|
|
64229
|
-
|
|
64230
|
-
|
|
64231
|
-
|
|
64232
|
-
|
|
64233
|
-
|
|
64234
|
-
|
|
64235
|
-
|
|
64236
|
-
|
|
64237
|
-
|
|
64238
|
-
|
|
64239
|
-
|
|
64240
|
-
|
|
64241
|
-
|
|
64242
|
-
|
|
64243
|
-
|
|
64244
|
-
const buffer = getTranscriptBuffer(path2);
|
|
64245
|
-
if (buffer) closeTranscriptBuffer(path2, buffer);
|
|
64246
|
-
}
|
|
64247
|
-
state = recoverInterruptedRange(options, conversationId, runId);
|
|
64248
|
-
} catch (error61) {
|
|
64249
|
-
options.onProblem(`transcript-recovery-failed run=${runId}: ${String(error61)}`);
|
|
64250
|
-
continue;
|
|
64251
|
-
}
|
|
64252
|
-
if (state.endOffset === void 0) continue;
|
|
64253
|
-
const size = state.endOffset - state.startOffset;
|
|
64254
|
-
if (state.syncedOffset === size && state.finalizedOffset === size) continue;
|
|
64255
|
-
const target = {
|
|
64256
|
-
configPath: options.configPath,
|
|
64257
|
-
apiUrl: options.apiUrl,
|
|
64258
|
-
conversationId,
|
|
64259
|
-
runId,
|
|
64260
|
-
getRuntimeToken: options.getRuntimeToken,
|
|
64261
|
-
signal: options.signal,
|
|
64262
|
-
sandbox: state.sandbox
|
|
64263
|
-
};
|
|
64264
|
-
const cooldownUntil = Math.max(state.pushRetryAfter ?? 0, state.liveRetryAfter ?? 0);
|
|
64265
|
-
const push2 = startTranscriptPush(target, options.onProblem);
|
|
64266
|
-
const live = startTranscriptLive(target, options.onProblem);
|
|
64267
|
-
try {
|
|
64268
|
-
await Promise.all([push2.flush(), live.flush()]);
|
|
64269
|
-
if (cooldownUntil > Date.now() && !isDelivered(readConversationSyncState(options.configPath, conversationId).runs[runId])) {
|
|
64270
|
-
await waitUntil(cooldownUntil, options.signal);
|
|
64271
|
-
if (!options.signal.aborted) await Promise.all([push2.flush(), live.flush()]);
|
|
64272
|
-
}
|
|
64273
|
-
} finally {
|
|
64274
|
-
await Promise.all([push2.stop(), live.stop()]);
|
|
64275
|
-
}
|
|
64712
|
+
if (state.endOffset === void 0 || isTranscriptDelivered(state)) continue;
|
|
64713
|
+
const cooldownUntil = Math.max(state.pushRetryAfter ?? 0, state.liveRetryAfter ?? 0);
|
|
64714
|
+
if (cooldownUntil > Date.now()) {
|
|
64715
|
+
cooldowns.earliest = Math.min(cooldowns.earliest ?? cooldownUntil, cooldownUntil);
|
|
64716
|
+
continue;
|
|
64717
|
+
}
|
|
64718
|
+
const target = {
|
|
64719
|
+
configPath: options.configPath,
|
|
64720
|
+
apiUrl: options.apiUrl,
|
|
64721
|
+
conversationId,
|
|
64722
|
+
runId,
|
|
64723
|
+
getRuntimeToken: options.getRuntimeToken,
|
|
64724
|
+
signal: options.signal,
|
|
64725
|
+
sandbox: state.sandbox
|
|
64726
|
+
};
|
|
64727
|
+
const push2 = startTranscriptPush(target, options.onProblem);
|
|
64728
|
+
const live = startTranscriptLive(target, options.onProblem);
|
|
64729
|
+
try {
|
|
64730
|
+
await Promise.all([push2.flush(), live.flush()]);
|
|
64731
|
+
} finally {
|
|
64732
|
+
await Promise.all([push2.stop(), live.stop()]);
|
|
64276
64733
|
}
|
|
64277
64734
|
}
|
|
64278
64735
|
}
|
|
64279
64736
|
|
|
64280
64737
|
// src/events/run-events.ts
|
|
64738
|
+
var TERMINAL_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
64739
|
+
"query_complete",
|
|
64740
|
+
"complete",
|
|
64741
|
+
"session_complete",
|
|
64742
|
+
"session_error",
|
|
64743
|
+
"agent_run_finished"
|
|
64744
|
+
]);
|
|
64745
|
+
var TERMINAL_RETRY_WINDOW_MS = 10 * 6e4;
|
|
64746
|
+
var RETRY_BACKOFF_CAP_MS = 3e4;
|
|
64747
|
+
function isRetryableStatus(status2) {
|
|
64748
|
+
return status2 === 408 || status2 === 429 || status2 >= 500;
|
|
64749
|
+
}
|
|
64750
|
+
function pause(ms, signal) {
|
|
64751
|
+
return new Promise((resolve16) => {
|
|
64752
|
+
const done = () => {
|
|
64753
|
+
clearTimeout(timer);
|
|
64754
|
+
signal.removeEventListener("abort", done);
|
|
64755
|
+
resolve16();
|
|
64756
|
+
};
|
|
64757
|
+
const timer = setTimeout(done, ms);
|
|
64758
|
+
signal.addEventListener("abort", done, { once: true });
|
|
64759
|
+
});
|
|
64760
|
+
}
|
|
64281
64761
|
function runEventsUrl(wsUrl) {
|
|
64282
64762
|
const base = wsUrl.replace(/^ws:/, "http:").replace(/^wss:/, "https:").replace(/\/+$/, "");
|
|
64283
64763
|
return `${base}/runtime/run-events`;
|
|
@@ -64339,24 +64819,41 @@ function createHttpRunEventSink(input2, url3, binding) {
|
|
|
64339
64819
|
}
|
|
64340
64820
|
}
|
|
64341
64821
|
async function deliver(conversationId, runId, event) {
|
|
64342
|
-
|
|
64343
|
-
const
|
|
64344
|
-
|
|
64345
|
-
|
|
64346
|
-
const
|
|
64347
|
-
|
|
64348
|
-
|
|
64349
|
-
|
|
64350
|
-
|
|
64351
|
-
|
|
64352
|
-
|
|
64353
|
-
|
|
64354
|
-
|
|
64355
|
-
|
|
64356
|
-
|
|
64357
|
-
|
|
64358
|
-
|
|
64359
|
-
|
|
64822
|
+
const terminal = TERMINAL_EVENT_TYPES.has(event.type);
|
|
64823
|
+
const giveUpAt = Date.now() + TERMINAL_RETRY_WINDOW_MS;
|
|
64824
|
+
for (let attempt = 0; ; attempt++) {
|
|
64825
|
+
if (shutdown.signal.aborted) return;
|
|
64826
|
+
const token = input2.getRuntimeToken();
|
|
64827
|
+
if (!token) return;
|
|
64828
|
+
let failure2;
|
|
64829
|
+
let retryable;
|
|
64830
|
+
const deadline = requestDeadline(1e4, shutdown.signal);
|
|
64831
|
+
try {
|
|
64832
|
+
const response = await postRunEvent({
|
|
64833
|
+
url: url3,
|
|
64834
|
+
token,
|
|
64835
|
+
conversationId,
|
|
64836
|
+
runId,
|
|
64837
|
+
event,
|
|
64838
|
+
signal: deadline.signal,
|
|
64839
|
+
binding
|
|
64840
|
+
});
|
|
64841
|
+
if (response.ok) return;
|
|
64842
|
+
failure2 = `run-event rejected ${response.status} run=${runId}`;
|
|
64843
|
+
retryable = isRetryableStatus(response.status);
|
|
64844
|
+
} catch (error61) {
|
|
64845
|
+
failure2 = `run-event send failed run=${runId}: ${error61 instanceof Error ? error61.message : String(error61)}`;
|
|
64846
|
+
retryable = true;
|
|
64847
|
+
} finally {
|
|
64848
|
+
deadline.dispose();
|
|
64849
|
+
}
|
|
64850
|
+
const backoff = Math.min(1e3 * 2 ** attempt, RETRY_BACKOFF_CAP_MS);
|
|
64851
|
+
if (!terminal || !retryable || Date.now() + backoff > giveUpAt) {
|
|
64852
|
+
input2.onFailure?.(failure2);
|
|
64853
|
+
return;
|
|
64854
|
+
}
|
|
64855
|
+
input2.onFailure?.(`${failure2}; retrying in ${backoff}ms`);
|
|
64856
|
+
await pause(backoff, shutdown.signal);
|
|
64360
64857
|
}
|
|
64361
64858
|
}
|
|
64362
64859
|
return {
|
|
@@ -64424,7 +64921,7 @@ function createTranscriptWatchRegistry() {
|
|
|
64424
64921
|
}
|
|
64425
64922
|
|
|
64426
64923
|
// src/native/ingest.ts
|
|
64427
|
-
var
|
|
64924
|
+
var import_node_fs21 = require("fs");
|
|
64428
64925
|
var import_promises10 = require("fs/promises");
|
|
64429
64926
|
|
|
64430
64927
|
// src/native/alan-runs.ts
|
|
@@ -64664,7 +65161,7 @@ async function pushNativeTurn(delivery, record4) {
|
|
|
64664
65161
|
|
|
64665
65162
|
// src/native/session-store.ts
|
|
64666
65163
|
var import_node_crypto9 = require("crypto");
|
|
64667
|
-
var
|
|
65164
|
+
var import_node_fs20 = require("fs");
|
|
64668
65165
|
var import_node_path19 = require("path");
|
|
64669
65166
|
var MAX_NATIVE_SESSION_ENTRIES = 500;
|
|
64670
65167
|
var nativeRunFinishEvents = ["agent_run_finished", "query_complete"];
|
|
@@ -64701,7 +65198,7 @@ function isSessionEntry(value2) {
|
|
|
64701
65198
|
function loadSessions(path2) {
|
|
64702
65199
|
let parsed;
|
|
64703
65200
|
try {
|
|
64704
|
-
parsed = JSON.parse((0,
|
|
65201
|
+
parsed = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
|
|
64705
65202
|
} catch {
|
|
64706
65203
|
return [];
|
|
64707
65204
|
}
|
|
@@ -64709,14 +65206,14 @@ function loadSessions(path2) {
|
|
|
64709
65206
|
return parsed.sessions.filter(isSessionEntry);
|
|
64710
65207
|
}
|
|
64711
65208
|
function writeAtomically(path2, contents) {
|
|
64712
|
-
(0,
|
|
65209
|
+
(0, import_node_fs20.mkdirSync)((0, import_node_path19.dirname)(path2), { recursive: true, mode: 448 });
|
|
64713
65210
|
const pending = `${path2}.pending-${process.pid}-${(0, import_node_crypto9.randomBytes)(6).toString("hex")}`;
|
|
64714
65211
|
try {
|
|
64715
|
-
(0,
|
|
64716
|
-
(0,
|
|
64717
|
-
(0,
|
|
65212
|
+
(0, import_node_fs20.writeFileSync)(pending, contents, { mode: 384 });
|
|
65213
|
+
(0, import_node_fs20.chmodSync)(pending, 384);
|
|
65214
|
+
(0, import_node_fs20.renameSync)(pending, path2);
|
|
64718
65215
|
} finally {
|
|
64719
|
-
(0,
|
|
65216
|
+
(0, import_node_fs20.rmSync)(pending, { force: true });
|
|
64720
65217
|
}
|
|
64721
65218
|
}
|
|
64722
65219
|
function evictionOrder(a, b) {
|
|
@@ -64965,7 +65462,7 @@ function sleep2(ms, signal) {
|
|
|
64965
65462
|
});
|
|
64966
65463
|
}
|
|
64967
65464
|
function holdFor(entry) {
|
|
64968
|
-
const stats = (0,
|
|
65465
|
+
const stats = (0, import_node_fs21.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
|
|
64969
65466
|
if (!stats) return [];
|
|
64970
65467
|
return [
|
|
64971
65468
|
{
|
|
@@ -65181,7 +65678,7 @@ function createNativeIngestionSink(deps) {
|
|
|
65181
65678
|
const recordAlanRun = (hold, runId) => {
|
|
65182
65679
|
const entry = store.get(hold.provider, hold.externalSessionId);
|
|
65183
65680
|
if (!entry || entry.dead) return;
|
|
65184
|
-
const stats = (0,
|
|
65681
|
+
const stats = (0, import_node_fs21.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
|
|
65185
65682
|
if (!stats) return;
|
|
65186
65683
|
const identity = { device: String(stats.dev), inode: String(stats.ino) };
|
|
65187
65684
|
const size = Number(stats.size);
|
|
@@ -65463,7 +65960,7 @@ function createNativeIngestionSink(deps) {
|
|
|
65463
65960
|
schedule(worker, timing.debounceMs);
|
|
65464
65961
|
};
|
|
65465
65962
|
const hasUnreadBytes = (entry, now) => {
|
|
65466
|
-
const stats = (0,
|
|
65963
|
+
const stats = (0, import_node_fs21.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
|
|
65467
65964
|
if (!stats || now - Number(stats.mtimeMs) > timing.sweepRecencyMs) return false;
|
|
65468
65965
|
const replaced = String(stats.dev) !== entry.device || String(stats.ino) !== entry.inode;
|
|
65469
65966
|
return replaced || Number(stats.size) > entry.cursor.offset;
|
|
@@ -67826,16 +68323,16 @@ function applyLeaseCheckResult(input2) {
|
|
|
67826
68323
|
}
|
|
67827
68324
|
|
|
67828
68325
|
// src/daemon/admission.ts
|
|
67829
|
-
var
|
|
68326
|
+
var import_node_fs23 = require("fs");
|
|
67830
68327
|
var import_node_path26 = require("path");
|
|
67831
68328
|
|
|
67832
68329
|
// src/workspace-relocation.ts
|
|
67833
68330
|
var import_node_child_process6 = require("child_process");
|
|
67834
|
-
var
|
|
68331
|
+
var import_node_fs22 = require("fs");
|
|
67835
68332
|
var import_node_path24 = require("path");
|
|
67836
68333
|
var MAX_RELOCATION_CANDIDATES = 200;
|
|
67837
68334
|
var DEFAULT_PROBE2 = {
|
|
67838
|
-
childDirectories: (parentPath, limit) => (0,
|
|
68335
|
+
childDirectories: (parentPath, limit) => (0, import_node_fs22.readdirSync)(parentPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).slice(0, limit).map((entry) => (0, import_node_path24.join)(parentPath, entry.name)),
|
|
67839
68336
|
gitRemoteUrl: (candidatePath) => {
|
|
67840
68337
|
const result = (0, import_node_child_process6.spawnSync)("git", ["-C", candidatePath, "config", "--get", "remote.origin.url"], {
|
|
67841
68338
|
encoding: "utf8",
|
|
@@ -68140,7 +68637,7 @@ function resolveWorkspace(ctx, payload) {
|
|
|
68140
68637
|
const workspacePathPinned = payload.workspacePathPinned === true;
|
|
68141
68638
|
if (isAlanDefaultWorkspace(payload.projectPath) && !workspacePathPinned) {
|
|
68142
68639
|
try {
|
|
68143
|
-
(0,
|
|
68640
|
+
(0, import_node_fs23.mkdirSync)(cwd, { recursive: true });
|
|
68144
68641
|
} catch {
|
|
68145
68642
|
}
|
|
68146
68643
|
}
|
|
@@ -68616,7 +69113,7 @@ async function launchRun(ctx, payload, plan) {
|
|
|
68616
69113
|
}
|
|
68617
69114
|
|
|
68618
69115
|
// src/daemon/journal.ts
|
|
68619
|
-
var
|
|
69116
|
+
var import_node_fs24 = require("fs");
|
|
68620
69117
|
var import_node_path27 = require("path");
|
|
68621
69118
|
var JOURNAL_VERSION = 1;
|
|
68622
69119
|
var INTERRUPTED_ENTRY_TTL_MS = 24 * 60 * 6e4;
|
|
@@ -68636,9 +69133,9 @@ function isEntry(value2) {
|
|
|
68636
69133
|
var RuntimeRunJournal = class {
|
|
68637
69134
|
constructor(path2, nowMs = Date.now()) {
|
|
68638
69135
|
this.path = path2;
|
|
68639
|
-
if (!(0,
|
|
69136
|
+
if (!(0, import_node_fs24.existsSync)(path2)) return;
|
|
68640
69137
|
try {
|
|
68641
|
-
const parsed = JSON.parse((0,
|
|
69138
|
+
const parsed = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf8"));
|
|
68642
69139
|
if (parsed.version !== JOURNAL_VERSION || !Array.isArray(parsed.entries)) {
|
|
68643
69140
|
throw new Error("unsupported run journal format");
|
|
68644
69141
|
}
|
|
@@ -68761,18 +69258,18 @@ var RuntimeRunJournal = class {
|
|
|
68761
69258
|
}
|
|
68762
69259
|
persist() {
|
|
68763
69260
|
const pendingPath = `${this.path}.pending`;
|
|
68764
|
-
(0,
|
|
69261
|
+
(0, import_node_fs24.mkdirSync)((0, import_node_path27.dirname)(this.path), { recursive: true });
|
|
68765
69262
|
try {
|
|
68766
|
-
(0,
|
|
69263
|
+
(0, import_node_fs24.writeFileSync)(
|
|
68767
69264
|
pendingPath,
|
|
68768
69265
|
`${JSON.stringify({ version: JOURNAL_VERSION, entries: [...this.entries.values()] })}
|
|
68769
69266
|
`,
|
|
68770
69267
|
{ mode: 384 }
|
|
68771
69268
|
);
|
|
68772
|
-
(0,
|
|
68773
|
-
(0,
|
|
69269
|
+
(0, import_node_fs24.chmodSync)(pendingPath, 384);
|
|
69270
|
+
(0, import_node_fs24.renameSync)(pendingPath, this.path);
|
|
68774
69271
|
} catch (error61) {
|
|
68775
|
-
(0,
|
|
69272
|
+
(0, import_node_fs24.rmSync)(pendingPath, { force: true });
|
|
68776
69273
|
throw error61;
|
|
68777
69274
|
}
|
|
68778
69275
|
}
|
|
@@ -68931,7 +69428,7 @@ function bindLocalApi(server, port) {
|
|
|
68931
69428
|
}
|
|
68932
69429
|
|
|
68933
69430
|
// src/daemon/log.ts
|
|
68934
|
-
var
|
|
69431
|
+
var import_node_fs25 = require("fs");
|
|
68935
69432
|
var import_node_path28 = require("path");
|
|
68936
69433
|
var RECENT_LIMIT = 200;
|
|
68937
69434
|
var MAX_BYTES = 5 * 1024 * 1024;
|
|
@@ -68944,20 +69441,20 @@ function openDaemonLog(configPath) {
|
|
|
68944
69441
|
let written = 0;
|
|
68945
69442
|
let sinceSizeCheck = 0;
|
|
68946
69443
|
const open6 = () => {
|
|
68947
|
-
(0,
|
|
68948
|
-
handle = (0,
|
|
69444
|
+
(0, import_node_fs25.mkdirSync)(directory, { recursive: true, mode: 448 });
|
|
69445
|
+
handle = (0, import_node_fs25.openSync)(path2, "a", 384);
|
|
68949
69446
|
try {
|
|
68950
|
-
written = (0,
|
|
69447
|
+
written = (0, import_node_fs25.statSync)(path2).size;
|
|
68951
69448
|
} catch {
|
|
68952
69449
|
written = 0;
|
|
68953
69450
|
}
|
|
68954
69451
|
};
|
|
68955
69452
|
const rotate = () => {
|
|
68956
69453
|
if (handle === null) return;
|
|
68957
|
-
(0,
|
|
69454
|
+
(0, import_node_fs25.closeSync)(handle);
|
|
68958
69455
|
handle = null;
|
|
68959
69456
|
try {
|
|
68960
|
-
(0,
|
|
69457
|
+
(0, import_node_fs25.renameSync)(path2, `${path2}.1`);
|
|
68961
69458
|
} catch {
|
|
68962
69459
|
}
|
|
68963
69460
|
open6();
|
|
@@ -68982,7 +69479,7 @@ function openDaemonLog(configPath) {
|
|
|
68982
69479
|
sinceSizeCheck = 0;
|
|
68983
69480
|
rotate();
|
|
68984
69481
|
}
|
|
68985
|
-
if (handle !== null) written += (0,
|
|
69482
|
+
if (handle !== null) written += (0, import_node_fs25.writeSync)(handle, line);
|
|
68986
69483
|
} catch {
|
|
68987
69484
|
}
|
|
68988
69485
|
};
|
|
@@ -68992,7 +69489,7 @@ function openDaemonLog(configPath) {
|
|
|
68992
69489
|
close: () => {
|
|
68993
69490
|
if (handle === null) return;
|
|
68994
69491
|
try {
|
|
68995
|
-
(0,
|
|
69492
|
+
(0, import_node_fs25.closeSync)(handle);
|
|
68996
69493
|
} catch {
|
|
68997
69494
|
}
|
|
68998
69495
|
handle = null;
|
|
@@ -69251,16 +69748,16 @@ function handleCapabilities(res) {
|
|
|
69251
69748
|
}
|
|
69252
69749
|
|
|
69253
69750
|
// src/daemon/routes/local-transcript.ts
|
|
69254
|
-
var
|
|
69751
|
+
var import_node_fs26 = require("fs");
|
|
69255
69752
|
var LocalTranscriptUnavailable = class extends Error {
|
|
69256
69753
|
};
|
|
69257
69754
|
function completeEnd(path2, start, end) {
|
|
69258
|
-
const file2 = (0,
|
|
69755
|
+
const file2 = (0, import_node_fs26.openSync)(path2, "r");
|
|
69259
69756
|
const buffer = Buffer.alloc(64 * 1024);
|
|
69260
69757
|
try {
|
|
69261
69758
|
while (end > start) {
|
|
69262
69759
|
const from = Math.max(start, end - buffer.length);
|
|
69263
|
-
const count2 = (0,
|
|
69760
|
+
const count2 = (0, import_node_fs26.readSync)(file2, buffer, 0, end - from, from);
|
|
69264
69761
|
if (count2 !== end - from)
|
|
69265
69762
|
throw new LocalTranscriptUnavailable("Journal changed during snapshot");
|
|
69266
69763
|
const newline = buffer.subarray(0, count2).lastIndexOf(10);
|
|
@@ -69269,12 +69766,12 @@ function completeEnd(path2, start, end) {
|
|
|
69269
69766
|
}
|
|
69270
69767
|
return start;
|
|
69271
69768
|
} finally {
|
|
69272
|
-
(0,
|
|
69769
|
+
(0, import_node_fs26.closeSync)(file2);
|
|
69273
69770
|
}
|
|
69274
69771
|
}
|
|
69275
69772
|
function localTranscriptSnapshot(configPath, conversationId) {
|
|
69276
69773
|
const path2 = transcriptPath(configPath, conversationId);
|
|
69277
|
-
const stat4 = (0,
|
|
69774
|
+
const stat4 = (0, import_node_fs26.statSync)(path2);
|
|
69278
69775
|
const state = readConversationSyncState(configPath, conversationId);
|
|
69279
69776
|
const messages = [];
|
|
69280
69777
|
const active2 = getTranscriptBuffer(path2);
|
|
@@ -69352,9 +69849,9 @@ function localRange(snapshot, messageId, offset2, maxBytes) {
|
|
|
69352
69849
|
throw new LocalTranscriptUnavailable("Unknown local message range");
|
|
69353
69850
|
const length = message.role === "user" ? message.end - message.start : Math.min(maxBytes, message.bytes - offset2);
|
|
69354
69851
|
const bytes = Buffer.alloc(length);
|
|
69355
|
-
const file2 = (0,
|
|
69852
|
+
const file2 = (0, import_node_fs26.openSync)(snapshot.path, "r");
|
|
69356
69853
|
try {
|
|
69357
|
-
const stat4 = (0,
|
|
69854
|
+
const stat4 = (0, import_node_fs26.fstatSync)(file2);
|
|
69358
69855
|
if (`${stat4.dev}.${stat4.ino}.${stat4.birthtimeMs}` !== snapshot.generation)
|
|
69359
69856
|
throw new LocalTranscriptUnavailable("Local journal generation changed");
|
|
69360
69857
|
const start = message.start + offset2;
|
|
@@ -69362,7 +69859,7 @@ function localRange(snapshot, messageId, offset2, maxBytes) {
|
|
|
69362
69859
|
const active2 = candidate && start + length <= candidate.produced ? candidate : void 0;
|
|
69363
69860
|
const memoryStart = active2 ? Math.max(start, active2.retainedFrom) : start + length;
|
|
69364
69861
|
const diskLength = Math.min(length, memoryStart - start);
|
|
69365
|
-
if (diskLength > 0 && (0,
|
|
69862
|
+
if (diskLength > 0 && (0, import_node_fs26.readSync)(file2, bytes, 0, diskLength, start) !== diskLength)
|
|
69366
69863
|
throw new LocalTranscriptUnavailable("Local journal changed during read");
|
|
69367
69864
|
if (diskLength < length) {
|
|
69368
69865
|
const tail = active2?.read(start + diskLength, length - diskLength);
|
|
@@ -69370,7 +69867,7 @@ function localRange(snapshot, messageId, offset2, maxBytes) {
|
|
|
69370
69867
|
tail.copy(bytes, diskLength);
|
|
69371
69868
|
}
|
|
69372
69869
|
} finally {
|
|
69373
|
-
(0,
|
|
69870
|
+
(0, import_node_fs26.closeSync)(file2);
|
|
69374
69871
|
}
|
|
69375
69872
|
if (message.role === "user") {
|
|
69376
69873
|
const parsed = JSON.parse(bytes.toString());
|
|
@@ -69937,7 +70434,7 @@ var BindingSwitchGitError = class extends Error {
|
|
|
69937
70434
|
// src/git/repo.ts
|
|
69938
70435
|
var import_node_child_process8 = require("child_process");
|
|
69939
70436
|
var import_node_crypto15 = require("crypto");
|
|
69940
|
-
var
|
|
70437
|
+
var import_node_fs27 = require("fs");
|
|
69941
70438
|
var import_node_os15 = require("os");
|
|
69942
70439
|
var import_node_path29 = require("path");
|
|
69943
70440
|
var import_node_url = require("url");
|
|
@@ -69970,12 +70467,12 @@ function networkGitTimeoutMs() {
|
|
|
69970
70467
|
async function waitForCheckpointTestBarrier() {
|
|
69971
70468
|
const barrierDir = process.env.NODE_ENV === "test" ? process.env.ALAN_TEST_GIT_CHECKPOINT_BARRIER_DIR : void 0;
|
|
69972
70469
|
if (!barrierDir) return;
|
|
69973
|
-
(0,
|
|
70470
|
+
(0, import_node_fs27.mkdirSync)(barrierDir, { recursive: true });
|
|
69974
70471
|
const readyPath = (0, import_node_path29.join)(barrierDir, "ready");
|
|
69975
70472
|
const releasePath = (0, import_node_path29.join)(barrierDir, "release");
|
|
69976
|
-
(0,
|
|
70473
|
+
(0, import_node_fs27.writeFileSync)(readyPath, "ready\n");
|
|
69977
70474
|
const deadline = Date.now() + 5e3;
|
|
69978
|
-
while (!(0,
|
|
70475
|
+
while (!(0, import_node_fs27.existsSync)(releasePath)) {
|
|
69979
70476
|
if (Date.now() >= deadline) {
|
|
69980
70477
|
throw new BindingSwitchGitError(
|
|
69981
70478
|
"checkpoint_prepare_timeout",
|
|
@@ -69988,12 +70485,12 @@ async function waitForCheckpointTestBarrier() {
|
|
|
69988
70485
|
async function waitForCheckpointFinalizeTestBarrier() {
|
|
69989
70486
|
const barrierDir = process.env.NODE_ENV === "test" ? process.env.ALAN_TEST_GIT_CHECKPOINT_FINALIZE_BARRIER_DIR : void 0;
|
|
69990
70487
|
if (!barrierDir) return;
|
|
69991
|
-
(0,
|
|
70488
|
+
(0, import_node_fs27.mkdirSync)(barrierDir, { recursive: true });
|
|
69992
70489
|
const readyPath = (0, import_node_path29.join)(barrierDir, "ready");
|
|
69993
70490
|
const releasePath = (0, import_node_path29.join)(barrierDir, "release");
|
|
69994
|
-
(0,
|
|
70491
|
+
(0, import_node_fs27.writeFileSync)(readyPath, "ready\n");
|
|
69995
70492
|
const deadline = Date.now() + 5e3;
|
|
69996
|
-
while (!(0,
|
|
70493
|
+
while (!(0, import_node_fs27.existsSync)(releasePath)) {
|
|
69997
70494
|
if (Date.now() >= deadline) {
|
|
69998
70495
|
throw new BindingSwitchGitError(
|
|
69999
70496
|
"checkpoint_finalize_timeout",
|
|
@@ -70106,7 +70603,7 @@ function sourceChangedDuringCheckpoint(message) {
|
|
|
70106
70603
|
}
|
|
70107
70604
|
function acquireCheckpointHeadLock(locks) {
|
|
70108
70605
|
try {
|
|
70109
|
-
(0,
|
|
70606
|
+
(0, import_node_fs27.writeFileSync)(locks.headLockPath, "", { flag: "wx" });
|
|
70110
70607
|
locks.headLockHeld = true;
|
|
70111
70608
|
} catch {
|
|
70112
70609
|
throw sourceChangedDuringCheckpoint(
|
|
@@ -70116,7 +70613,7 @@ function acquireCheckpointHeadLock(locks) {
|
|
|
70116
70613
|
}
|
|
70117
70614
|
function releaseCheckpointHeadLock(locks) {
|
|
70118
70615
|
if (!locks.headLockHeld) return;
|
|
70119
|
-
(0,
|
|
70616
|
+
(0, import_node_fs27.rmSync)(locks.headLockPath, { force: true });
|
|
70120
70617
|
locks.headLockHeld = false;
|
|
70121
70618
|
}
|
|
70122
70619
|
function acquireCheckpointRepositoryLocks(repoRoot) {
|
|
@@ -70138,13 +70635,13 @@ function acquireCheckpointRepositoryLocks(repoRoot) {
|
|
|
70138
70635
|
indexPath
|
|
70139
70636
|
};
|
|
70140
70637
|
try {
|
|
70141
|
-
(0,
|
|
70638
|
+
(0, import_node_fs27.writeFileSync)(locks.indexLockPath, "", { flag: "wx" });
|
|
70142
70639
|
locks.indexLockHeld = true;
|
|
70143
70640
|
acquireCheckpointHeadLock(locks);
|
|
70144
70641
|
return locks;
|
|
70145
70642
|
} catch {
|
|
70146
70643
|
if (locks.indexLockHeld) {
|
|
70147
|
-
(0,
|
|
70644
|
+
(0, import_node_fs27.rmSync)(locks.indexLockPath, { force: true });
|
|
70148
70645
|
locks.indexLockHeld = false;
|
|
70149
70646
|
}
|
|
70150
70647
|
throw sourceChangedDuringCheckpoint(
|
|
@@ -70155,7 +70652,7 @@ function acquireCheckpointRepositoryLocks(repoRoot) {
|
|
|
70155
70652
|
function releaseCheckpointRepositoryLocks(locks) {
|
|
70156
70653
|
releaseCheckpointHeadLock(locks);
|
|
70157
70654
|
if (locks.indexLockHeld) {
|
|
70158
|
-
(0,
|
|
70655
|
+
(0, import_node_fs27.rmSync)(locks.indexLockPath, { force: true });
|
|
70159
70656
|
locks.indexLockHeld = false;
|
|
70160
70657
|
}
|
|
70161
70658
|
}
|
|
@@ -70173,7 +70670,7 @@ function assertCheckpointHead(repoRoot, expectedRef, expectedHeadSha) {
|
|
|
70173
70670
|
}
|
|
70174
70671
|
}
|
|
70175
70672
|
function createCheckpointIndexBaseline(repoRoot, checkpointSha) {
|
|
70176
|
-
const tempDir = (0,
|
|
70673
|
+
const tempDir = (0, import_node_fs27.mkdtempSync)((0, import_node_path29.join)((0, import_node_os15.tmpdir)(), "alan-checkpoint-index-"));
|
|
70177
70674
|
const indexPath = (0, import_node_path29.join)(tempDir, "index");
|
|
70178
70675
|
try {
|
|
70179
70676
|
runGitWithOptions(
|
|
@@ -70184,14 +70681,14 @@ function createCheckpointIndexBaseline(repoRoot, checkpointSha) {
|
|
|
70184
70681
|
);
|
|
70185
70682
|
return { indexPath, tempDir };
|
|
70186
70683
|
} catch (error61) {
|
|
70187
|
-
(0,
|
|
70684
|
+
(0, import_node_fs27.rmSync)(tempDir, { recursive: true, force: true });
|
|
70188
70685
|
throw error61;
|
|
70189
70686
|
}
|
|
70190
70687
|
}
|
|
70191
70688
|
function installCheckpointIndexBaseline(locks, baselineIndexPath) {
|
|
70192
70689
|
try {
|
|
70193
|
-
(0,
|
|
70194
|
-
(0,
|
|
70690
|
+
(0, import_node_fs27.copyFileSync)(baselineIndexPath, locks.indexLockPath);
|
|
70691
|
+
(0, import_node_fs27.renameSync)(locks.indexLockPath, locks.indexPath);
|
|
70195
70692
|
locks.indexLockHeld = false;
|
|
70196
70693
|
} catch (error61) {
|
|
70197
70694
|
throw new BindingSwitchGitError(
|
|
@@ -70354,7 +70851,7 @@ function inspectedRemoteUrl(repoRoot, params) {
|
|
|
70354
70851
|
function canonicalPathWithMissingTail(path2) {
|
|
70355
70852
|
const missingSegments = [];
|
|
70356
70853
|
let cursor = (0, import_node_path29.resolve)(path2);
|
|
70357
|
-
while (!(0,
|
|
70854
|
+
while (!(0, import_node_fs27.existsSync)(cursor)) {
|
|
70358
70855
|
const parent = (0, import_node_path29.dirname)(cursor);
|
|
70359
70856
|
if (parent === cursor) {
|
|
70360
70857
|
throw new BindingSwitchGitError(
|
|
@@ -70365,10 +70862,10 @@ function canonicalPathWithMissingTail(path2) {
|
|
|
70365
70862
|
missingSegments.unshift((0, import_node_path29.basename)(cursor));
|
|
70366
70863
|
cursor = parent;
|
|
70367
70864
|
}
|
|
70368
|
-
return (0, import_node_path29.join)(
|
|
70865
|
+
return (0, import_node_path29.join)(import_node_fs27.realpathSync.native(cursor), ...missingSegments);
|
|
70369
70866
|
}
|
|
70370
70867
|
function resolveRepositoryRoot(requestedPath) {
|
|
70371
|
-
if (!(0,
|
|
70868
|
+
if (!(0, import_node_fs27.existsSync)(requestedPath)) {
|
|
70372
70869
|
throw new BindingSwitchGitError(
|
|
70373
70870
|
"repository_not_found",
|
|
70374
70871
|
`The selected repository path does not exist: ${requestedPath}`
|
|
@@ -70381,7 +70878,7 @@ function resolveRepositoryRoot(requestedPath) {
|
|
|
70381
70878
|
"The selected folder is not inside a Git repository"
|
|
70382
70879
|
);
|
|
70383
70880
|
}
|
|
70384
|
-
return
|
|
70881
|
+
return import_node_fs27.realpathSync.native((0, import_node_path29.resolve)(root.stdout.trim()));
|
|
70385
70882
|
}
|
|
70386
70883
|
function listWorktrees(repoRoot) {
|
|
70387
70884
|
return runGit(repoRoot, ["worktree", "list", "--porcelain"]).split("\n\n").flatMap((entry) => {
|
|
@@ -70437,7 +70934,7 @@ function updateLengthPrefixed(hash2, value2) {
|
|
|
70437
70934
|
hash2.update("\0");
|
|
70438
70935
|
}
|
|
70439
70936
|
function proposedTreeSha(repoRoot, headSha) {
|
|
70440
|
-
const tempDir = (0,
|
|
70937
|
+
const tempDir = (0, import_node_fs27.mkdtempSync)((0, import_node_path29.join)((0, import_node_os15.tmpdir)(), "alan-switch-index-"));
|
|
70441
70938
|
const indexPath = (0, import_node_path29.join)(tempDir, "index");
|
|
70442
70939
|
const options = { env: { GIT_INDEX_FILE: indexPath } };
|
|
70443
70940
|
try {
|
|
@@ -70451,7 +70948,7 @@ function proposedTreeSha(repoRoot, headSha) {
|
|
|
70451
70948
|
assertCommitSha(treeSha, "proposedTreeSha");
|
|
70452
70949
|
return treeSha;
|
|
70453
70950
|
} finally {
|
|
70454
|
-
(0,
|
|
70951
|
+
(0, import_node_fs27.rmSync)(tempDir, { recursive: true, force: true });
|
|
70455
70952
|
}
|
|
70456
70953
|
}
|
|
70457
70954
|
function statusFingerprint(repoRoot, porcelain, proposedTree) {
|
|
@@ -70686,7 +71183,7 @@ async function checkout(params) {
|
|
|
70686
71183
|
}
|
|
70687
71184
|
|
|
70688
71185
|
// src/git/checkpoint.ts
|
|
70689
|
-
var
|
|
71186
|
+
var import_node_fs28 = require("fs");
|
|
70690
71187
|
async function checkpoint(params) {
|
|
70691
71188
|
const { switchId, repoKey } = commonRequest(params);
|
|
70692
71189
|
const repoRoot = resolveAuthorizedRepository(params, true);
|
|
@@ -70711,7 +71208,7 @@ async function checkpoint(params) {
|
|
|
70711
71208
|
return { repoRoot, sha: status2.headSha, replayed: true };
|
|
70712
71209
|
} finally {
|
|
70713
71210
|
if (locks2) releaseCheckpointRepositoryLocks(locks2);
|
|
70714
|
-
(0,
|
|
71211
|
+
(0, import_node_fs28.rmSync)(baseline2.tempDir, { recursive: true, force: true });
|
|
70715
71212
|
}
|
|
70716
71213
|
}
|
|
70717
71214
|
assertSourcePreconditions(status2, expectedHeadSha, expectedStatusFingerprint, expectedBranch);
|
|
@@ -70819,7 +71316,7 @@ Alan-Repository-Id: ${repoKey}`;
|
|
|
70819
71316
|
runGitResult(repoRoot, ["update-ref", expectedRef, expectedHeadSha, sha]);
|
|
70820
71317
|
}
|
|
70821
71318
|
if (locks) releaseCheckpointRepositoryLocks(locks);
|
|
70822
|
-
(0,
|
|
71319
|
+
(0, import_node_fs28.rmSync)(baseline.tempDir, { recursive: true, force: true });
|
|
70823
71320
|
}
|
|
70824
71321
|
}
|
|
70825
71322
|
|
|
@@ -71025,7 +71522,7 @@ async function stopBackgroundTaskForRun(deps, payload) {
|
|
|
71025
71522
|
}
|
|
71026
71523
|
|
|
71027
71524
|
// src/daemon/sweep.ts
|
|
71028
|
-
var
|
|
71525
|
+
var import_node_fs29 = require("fs");
|
|
71029
71526
|
var import_node_path30 = require("path");
|
|
71030
71527
|
function retiredPaths(configPath) {
|
|
71031
71528
|
const directory = (0, import_node_path30.dirname)(configPath);
|
|
@@ -71044,9 +71541,9 @@ function retiredPaths(configPath) {
|
|
|
71044
71541
|
function sweepRetiredArtifacts(configPath) {
|
|
71045
71542
|
const removed = [];
|
|
71046
71543
|
for (const path2 of retiredPaths(configPath)) {
|
|
71047
|
-
if (!(0,
|
|
71544
|
+
if (!(0, import_node_fs29.existsSync)(path2)) continue;
|
|
71048
71545
|
try {
|
|
71049
|
-
(0,
|
|
71546
|
+
(0, import_node_fs29.rmSync)(path2, { recursive: true, force: true });
|
|
71050
71547
|
removed.push(path2);
|
|
71051
71548
|
} catch {
|
|
71052
71549
|
}
|
|
@@ -71056,6 +71553,8 @@ function sweepRetiredArtifacts(configPath) {
|
|
|
71056
71553
|
|
|
71057
71554
|
// src/daemon/start.ts
|
|
71058
71555
|
var RUNTIME_TOKEN_RENEWAL_WINDOW_MS2 = 24 * 60 * 60 * 1e3;
|
|
71556
|
+
var TRANSCRIPT_BACKLOG_TTL_MS = 1e4;
|
|
71557
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
71059
71558
|
async function startDaemon(args) {
|
|
71060
71559
|
bindConfigPath(args);
|
|
71061
71560
|
const stored = readConfig();
|
|
@@ -71431,6 +71930,33 @@ async function startDaemon(args) {
|
|
|
71431
71930
|
});
|
|
71432
71931
|
const persistWorkspaceRelocations = relocationTracker.persist;
|
|
71433
71932
|
const flushWorkspaceRelocations = relocationTracker.flush;
|
|
71933
|
+
let transcriptBacklog = {
|
|
71934
|
+
readAtMs: 0,
|
|
71935
|
+
runs: []
|
|
71936
|
+
};
|
|
71937
|
+
const transcriptSyncPending = () => {
|
|
71938
|
+
const nowMs = Date.now();
|
|
71939
|
+
if (nowMs - transcriptBacklog.readAtMs < TRANSCRIPT_BACKLOG_TTL_MS)
|
|
71940
|
+
return transcriptBacklog.runs;
|
|
71941
|
+
try {
|
|
71942
|
+
const runs = readTranscriptSyncBacklog(
|
|
71943
|
+
configPath,
|
|
71944
|
+
(runId) => activeAgents.has(runId) || pendingRunStarts.has(runId)
|
|
71945
|
+
).filter(
|
|
71946
|
+
(entry) => UUID_PATTERN.test(entry.runId) && UUID_PATTERN.test(entry.conversationId)
|
|
71947
|
+
).slice(0, MAX_REPORTED_TRANSCRIPT_SYNC_RUNS).map((entry) => ({
|
|
71948
|
+
runId: entry.runId,
|
|
71949
|
+
conversationId: entry.conversationId,
|
|
71950
|
+
...entry.problem?.status !== void 0 ? { problemStatus: entry.problem.status } : {},
|
|
71951
|
+
...entry.problem ? { problemPermanent: entry.problem.permanent } : {}
|
|
71952
|
+
}));
|
|
71953
|
+
transcriptBacklog = { readAtMs: nowMs, runs };
|
|
71954
|
+
} catch (error61) {
|
|
71955
|
+
pushLog(`transcript-backlog-scan-failed ${String(error61)}`);
|
|
71956
|
+
transcriptBacklog = { ...transcriptBacklog, readAtMs: nowMs };
|
|
71957
|
+
}
|
|
71958
|
+
return transcriptBacklog.runs;
|
|
71959
|
+
};
|
|
71434
71960
|
const runnerStatusInput = () => ({
|
|
71435
71961
|
connected: socket.connected,
|
|
71436
71962
|
activeAgents,
|
|
@@ -71439,6 +71965,7 @@ async function startDaemon(args) {
|
|
|
71439
71965
|
daemonEpoch,
|
|
71440
71966
|
heartbeatSeq,
|
|
71441
71967
|
interruptedRunIds: runJournal.recoveredRunIds(),
|
|
71968
|
+
transcriptSyncPending: transcriptSyncPending(),
|
|
71442
71969
|
endpointProfile,
|
|
71443
71970
|
configPath,
|
|
71444
71971
|
runtimeId,
|
|
@@ -71460,6 +71987,19 @@ async function startDaemon(args) {
|
|
|
71460
71987
|
let transcriptReplayEnabled = false;
|
|
71461
71988
|
let transcriptReplay = null;
|
|
71462
71989
|
let transcriptReplayRequested = false;
|
|
71990
|
+
let transcriptCooldownTimer;
|
|
71991
|
+
const scheduleCooldownReplay = (retryAt) => {
|
|
71992
|
+
if (retryAt === void 0 || shutdownAbort.signal.aborted) return;
|
|
71993
|
+
if (transcriptCooldownTimer) clearTimeout(transcriptCooldownTimer);
|
|
71994
|
+
transcriptCooldownTimer = setTimeout(
|
|
71995
|
+
() => {
|
|
71996
|
+
transcriptCooldownTimer = void 0;
|
|
71997
|
+
replayTranscripts();
|
|
71998
|
+
},
|
|
71999
|
+
Math.max(0, retryAt - Date.now())
|
|
72000
|
+
);
|
|
72001
|
+
transcriptCooldownTimer.unref?.();
|
|
72002
|
+
};
|
|
71463
72003
|
const replayTranscripts = () => {
|
|
71464
72004
|
if (!transcriptReplayEnabled || shutdownAbort.signal.aborted || terminalAuthFailureCode) return;
|
|
71465
72005
|
if (transcriptReplay) {
|
|
@@ -71474,7 +72014,7 @@ async function startDaemon(args) {
|
|
|
71474
72014
|
canReplay: () => !terminalAuthFailureCode,
|
|
71475
72015
|
signal: shutdownAbort.signal,
|
|
71476
72016
|
onProblem: pushLog
|
|
71477
|
-
}).catch((error61) => pushLog(`transcript-replay-failed ${String(error61)}`)).finally(() => {
|
|
72017
|
+
}).then(scheduleCooldownReplay).catch((error61) => pushLog(`transcript-replay-failed ${String(error61)}`)).finally(() => {
|
|
71478
72018
|
transcriptReplay = null;
|
|
71479
72019
|
if (transcriptReplayRequested) {
|
|
71480
72020
|
transcriptReplayRequested = false;
|
|
@@ -71519,6 +72059,11 @@ async function startDaemon(args) {
|
|
|
71519
72059
|
socket.on("connect", () => {
|
|
71520
72060
|
disconnectedSinceMs = null;
|
|
71521
72061
|
clearConnectErrors();
|
|
72062
|
+
try {
|
|
72063
|
+
if (releasePermanentTranscriptCooldowns(configPath) > 0) replayTranscripts();
|
|
72064
|
+
} catch (error61) {
|
|
72065
|
+
pushLog(`transcript-cooldown-release-failed ${String(error61)}`);
|
|
72066
|
+
}
|
|
71522
72067
|
deniedRedialAttempt = 0;
|
|
71523
72068
|
if (deniedRedialTimer) {
|
|
71524
72069
|
clearTimeout(deniedRedialTimer);
|
|
@@ -71845,6 +72390,7 @@ async function startDaemon(args) {
|
|
|
71845
72390
|
);
|
|
71846
72391
|
const abortStartup = async (error61, closeServer = false) => {
|
|
71847
72392
|
clearInterval(heartbeat);
|
|
72393
|
+
if (transcriptCooldownTimer) clearTimeout(transcriptCooldownTimer);
|
|
71848
72394
|
clearInterval(versionRefresh);
|
|
71849
72395
|
leaseMonitor.stop();
|
|
71850
72396
|
suspensionDetector.stop();
|
|
@@ -71883,6 +72429,7 @@ async function startDaemon(args) {
|
|
|
71883
72429
|
let shutdownComplete = false;
|
|
71884
72430
|
try {
|
|
71885
72431
|
clearInterval(heartbeat);
|
|
72432
|
+
if (transcriptCooldownTimer) clearTimeout(transcriptCooldownTimer);
|
|
71886
72433
|
clearInterval(versionRefresh);
|
|
71887
72434
|
leaseMonitor.stop();
|
|
71888
72435
|
clearInterval(skillSyncInterval);
|
|
@@ -71945,7 +72492,7 @@ async function startDaemon(args) {
|
|
|
71945
72492
|
// src/service-manager.ts
|
|
71946
72493
|
var import_node_child_process9 = require("child_process");
|
|
71947
72494
|
var import_node_crypto17 = require("crypto");
|
|
71948
|
-
var
|
|
72495
|
+
var import_node_fs30 = require("fs");
|
|
71949
72496
|
var import_node_os17 = require("os");
|
|
71950
72497
|
var import_node_path32 = require("path");
|
|
71951
72498
|
var SERVICE_LABEL = "ai.tryalan.agent";
|
|
@@ -72383,19 +72930,19 @@ function currentServicePlan(args, runtime, options = {}) {
|
|
|
72383
72930
|
});
|
|
72384
72931
|
}
|
|
72385
72932
|
function writeManifestAtomic(path2, contents) {
|
|
72386
|
-
(0,
|
|
72933
|
+
(0, import_node_fs30.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true, mode: 448 });
|
|
72387
72934
|
const pendingPath = `${path2}.pending-${process.pid}`;
|
|
72388
72935
|
try {
|
|
72389
|
-
(0,
|
|
72390
|
-
(0,
|
|
72391
|
-
(0,
|
|
72936
|
+
(0, import_node_fs30.writeFileSync)(pendingPath, contents, { mode: 384 });
|
|
72937
|
+
(0, import_node_fs30.chmodSync)(pendingPath, 384);
|
|
72938
|
+
(0, import_node_fs30.renameSync)(pendingPath, path2);
|
|
72392
72939
|
} finally {
|
|
72393
|
-
(0,
|
|
72940
|
+
(0, import_node_fs30.rmSync)(pendingPath, { force: true });
|
|
72394
72941
|
}
|
|
72395
72942
|
}
|
|
72396
72943
|
function defaultReadManifest(path2) {
|
|
72397
|
-
if (!(0,
|
|
72398
|
-
return (0,
|
|
72944
|
+
if (!(0, import_node_fs30.existsSync)(path2)) return null;
|
|
72945
|
+
return (0, import_node_fs30.readFileSync)(path2, "utf8");
|
|
72399
72946
|
}
|
|
72400
72947
|
function runServiceCommand(command, options = {}) {
|
|
72401
72948
|
return new Promise((resolveCommand2, reject2) => {
|
|
@@ -72594,9 +73141,9 @@ function createHostContext(options = {}) {
|
|
|
72594
73141
|
};
|
|
72595
73142
|
const readManifest = options.readManifest ?? defaultReadManifest;
|
|
72596
73143
|
const writeManifest = options.writeManifest ?? writeManifestAtomic;
|
|
72597
|
-
const removeManifest = options.removeManifest ?? ((path2) => (0,
|
|
73144
|
+
const removeManifest = options.removeManifest ?? ((path2) => (0, import_node_fs30.rmSync)(path2, { force: true }));
|
|
72598
73145
|
const ensureLogDir = options.ensureLogDir ?? (() => {
|
|
72599
|
-
if (plan.logDirectory) (0,
|
|
73146
|
+
if (plan.logDirectory) (0, import_node_fs30.mkdirSync)(plan.logDirectory, { recursive: true, mode: 448 });
|
|
72600
73147
|
});
|
|
72601
73148
|
return {
|
|
72602
73149
|
args,
|
|
@@ -72918,7 +73465,7 @@ ${result.output}
|
|
|
72918
73465
|
|
|
72919
73466
|
// src/mcp-config-adapters.ts
|
|
72920
73467
|
var import_node_crypto18 = require("crypto");
|
|
72921
|
-
var
|
|
73468
|
+
var import_node_fs31 = require("fs");
|
|
72922
73469
|
var import_node_os18 = require("os");
|
|
72923
73470
|
var import_node_path33 = require("path");
|
|
72924
73471
|
var log2 = {
|
|
@@ -72945,22 +73492,22 @@ function parseJsonSafe(content) {
|
|
|
72945
73492
|
throw new MalformedToolConfigError("Existing tool config is malformed");
|
|
72946
73493
|
}
|
|
72947
73494
|
function readFileOr(path2) {
|
|
72948
|
-
return (0,
|
|
73495
|
+
return (0, import_node_fs31.existsSync)(path2) ? (0, import_node_fs31.readFileSync)(path2, "utf-8") : null;
|
|
72949
73496
|
}
|
|
72950
73497
|
function acquireConfigLock(path2) {
|
|
72951
|
-
(0,
|
|
73498
|
+
(0, import_node_fs31.mkdirSync)((0, import_node_path33.dirname)(path2), { recursive: true });
|
|
72952
73499
|
const lockPath = `${path2}.alan-lock`;
|
|
72953
73500
|
const startedAt = Date.now();
|
|
72954
73501
|
while (true) {
|
|
72955
73502
|
try {
|
|
72956
|
-
(0,
|
|
72957
|
-
return () => (0,
|
|
73503
|
+
(0, import_node_fs31.mkdirSync)(lockPath);
|
|
73504
|
+
return () => (0, import_node_fs31.rmSync)(lockPath, { recursive: true, force: true });
|
|
72958
73505
|
} catch (error61) {
|
|
72959
73506
|
const code = error61 && typeof error61 === "object" && "code" in error61 ? error61.code : void 0;
|
|
72960
73507
|
if (code !== "EEXIST") throw error61;
|
|
72961
73508
|
try {
|
|
72962
|
-
if (Date.now() - (0,
|
|
72963
|
-
(0,
|
|
73509
|
+
if (Date.now() - (0, import_node_fs31.statSync)(lockPath).mtimeMs > 3e4) {
|
|
73510
|
+
(0, import_node_fs31.rmSync)(lockPath, { recursive: true, force: true });
|
|
72964
73511
|
continue;
|
|
72965
73512
|
}
|
|
72966
73513
|
} catch {
|
|
@@ -72974,19 +73521,19 @@ function acquireConfigLock(path2) {
|
|
|
72974
73521
|
}
|
|
72975
73522
|
}
|
|
72976
73523
|
function writeFileSafe(path2, content) {
|
|
72977
|
-
(0,
|
|
73524
|
+
(0, import_node_fs31.mkdirSync)((0, import_node_path33.dirname)(path2), { recursive: true });
|
|
72978
73525
|
const pendingPath = `${path2}.alan-pending-${process.pid}-${(0, import_node_crypto18.randomBytes)(6).toString("hex")}`;
|
|
72979
73526
|
try {
|
|
72980
|
-
(0,
|
|
72981
|
-
(0,
|
|
73527
|
+
(0, import_node_fs31.writeFileSync)(pendingPath, content, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
73528
|
+
(0, import_node_fs31.renameSync)(pendingPath, path2);
|
|
72982
73529
|
} finally {
|
|
72983
|
-
(0,
|
|
73530
|
+
(0, import_node_fs31.rmSync)(pendingPath, { force: true });
|
|
72984
73531
|
}
|
|
72985
73532
|
}
|
|
72986
73533
|
function saveMalformedBackup(path2, content) {
|
|
72987
73534
|
const hash2 = (0, import_node_crypto18.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
72988
73535
|
const backupPath = `${path2}.alan-backup-${hash2}`;
|
|
72989
|
-
if (!(0,
|
|
73536
|
+
if (!(0, import_node_fs31.existsSync)(backupPath)) (0, import_node_fs31.copyFileSync)(path2, backupPath);
|
|
72990
73537
|
return backupPath;
|
|
72991
73538
|
}
|
|
72992
73539
|
var claudeAdapter = {
|
|
@@ -73359,6 +73906,95 @@ var commandCodeAdapter = {
|
|
|
73359
73906
|
return JSON.stringify(config4, null, 2);
|
|
73360
73907
|
}
|
|
73361
73908
|
};
|
|
73909
|
+
var copilotAdapter = {
|
|
73910
|
+
cli: "GitHub Copilot CLI",
|
|
73911
|
+
get configPath() {
|
|
73912
|
+
return (0, import_node_path33.join)(homeDirectory(), ".copilot", "mcp-config.json");
|
|
73913
|
+
},
|
|
73914
|
+
get guardDir() {
|
|
73915
|
+
return (0, import_node_path33.join)(homeDirectory(), ".copilot");
|
|
73916
|
+
},
|
|
73917
|
+
merge(existing, servers) {
|
|
73918
|
+
const config4 = parseJsonSafe(existing);
|
|
73919
|
+
const mcpServers = config4.mcpServers ?? {};
|
|
73920
|
+
for (const s of servers) {
|
|
73921
|
+
if (s.kind === "http") {
|
|
73922
|
+
mcpServers[s.name] = {
|
|
73923
|
+
type: "http",
|
|
73924
|
+
url: s.url,
|
|
73925
|
+
tools: ["*"],
|
|
73926
|
+
headers: s.headers
|
|
73927
|
+
};
|
|
73928
|
+
} else {
|
|
73929
|
+
mcpServers[s.name] = {
|
|
73930
|
+
type: "stdio",
|
|
73931
|
+
command: s.command,
|
|
73932
|
+
tools: ["*"],
|
|
73933
|
+
...s.args?.length ? { args: s.args } : {},
|
|
73934
|
+
...s.env && Object.keys(s.env).length > 0 ? { env: s.env } : {}
|
|
73935
|
+
};
|
|
73936
|
+
}
|
|
73937
|
+
}
|
|
73938
|
+
config4.mcpServers = mcpServers;
|
|
73939
|
+
return JSON.stringify(config4, null, 2);
|
|
73940
|
+
},
|
|
73941
|
+
remove(existing, serverNames) {
|
|
73942
|
+
const config4 = parseJsonSafe(existing);
|
|
73943
|
+
const mcpServers = config4.mcpServers ?? {};
|
|
73944
|
+
for (const name of serverNames) delete mcpServers[name];
|
|
73945
|
+
config4.mcpServers = mcpServers;
|
|
73946
|
+
return JSON.stringify(config4, null, 2);
|
|
73947
|
+
}
|
|
73948
|
+
};
|
|
73949
|
+
var grokAdapter = {
|
|
73950
|
+
cli: "Grok CLI",
|
|
73951
|
+
get configPath() {
|
|
73952
|
+
return (0, import_node_path33.join)(homeDirectory(), ".grok", "config.toml");
|
|
73953
|
+
},
|
|
73954
|
+
get guardDir() {
|
|
73955
|
+
return (0, import_node_path33.join)(homeDirectory(), ".grok");
|
|
73956
|
+
},
|
|
73957
|
+
merge(existing, servers) {
|
|
73958
|
+
let config4 = {};
|
|
73959
|
+
if (existing) {
|
|
73960
|
+
try {
|
|
73961
|
+
config4 = parse4(existing);
|
|
73962
|
+
} catch {
|
|
73963
|
+
throw new MalformedToolConfigError("Existing tool config is malformed");
|
|
73964
|
+
}
|
|
73965
|
+
}
|
|
73966
|
+
const mcpServers = config4.mcp_servers ?? {};
|
|
73967
|
+
for (const s of servers) {
|
|
73968
|
+
if (s.kind === "http") {
|
|
73969
|
+
mcpServers[s.name] = {
|
|
73970
|
+
url: s.url,
|
|
73971
|
+
...Object.keys(s.headers).length > 0 ? { headers: s.headers } : {}
|
|
73972
|
+
};
|
|
73973
|
+
} else {
|
|
73974
|
+
mcpServers[s.name] = {
|
|
73975
|
+
command: s.command,
|
|
73976
|
+
...s.args?.length ? { args: s.args } : {},
|
|
73977
|
+
...s.env && Object.keys(s.env).length > 0 ? { env: s.env } : {}
|
|
73978
|
+
};
|
|
73979
|
+
}
|
|
73980
|
+
}
|
|
73981
|
+
config4.mcp_servers = mcpServers;
|
|
73982
|
+
return stringify(config4);
|
|
73983
|
+
},
|
|
73984
|
+
remove(existing, serverNames) {
|
|
73985
|
+
if (!existing) return "";
|
|
73986
|
+
let config4 = {};
|
|
73987
|
+
try {
|
|
73988
|
+
config4 = parse4(existing);
|
|
73989
|
+
} catch {
|
|
73990
|
+
return existing;
|
|
73991
|
+
}
|
|
73992
|
+
const mcpServers = config4.mcp_servers ?? {};
|
|
73993
|
+
for (const name of serverNames) delete mcpServers[name];
|
|
73994
|
+
config4.mcp_servers = mcpServers;
|
|
73995
|
+
return stringify(config4);
|
|
73996
|
+
}
|
|
73997
|
+
};
|
|
73362
73998
|
var ALL_ADAPTERS = [
|
|
73363
73999
|
claudeAdapter,
|
|
73364
74000
|
codexAdapter,
|
|
@@ -73369,10 +74005,12 @@ var ALL_ADAPTERS = [
|
|
|
73369
74005
|
commandCodeAdapter,
|
|
73370
74006
|
opencodeAdapter,
|
|
73371
74007
|
factoryAdapter,
|
|
73372
|
-
ampAdapter
|
|
74008
|
+
ampAdapter,
|
|
74009
|
+
copilotAdapter,
|
|
74010
|
+
grokAdapter
|
|
73373
74011
|
];
|
|
73374
74012
|
function serverEntry(adapter, content, name) {
|
|
73375
|
-
if (adapter === codexAdapter) {
|
|
74013
|
+
if (adapter === codexAdapter || adapter === grokAdapter) {
|
|
73376
74014
|
const parsed2 = parse4(content);
|
|
73377
74015
|
const servers2 = parsed2.mcp_servers;
|
|
73378
74016
|
return servers2 && typeof servers2 === "object" ? servers2[name] : void 0;
|
|
@@ -73551,7 +74189,7 @@ function syncMcpToAllClis(servers, oldManagedServers = []) {
|
|
|
73551
74189
|
const written = [];
|
|
73552
74190
|
const failures = [];
|
|
73553
74191
|
for (const adapter of ALL_ADAPTERS) {
|
|
73554
|
-
if (!(0,
|
|
74192
|
+
if (!(0, import_node_fs31.existsSync)(adapter.guardDir)) {
|
|
73555
74193
|
log2.debug("MCP Adapters", `Skipping ${adapter.cli} \u2014 guard dir not found`, {
|
|
73556
74194
|
guardDir: adapter.guardDir
|
|
73557
74195
|
});
|
|
@@ -73631,7 +74269,7 @@ function removeMcpFromAllClis(managedServers) {
|
|
|
73631
74269
|
if (managedServers.length === 0) return;
|
|
73632
74270
|
const ownershipKnown = isManagedServerList(managedServers);
|
|
73633
74271
|
for (const adapter of ALL_ADAPTERS) {
|
|
73634
|
-
if (!(0,
|
|
74272
|
+
if (!(0, import_node_fs31.existsSync)(adapter.guardDir)) continue;
|
|
73635
74273
|
const releaseLock = acquireConfigLock(adapter.configPath);
|
|
73636
74274
|
try {
|
|
73637
74275
|
const existing = readFileOr(adapter.configPath);
|
|
@@ -73670,7 +74308,7 @@ function inspectAlanMcpPresence(expectedServers = [], candidateNames = DEFAULT_A
|
|
|
73670
74308
|
]);
|
|
73671
74309
|
const expectedByName = new Map(expectedServers.map((server) => [server.name, server]));
|
|
73672
74310
|
for (const adapter of ALL_ADAPTERS) {
|
|
73673
|
-
if (!(0,
|
|
74311
|
+
if (!(0, import_node_fs31.existsSync)(adapter.guardDir)) continue;
|
|
73674
74312
|
inspectedClis.push(adapter.cli);
|
|
73675
74313
|
const existing = readFileOr(adapter.configPath);
|
|
73676
74314
|
if (!existing) continue;
|
|
@@ -73781,11 +74419,11 @@ var McpSyncService = class {
|
|
|
73781
74419
|
};
|
|
73782
74420
|
|
|
73783
74421
|
// src/cli/ingestion-hooks.ts
|
|
73784
|
-
var
|
|
74422
|
+
var import_node_fs33 = require("fs");
|
|
73785
74423
|
var import_node_path35 = require("path");
|
|
73786
74424
|
|
|
73787
74425
|
// src/native/hook-config.ts
|
|
73788
|
-
var
|
|
74426
|
+
var import_node_fs32 = require("fs");
|
|
73789
74427
|
var import_node_os19 = require("os");
|
|
73790
74428
|
var import_node_path34 = require("path");
|
|
73791
74429
|
var INGESTION_HOOK_MARKER = "# alan-session-ingest";
|
|
@@ -73854,9 +74492,9 @@ function hookHandler(provider, event, options) {
|
|
|
73854
74492
|
return { type: "command", command: posixCommand(argv, environment), timeout: 5 };
|
|
73855
74493
|
}
|
|
73856
74494
|
function readSettings2(path2, backupWhenMalformed) {
|
|
73857
|
-
if (!(0,
|
|
74495
|
+
if (!(0, import_node_fs32.existsSync)(path2)) return {};
|
|
73858
74496
|
try {
|
|
73859
|
-
const value2 = JSON.parse((0,
|
|
74497
|
+
const value2 = JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8"));
|
|
73860
74498
|
if (!isRecord7(value2)) throw new Error("settings root must be an object");
|
|
73861
74499
|
if (value2.hooks !== void 0 && !isRecord7(value2.hooks)) {
|
|
73862
74500
|
throw new Error("settings `hooks` must be an object");
|
|
@@ -73866,7 +74504,7 @@ function readSettings2(path2, backupWhenMalformed) {
|
|
|
73866
74504
|
const reason = error61 instanceof Error ? error61.message : String(error61);
|
|
73867
74505
|
if (!backupWhenMalformed) throw new Error(`${path2} is malformed: ${reason}`);
|
|
73868
74506
|
const backup = `${path2}.malformed-${Date.now()}.bak`;
|
|
73869
|
-
(0,
|
|
74507
|
+
(0, import_node_fs32.copyFileSync)(path2, backup);
|
|
73870
74508
|
throw new Error(`${path2} is malformed and was copied to ${backup}: ${reason}`);
|
|
73871
74509
|
}
|
|
73872
74510
|
}
|
|
@@ -73874,14 +74512,14 @@ function hooksOf(settings2) {
|
|
|
73874
74512
|
return isRecord7(settings2.hooks) ? settings2.hooks : {};
|
|
73875
74513
|
}
|
|
73876
74514
|
function writeSettings2(path2, settings2) {
|
|
73877
|
-
(0,
|
|
74515
|
+
(0, import_node_fs32.mkdirSync)((0, import_node_path34.dirname)(path2), { recursive: true, mode: 448 });
|
|
73878
74516
|
const temporary = `${path2}.${process.pid}.tmp`;
|
|
73879
74517
|
try {
|
|
73880
|
-
(0,
|
|
74518
|
+
(0, import_node_fs32.writeFileSync)(temporary, `${JSON.stringify(settings2, null, 2)}
|
|
73881
74519
|
`, { mode: 384 });
|
|
73882
|
-
(0,
|
|
74520
|
+
(0, import_node_fs32.renameSync)(temporary, path2);
|
|
73883
74521
|
} finally {
|
|
73884
|
-
(0,
|
|
74522
|
+
(0, import_node_fs32.rmSync)(temporary, { force: true });
|
|
73885
74523
|
}
|
|
73886
74524
|
}
|
|
73887
74525
|
function isIngestionHandler(handler) {
|
|
@@ -73926,7 +74564,7 @@ function installIngestionHooks(provider, options) {
|
|
|
73926
74564
|
}
|
|
73927
74565
|
function removeIngestionHooks(provider, options = {}) {
|
|
73928
74566
|
const path2 = providerHookSettingsPath(provider, options);
|
|
73929
|
-
if (!(0,
|
|
74567
|
+
if (!(0, import_node_fs32.existsSync)(path2)) return { provider, path: path2, changed: false };
|
|
73930
74568
|
const settings2 = readSettings2(path2, true);
|
|
73931
74569
|
const hooks = hooksOf(settings2);
|
|
73932
74570
|
const nextHooks = {};
|
|
@@ -73968,7 +74606,7 @@ function systemNodeProbe(env) {
|
|
|
73968
74606
|
pathEntries: (env.PATH ?? "").split(import_node_path35.delimiter),
|
|
73969
74607
|
realpath: (path2) => {
|
|
73970
74608
|
try {
|
|
73971
|
-
return (0,
|
|
74609
|
+
return (0, import_node_fs33.realpathSync)(path2);
|
|
73972
74610
|
} catch {
|
|
73973
74611
|
return null;
|
|
73974
74612
|
}
|
|
@@ -74357,7 +74995,7 @@ var agentProbeAckSchema = external_exports.object({
|
|
|
74357
74995
|
});
|
|
74358
74996
|
|
|
74359
74997
|
// src/resource-diagnostics.ts
|
|
74360
|
-
var
|
|
74998
|
+
var import_node_fs34 = require("fs");
|
|
74361
74999
|
var import_node_os20 = require("os");
|
|
74362
75000
|
var import_node_path36 = require("path");
|
|
74363
75001
|
var import_node_perf_hooks = require("perf_hooks");
|
|
@@ -74365,7 +75003,7 @@ var MAX_RESOURCE_FILE_BYTES = 16384;
|
|
|
74365
75003
|
var RESOURCE_READ_TIMEOUT_MS = 500;
|
|
74366
75004
|
async function readResourceFile(path2) {
|
|
74367
75005
|
try {
|
|
74368
|
-
const stream = (0,
|
|
75006
|
+
const stream = (0, import_node_fs34.createReadStream)(path2, {
|
|
74369
75007
|
encoding: "utf8",
|
|
74370
75008
|
start: 0,
|
|
74371
75009
|
end: MAX_RESOURCE_FILE_BYTES,
|
|
@@ -75503,7 +76141,7 @@ var ExecutionLeaseClient = class {
|
|
|
75503
76141
|
}
|
|
75504
76142
|
const takeoverPending = response.status === 409 && code === "EXECUTION_LEASE_TAKEOVER_PENDING";
|
|
75505
76143
|
const mixedVersionUnavailable = (response.status === 401 || response.status === 403 || response.status === 404) && !code?.startsWith("EXECUTION_LEASE_");
|
|
75506
|
-
const retryable = takeoverPending || mixedVersionUnavailable ||
|
|
76144
|
+
const retryable = takeoverPending || mixedVersionUnavailable || isRetryableStatus2(response.status);
|
|
75507
76145
|
if (!retryable || attempt === this.retryDelaysMs.length) {
|
|
75508
76146
|
if (response.status === 404 && !code && this.isCurrentRun(activity, activityGeneration)) {
|
|
75509
76147
|
this.protectionMode = "legacy";
|
|
@@ -75559,7 +76197,7 @@ async function readProtectionBody(response) {
|
|
|
75559
76197
|
return {};
|
|
75560
76198
|
}
|
|
75561
76199
|
}
|
|
75562
|
-
function
|
|
76200
|
+
function isRetryableStatus2(status2) {
|
|
75563
76201
|
return status2 === 408 || status2 === 429 || status2 >= 500;
|
|
75564
76202
|
}
|
|
75565
76203
|
async function readErrorBody(response) {
|