chatroom-cli 1.65.2 → 1.65.4
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.js +712 -243
- package/dist/index.js.map +30 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32368,6 +32368,13 @@ async function withTimeout(p, ms, label) {
|
|
|
32368
32368
|
}
|
|
32369
32369
|
|
|
32370
32370
|
// src/infrastructure/services/remote-agents/claude-sdk/claude-sdk-package.ts
|
|
32371
|
+
var exports_claude_sdk_package = {};
|
|
32372
|
+
__export(exports_claude_sdk_package, {
|
|
32373
|
+
resolvePathToClaudeCodeExecutable: () => resolvePathToClaudeCodeExecutable,
|
|
32374
|
+
importBundledClaudeSdk: () => importBundledClaudeSdk,
|
|
32375
|
+
getBundledClaudeSdkVersion: () => getBundledClaudeSdkVersion,
|
|
32376
|
+
formatClaudeSdkLoadError: () => formatClaudeSdkLoadError
|
|
32377
|
+
});
|
|
32371
32378
|
import { existsSync, readFileSync as readFileSync3 } from "node:fs";
|
|
32372
32379
|
import { createRequire as createRequire3 } from "node:module";
|
|
32373
32380
|
import { dirname as dirname2, join as join7 } from "node:path";
|
|
@@ -33522,6 +33529,8 @@ var init_cursor_sdk_stream_adapter = __esm(() => {
|
|
|
33522
33529
|
case "task":
|
|
33523
33530
|
this.writeLine(formatAgentLogLine(this.logPrefix, "task", [message.status, message.text].filter(Boolean).join(": ")));
|
|
33524
33531
|
break;
|
|
33532
|
+
case "usage":
|
|
33533
|
+
break;
|
|
33525
33534
|
default: {
|
|
33526
33535
|
const unknown = message;
|
|
33527
33536
|
if (unknown.type) {
|
|
@@ -36100,9 +36109,6 @@ function selectAgent(agents) {
|
|
|
36100
36109
|
}
|
|
36101
36110
|
|
|
36102
36111
|
// src/domain/agent-lifecycle/policies/terminal-provider-error.ts
|
|
36103
|
-
function isProviderRateLimitHarnessMarker(line) {
|
|
36104
|
-
return PROVIDER_RATE_LIMIT_AGENT_END_MARKER.test(line);
|
|
36105
|
-
}
|
|
36106
36112
|
function matchesQuotaPhrase(blob) {
|
|
36107
36113
|
const text = blob.toLowerCase();
|
|
36108
36114
|
return QUOTA_PHRASES.some((phrase) => text.includes(phrase));
|
|
@@ -36137,30 +36143,6 @@ function isTerminalProviderError(error) {
|
|
|
36137
36143
|
const message = extractMessage(e);
|
|
36138
36144
|
return matchesQuotaPhrase(message) || matchesQuotaPhrase(`${name} ${message}`) || matchesFatalHarnessErrorText(message) || matchesFatalHarnessErrorText(`${name} ${message}`);
|
|
36139
36145
|
}
|
|
36140
|
-
function isTerminalProviderFailureInLogs(logLines) {
|
|
36141
|
-
for (const line of logLines) {
|
|
36142
|
-
if (!isClassifiableHarnessLogLine(line))
|
|
36143
|
-
continue;
|
|
36144
|
-
if (isProviderRateLimitHarnessMarker(line))
|
|
36145
|
-
return true;
|
|
36146
|
-
if (isNonRetryableHarnessFailureText(line))
|
|
36147
|
-
return true;
|
|
36148
|
-
}
|
|
36149
|
-
return false;
|
|
36150
|
-
}
|
|
36151
|
-
function isClassifiableHarnessLogLine(line) {
|
|
36152
|
-
if (/\b(?:text|thinking)\]/.test(line))
|
|
36153
|
-
return false;
|
|
36154
|
-
if (line.includes("agent_end]"))
|
|
36155
|
-
return true;
|
|
36156
|
-
if (line.includes("spawn-error]"))
|
|
36157
|
-
return true;
|
|
36158
|
-
if (line.includes(" error]"))
|
|
36159
|
-
return true;
|
|
36160
|
-
if (line.includes(" run-error]"))
|
|
36161
|
-
return true;
|
|
36162
|
-
return false;
|
|
36163
|
-
}
|
|
36164
36146
|
function extractName(e) {
|
|
36165
36147
|
const name = e.name;
|
|
36166
36148
|
if (typeof name === "string")
|
|
@@ -36191,12 +36173,7 @@ function messageFromData(data) {
|
|
|
36191
36173
|
const msg = data.message;
|
|
36192
36174
|
return typeof msg === "string" ? msg.toLowerCase() : undefined;
|
|
36193
36175
|
}
|
|
36194
|
-
|
|
36195
|
-
const blob = logLines.join(`
|
|
36196
|
-
`).trim();
|
|
36197
|
-
return blob ? `Fatal harness error (non-retryable): ${blob.slice(-500)}` : "Fatal harness error (non-retryable)";
|
|
36198
|
-
}
|
|
36199
|
-
var FATAL_HARNESS_PHRASES, QUOTA_PHRASES, PROVIDER_ERROR_NAMES, PROVIDER_RATE_LIMIT_AGENT_END_MARKER;
|
|
36176
|
+
var FATAL_HARNESS_PHRASES, QUOTA_PHRASES, PROVIDER_ERROR_NAMES;
|
|
36200
36177
|
var init_terminal_provider_error = __esm(() => {
|
|
36201
36178
|
FATAL_HARNESS_PHRASES = [
|
|
36202
36179
|
"failed to load model",
|
|
@@ -36217,7 +36194,6 @@ var init_terminal_provider_error = __esm(() => {
|
|
|
36217
36194
|
"exceeded your weekly"
|
|
36218
36195
|
];
|
|
36219
36196
|
PROVIDER_ERROR_NAMES = ["ai_apicallerror", "ai_retryerror"];
|
|
36220
|
-
PROVIDER_RATE_LIMIT_AGENT_END_MARKER = /\bagent_end]\s*reason:\s*provider_rate_limit\b/;
|
|
36221
36197
|
});
|
|
36222
36198
|
|
|
36223
36199
|
// src/infrastructure/services/remote-agents/opencode-sdk/session-event-forwarder.ts
|
|
@@ -36269,10 +36245,12 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36269
36245
|
let doneResolve;
|
|
36270
36246
|
let sessionStarted = false;
|
|
36271
36247
|
let terminalAbortRequested = false;
|
|
36248
|
+
let agentEndEmitted = false;
|
|
36272
36249
|
const seenToolStates = new Map;
|
|
36273
36250
|
let lastStatus;
|
|
36274
36251
|
const agentEndCallbacks = [];
|
|
36275
36252
|
const recentLogLines = [];
|
|
36253
|
+
let retryIdleTimeout;
|
|
36276
36254
|
const donePromise = new Promise((resolve2) => {
|
|
36277
36255
|
doneResolve = resolve2;
|
|
36278
36256
|
});
|
|
@@ -36295,7 +36273,26 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36295
36273
|
options.onActivity?.();
|
|
36296
36274
|
}
|
|
36297
36275
|
}
|
|
36276
|
+
function clearRetryIdleTimeout() {
|
|
36277
|
+
if (retryIdleTimeout !== undefined) {
|
|
36278
|
+
clearTimeout(retryIdleTimeout);
|
|
36279
|
+
retryIdleTimeout = undefined;
|
|
36280
|
+
}
|
|
36281
|
+
}
|
|
36282
|
+
function scheduleRetryIdleTimeout() {
|
|
36283
|
+
clearRetryIdleTimeout();
|
|
36284
|
+
const timeoutMs = options.sessionRetryIdleTimeoutMs ?? DEFAULT_SESSION_RETRY_IDLE_TIMEOUT_MS;
|
|
36285
|
+
retryIdleTimeout = setTimeout(() => {
|
|
36286
|
+
if (cancelled || terminalAbortRequested)
|
|
36287
|
+
return;
|
|
36288
|
+
logLine(target, "status", "retry_timeout");
|
|
36289
|
+
emitAgentEnd();
|
|
36290
|
+
}, timeoutMs);
|
|
36291
|
+
}
|
|
36298
36292
|
function emitAgentEnd(reason) {
|
|
36293
|
+
if (agentEndEmitted)
|
|
36294
|
+
return;
|
|
36295
|
+
agentEndEmitted = true;
|
|
36299
36296
|
logLine(target, "agent_end", reason ? `reason: ${reason}` : undefined);
|
|
36300
36297
|
for (const cb of agentEndCallbacks)
|
|
36301
36298
|
cb();
|
|
@@ -36338,11 +36335,6 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36338
36335
|
if (chunk2)
|
|
36339
36336
|
logLine(target, "thinking", chunk2);
|
|
36340
36337
|
}
|
|
36341
|
-
async function handleToolPartUpdate(part, props, toolStates) {
|
|
36342
|
-
if (!part.tool)
|
|
36343
|
-
return;
|
|
36344
|
-
await handleToolPart(part, props, toolStates);
|
|
36345
|
-
}
|
|
36346
36338
|
async function handlePartUpdated(props) {
|
|
36347
36339
|
const part = props.part;
|
|
36348
36340
|
const partType = part?.type;
|
|
@@ -36351,7 +36343,7 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36351
36343
|
const dispatch = {
|
|
36352
36344
|
text: () => handleTextPartUpdate(props, part),
|
|
36353
36345
|
reasoning: () => handleReasoningPartUpdate(props, part),
|
|
36354
|
-
tool: () =>
|
|
36346
|
+
tool: () => part.tool ? handleToolPart(part, props, seenToolStates) : Promise.resolve()
|
|
36355
36347
|
};
|
|
36356
36348
|
await dispatch[partType]?.();
|
|
36357
36349
|
}
|
|
@@ -36385,6 +36377,7 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36385
36377
|
logLine(target, "file", formatFilePayload(props));
|
|
36386
36378
|
}
|
|
36387
36379
|
async function handleSessionIdle() {
|
|
36380
|
+
clearRetryIdleTimeout();
|
|
36388
36381
|
if (terminalAbortRequested)
|
|
36389
36382
|
return;
|
|
36390
36383
|
emitAgentEnd();
|
|
@@ -36397,9 +36390,15 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36397
36390
|
if (currentStatus !== lastStatus) {
|
|
36398
36391
|
lastStatus = currentStatus;
|
|
36399
36392
|
logLine(target, "status", currentStatus);
|
|
36400
|
-
if (currentStatus === "retry"
|
|
36401
|
-
|
|
36393
|
+
if (currentStatus === "retry") {
|
|
36394
|
+
if (terminalAbortRequested) {
|
|
36395
|
+
abortTerminalProviderError();
|
|
36396
|
+
return;
|
|
36397
|
+
}
|
|
36398
|
+
scheduleRetryIdleTimeout();
|
|
36399
|
+
return;
|
|
36402
36400
|
}
|
|
36401
|
+
clearRetryIdleTimeout();
|
|
36403
36402
|
}
|
|
36404
36403
|
}
|
|
36405
36404
|
async function handleSessionError(props) {
|
|
@@ -36484,6 +36483,7 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36484
36483
|
return {
|
|
36485
36484
|
stop: () => {
|
|
36486
36485
|
cancelled = true;
|
|
36486
|
+
clearRetryIdleTimeout();
|
|
36487
36487
|
},
|
|
36488
36488
|
done: donePromise,
|
|
36489
36489
|
onAgentEnd: (cb) => {
|
|
@@ -36492,9 +36492,10 @@ function startSessionEventForwarder(client4, options) {
|
|
|
36492
36492
|
abortTerminalProviderError
|
|
36493
36493
|
};
|
|
36494
36494
|
}
|
|
36495
|
-
var RECENT_LOG_LINE_CAP = 20;
|
|
36495
|
+
var RECENT_LOG_LINE_CAP = 20, DEFAULT_SESSION_RETRY_IDLE_TIMEOUT_MS;
|
|
36496
36496
|
var init_session_event_forwarder = __esm(() => {
|
|
36497
36497
|
init_terminal_provider_error();
|
|
36498
|
+
DEFAULT_SESSION_RETRY_IDLE_TIMEOUT_MS = 5 * 60 * 1000;
|
|
36498
36499
|
});
|
|
36499
36500
|
|
|
36500
36501
|
// src/infrastructure/services/remote-agents/opencode-sdk/session-metadata-store.ts
|
|
@@ -36594,7 +36595,6 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36594
36595
|
init_parse_listening_url();
|
|
36595
36596
|
init_session_event_forwarder();
|
|
36596
36597
|
init_session_metadata_store();
|
|
36597
|
-
init_terminal_provider_error();
|
|
36598
36598
|
OpenCodeSdkAgentService = class OpenCodeSdkAgentService extends OpenCodeBinaryAgentService {
|
|
36599
36599
|
agentEndCallbacksByPid = new Map;
|
|
36600
36600
|
assistantTextCallbacksByPid = new Map;
|
|
@@ -36678,10 +36678,6 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36678
36678
|
if (childProcess.stderr) {
|
|
36679
36679
|
const stderrBuffer = new StderrLineBuffer((line) => {
|
|
36680
36680
|
emitLogLine(line);
|
|
36681
|
-
const activeForwarder = this.forwarders.get(pid);
|
|
36682
|
-
if (activeForwarder && isNonRetryableHarnessFailureText(line)) {
|
|
36683
|
-
activeForwarder.abortTerminalProviderError();
|
|
36684
|
-
}
|
|
36685
36681
|
});
|
|
36686
36682
|
childProcess.stderr.on("data", (chunk2) => {
|
|
36687
36683
|
entry.lastOutputAt = Date.now();
|
|
@@ -36694,6 +36690,18 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36694
36690
|
});
|
|
36695
36691
|
}
|
|
36696
36692
|
}
|
|
36693
|
+
createSessionForwarder(client4, sessionId, context5, emitLogLine, emitAssistantText, outputCallbacks) {
|
|
36694
|
+
return startSessionEventForwarder(client4, {
|
|
36695
|
+
sessionId,
|
|
36696
|
+
role: context5.role,
|
|
36697
|
+
onLogLine: emitLogLine,
|
|
36698
|
+
onAssistantText: emitAssistantText,
|
|
36699
|
+
onActivity: () => {
|
|
36700
|
+
for (const cb of outputCallbacks)
|
|
36701
|
+
cb();
|
|
36702
|
+
}
|
|
36703
|
+
});
|
|
36704
|
+
}
|
|
36697
36705
|
registerRunningSession(args2) {
|
|
36698
36706
|
const {
|
|
36699
36707
|
childProcess,
|
|
@@ -36884,16 +36892,7 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36884
36892
|
if (!sessionInfo.data?.id) {
|
|
36885
36893
|
throw new Error(`OpenCode session ${sessionId} not found (sessions may not survive serve restart)`);
|
|
36886
36894
|
}
|
|
36887
|
-
forwarder =
|
|
36888
|
-
sessionId,
|
|
36889
|
-
role: context5.role,
|
|
36890
|
-
onLogLine: emitLogLine,
|
|
36891
|
-
onAssistantText: emitAssistantText,
|
|
36892
|
-
onActivity: () => {
|
|
36893
|
-
for (const cb of outputCallbacks)
|
|
36894
|
-
cb();
|
|
36895
|
-
}
|
|
36896
|
-
});
|
|
36895
|
+
forwarder = this.createSessionForwarder(client4, sessionId, context5, emitLogLine, emitAssistantText, outputCallbacks);
|
|
36897
36896
|
const availableAgents = await this.listAvailableAgents(client4);
|
|
36898
36897
|
const agentDef = availableAgents.find((a) => a.name === agentName);
|
|
36899
36898
|
const composedSystem = composeSystemPrompt(agentDef?.prompt, systemPrompt);
|
|
@@ -36941,16 +36940,7 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36941
36940
|
throw new Error("Failed to create session");
|
|
36942
36941
|
}
|
|
36943
36942
|
sessionId = sessionCreateResult.data.id;
|
|
36944
|
-
forwarder =
|
|
36945
|
-
sessionId,
|
|
36946
|
-
role: context5.role,
|
|
36947
|
-
onLogLine: emitLogLine,
|
|
36948
|
-
onAssistantText: emitAssistantText,
|
|
36949
|
-
onActivity: () => {
|
|
36950
|
-
for (const cb of outputCallbacks)
|
|
36951
|
-
cb();
|
|
36952
|
-
}
|
|
36953
|
-
});
|
|
36943
|
+
forwarder = this.createSessionForwarder(client4, sessionId, context5, emitLogLine, emitAssistantText, outputCallbacks);
|
|
36954
36944
|
const availableAgents = await this.listAvailableAgents(client4);
|
|
36955
36945
|
const selected = selectAgent(availableAgents);
|
|
36956
36946
|
agentName = selected.name;
|
|
@@ -37772,10 +37762,17 @@ var init_detection = __esm(() => {
|
|
|
37772
37762
|
var MACHINE_CONFIG_VERSION = "1";
|
|
37773
37763
|
|
|
37774
37764
|
// src/infrastructure/machine/storage.ts
|
|
37775
|
-
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
37765
|
+
import { randomBytes, randomUUID as randomUUID3 } from "node:crypto";
|
|
37776
37766
|
import * as fs4 from "node:fs/promises";
|
|
37777
37767
|
import { homedir as homedir3, hostname as hostname2 } from "node:os";
|
|
37778
37768
|
import { join as join11 } from "node:path";
|
|
37769
|
+
function enqueueMachineConfigSave(task) {
|
|
37770
|
+
const run3 = saveChain.then(task, task);
|
|
37771
|
+
saveChain = run3.catch(() => {
|
|
37772
|
+
return;
|
|
37773
|
+
});
|
|
37774
|
+
return run3;
|
|
37775
|
+
}
|
|
37779
37776
|
function chatroomConfigDir() {
|
|
37780
37777
|
return join11(homedir3(), ".chatroom");
|
|
37781
37778
|
}
|
|
@@ -37801,13 +37798,20 @@ async function loadConfigFile() {
|
|
|
37801
37798
|
return null;
|
|
37802
37799
|
}
|
|
37803
37800
|
}
|
|
37804
|
-
async function
|
|
37801
|
+
async function writeConfigFileAtomically(configFile) {
|
|
37805
37802
|
await ensureConfigDir2();
|
|
37806
37803
|
const configPath = getMachineConfigPath();
|
|
37807
|
-
const tempPath = `${configPath}.tmp`;
|
|
37804
|
+
const tempPath = `${configPath}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
|
|
37808
37805
|
const content = JSON.stringify(configFile, null, 2);
|
|
37809
37806
|
await fs4.writeFile(tempPath, content, { mode: 384 });
|
|
37810
|
-
|
|
37807
|
+
try {
|
|
37808
|
+
await fs4.rename(tempPath, configPath);
|
|
37809
|
+
} catch (error) {
|
|
37810
|
+
await fs4.unlink(tempPath).catch(() => {
|
|
37811
|
+
return;
|
|
37812
|
+
});
|
|
37813
|
+
throw error;
|
|
37814
|
+
}
|
|
37811
37815
|
}
|
|
37812
37816
|
async function loadMachineConfig() {
|
|
37813
37817
|
const configFile = await loadConfigFile();
|
|
@@ -37817,13 +37821,15 @@ async function loadMachineConfig() {
|
|
|
37817
37821
|
return configFile.machines[convexUrl] ?? null;
|
|
37818
37822
|
}
|
|
37819
37823
|
async function saveMachineConfig(config2) {
|
|
37820
|
-
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
|
|
37824
|
-
|
|
37825
|
-
|
|
37826
|
-
|
|
37824
|
+
await enqueueMachineConfigSave(async () => {
|
|
37825
|
+
const configFile = await loadConfigFile() ?? {
|
|
37826
|
+
version: MACHINE_CONFIG_VERSION,
|
|
37827
|
+
machines: {}
|
|
37828
|
+
};
|
|
37829
|
+
const convexUrl = getConvexUrl();
|
|
37830
|
+
configFile.machines[convexUrl] = config2;
|
|
37831
|
+
await writeConfigFileAtomically(configFile);
|
|
37832
|
+
});
|
|
37827
37833
|
}
|
|
37828
37834
|
async function createNewEndpointConfig() {
|
|
37829
37835
|
const now = new Date().toISOString();
|
|
@@ -37867,10 +37873,11 @@ async function getMachineId() {
|
|
|
37867
37873
|
const config2 = await loadMachineConfig();
|
|
37868
37874
|
return config2?.machineId ?? null;
|
|
37869
37875
|
}
|
|
37870
|
-
var MACHINE_FILE = "machine.json";
|
|
37876
|
+
var MACHINE_FILE = "machine.json", saveChain;
|
|
37871
37877
|
var init_storage2 = __esm(() => {
|
|
37872
37878
|
init_detection();
|
|
37873
37879
|
init_client2();
|
|
37880
|
+
saveChain = Promise.resolve();
|
|
37874
37881
|
});
|
|
37875
37882
|
|
|
37876
37883
|
// src/infrastructure/machine/daemon-state.ts
|
|
@@ -80480,6 +80487,8 @@ ${getRoleGuidanceDisclosureBlock(roleGuidanceContext)}
|
|
|
80480
80487
|
<!-- Demonstrate adherence to:
|
|
80481
80488
|
- Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
|
|
80482
80489
|
- Static Evaluability and Provability: the system's behavior should be provably correct by looking at the source code, then automated tests, then manual tests, in this order.
|
|
80490
|
+
- No Revisit: implemented in a way so the user does not have to revisit this implementation again.
|
|
80491
|
+
- Leave It Better: leave the code in a slightly better state than before when touching files.
|
|
80483
80492
|
-->
|
|
80484
80493
|
<how this work follows the principles above — localized changes, readable structure, correctness provable from source then tests>
|
|
80485
80494
|
|
|
@@ -80641,6 +80650,8 @@ ${getRoleGuidanceDisclosureBlock(roleGuidanceContext)}
|
|
|
80641
80650
|
<!-- Demonstrate adherence to:
|
|
80642
80651
|
- Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
|
|
80643
80652
|
- Static Evaluability and Provability: the system's behavior should be provably correct by looking at the source code, then automated tests, then manual tests, in this order.
|
|
80653
|
+
- No Revisit: implemented in a way so the user does not have to revisit this implementation again.
|
|
80654
|
+
- Leave It Better: leave the code in a slightly better state than before when touching files.
|
|
80644
80655
|
-->
|
|
80645
80656
|
<how this work follows the principles above — localized changes, readable structure, correctness provable from source then tests>
|
|
80646
80657
|
|
|
@@ -80741,6 +80752,8 @@ ${getRoleGuidanceDisclosureBlock(roleGuidanceContext)}
|
|
|
80741
80752
|
<!-- Demonstrate adherence to:
|
|
80742
80753
|
- Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
|
|
80743
80754
|
- Static Evaluability and Provability: the system's behavior should be provably correct by looking at the source code, then automated tests, then manual tests, in this order.
|
|
80755
|
+
- No Revisit: implemented in a way so the user does not have to revisit this implementation again.
|
|
80756
|
+
- Leave It Better: leave the code in a slightly better state than before when touching files.
|
|
80744
80757
|
-->
|
|
80745
80758
|
<how this work follows the principles above — localized changes, readable structure, correctness provable from source then tests>
|
|
80746
80759
|
|
|
@@ -84686,6 +84699,7 @@ var DaemonMachineService, DaemonMachineServiceLive = (ops) => exports_Layer.succ
|
|
|
84686
84699
|
recover: () => exports_Effect.promise(() => mgr.recover()),
|
|
84687
84700
|
getSlot: (chatroomId, role) => mgr.getSlot(chatroomId, role),
|
|
84688
84701
|
listActive: () => mgr.listActive(),
|
|
84702
|
+
clearStuckStoppingSlot: (chatroomId, role) => exports_Effect.promise(() => mgr.clearStuckStoppingSlot(chatroomId, role)),
|
|
84689
84703
|
whenTurnEndsIdle: () => exports_Effect.promise(() => mgr.whenTurnEndsIdle()),
|
|
84690
84704
|
resumeTurnForSlot: (args2) => exports_Effect.promise(() => mgr.resumeTurnForSlot(args2)),
|
|
84691
84705
|
setLastInFlightTask: (chatroomId, role, taskId) => exports_Effect.sync(() => mgr.setLastInFlightTask(chatroomId, role, taskId))
|
|
@@ -86028,9 +86042,369 @@ var init_pid = __esm(() => {
|
|
|
86028
86042
|
CHATROOM_DIR4 = join17(homedir6(), ".chatroom");
|
|
86029
86043
|
});
|
|
86030
86044
|
|
|
86031
|
-
// src/infrastructure/harnesses/
|
|
86045
|
+
// src/infrastructure/harnesses/claude-sdk/claude-session.ts
|
|
86032
86046
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
86033
86047
|
|
|
86048
|
+
class ClaudeSdkSession {
|
|
86049
|
+
opencodeSessionId;
|
|
86050
|
+
_sessionTitle;
|
|
86051
|
+
get sessionTitle() {
|
|
86052
|
+
return this._sessionTitle;
|
|
86053
|
+
}
|
|
86054
|
+
cwd;
|
|
86055
|
+
executablePath;
|
|
86056
|
+
query;
|
|
86057
|
+
defaultModel;
|
|
86058
|
+
storedSystemPrompt;
|
|
86059
|
+
onClose;
|
|
86060
|
+
listeners = new Set;
|
|
86061
|
+
closed = false;
|
|
86062
|
+
providerSessionId;
|
|
86063
|
+
resumeOnFirstQuery;
|
|
86064
|
+
isFirstQuery = true;
|
|
86065
|
+
activeQuery;
|
|
86066
|
+
sawTextDelta = false;
|
|
86067
|
+
sawThinkingDelta = false;
|
|
86068
|
+
constructor(options) {
|
|
86069
|
+
this.cwd = options.cwd;
|
|
86070
|
+
this.executablePath = options.executablePath;
|
|
86071
|
+
this.query = options.query;
|
|
86072
|
+
this.opencodeSessionId = options.opencodeSessionId;
|
|
86073
|
+
this._sessionTitle = options.sessionTitle;
|
|
86074
|
+
this.defaultModel = options.defaultModel;
|
|
86075
|
+
this.storedSystemPrompt = options.systemPrompt;
|
|
86076
|
+
this.providerSessionId = options.providerSessionId;
|
|
86077
|
+
this.resumeOnFirstQuery = options.resumeOnFirstQuery ?? false;
|
|
86078
|
+
this.onClose = options.onClose;
|
|
86079
|
+
}
|
|
86080
|
+
setTitle(title) {
|
|
86081
|
+
this._sessionTitle = title;
|
|
86082
|
+
}
|
|
86083
|
+
async prompt(input) {
|
|
86084
|
+
if (this.closed)
|
|
86085
|
+
throw new Error("Session is closed");
|
|
86086
|
+
const text = input.parts.map((p) => p.text).join(`
|
|
86087
|
+
`);
|
|
86088
|
+
const messageId = randomUUID4();
|
|
86089
|
+
const model = resolveClaudeModel(this.defaultModel, input.model);
|
|
86090
|
+
const useResume = Boolean(this.providerSessionId) && (!this.isFirstQuery || this.resumeOnFirstQuery);
|
|
86091
|
+
this.sawTextDelta = false;
|
|
86092
|
+
this.sawThinkingDelta = false;
|
|
86093
|
+
const queryInstance = this.query({
|
|
86094
|
+
prompt: text,
|
|
86095
|
+
options: {
|
|
86096
|
+
cwd: this.cwd,
|
|
86097
|
+
model,
|
|
86098
|
+
maxTurns: DEFAULT_MAX_TURNS3,
|
|
86099
|
+
pathToClaudeCodeExecutable: this.executablePath,
|
|
86100
|
+
includePartialMessages: true,
|
|
86101
|
+
systemPrompt: this.isFirstQuery && !this.resumeOnFirstQuery ? this.storedSystemPrompt : undefined,
|
|
86102
|
+
resume: useResume ? this.providerSessionId : undefined,
|
|
86103
|
+
settingSources: [],
|
|
86104
|
+
permissionMode: "bypassPermissions",
|
|
86105
|
+
allowDangerouslySkipPermissions: true,
|
|
86106
|
+
effort: DEFAULT_EFFORT2,
|
|
86107
|
+
canUseTool: async (_toolName, toolInput) => ({
|
|
86108
|
+
behavior: "allow",
|
|
86109
|
+
updatedInput: toolInput
|
|
86110
|
+
})
|
|
86111
|
+
}
|
|
86112
|
+
});
|
|
86113
|
+
this.activeQuery = queryInstance;
|
|
86114
|
+
if (this.resumeOnFirstQuery) {
|
|
86115
|
+
this.resumeOnFirstQuery = false;
|
|
86116
|
+
}
|
|
86117
|
+
this.isFirstQuery = false;
|
|
86118
|
+
try {
|
|
86119
|
+
await withTimeout((async () => {
|
|
86120
|
+
for await (const message of queryInstance) {
|
|
86121
|
+
if (this.closed)
|
|
86122
|
+
break;
|
|
86123
|
+
this.captureProviderSessionId(message);
|
|
86124
|
+
this.emitFromSdkMessage(message, messageId);
|
|
86125
|
+
if (message.type === "result") {
|
|
86126
|
+
if (message.is_error) {
|
|
86127
|
+
const errors2 = "errors" in message && Array.isArray(message.errors) ? message.errors.join("; ") : "turn failed";
|
|
86128
|
+
throw new Error(errors2);
|
|
86129
|
+
}
|
|
86130
|
+
break;
|
|
86131
|
+
}
|
|
86132
|
+
}
|
|
86133
|
+
})(), QUERY_TIMEOUT_MS, "query");
|
|
86134
|
+
} finally {
|
|
86135
|
+
this.activeQuery = undefined;
|
|
86136
|
+
}
|
|
86137
|
+
this.emit({ type: "session.idle", payload: {}, timestamp: Date.now() });
|
|
86138
|
+
}
|
|
86139
|
+
onEvent(listener) {
|
|
86140
|
+
this.listeners.add(listener);
|
|
86141
|
+
return () => {
|
|
86142
|
+
this.listeners.delete(listener);
|
|
86143
|
+
};
|
|
86144
|
+
}
|
|
86145
|
+
async close() {
|
|
86146
|
+
if (this.closed)
|
|
86147
|
+
return;
|
|
86148
|
+
this.closed = true;
|
|
86149
|
+
try {
|
|
86150
|
+
await this.activeQuery?.interrupt();
|
|
86151
|
+
} catch {}
|
|
86152
|
+
this.activeQuery = undefined;
|
|
86153
|
+
this.onClose?.(this.opencodeSessionId);
|
|
86154
|
+
this.listeners.clear();
|
|
86155
|
+
}
|
|
86156
|
+
emit(event) {
|
|
86157
|
+
for (const listener of this.listeners) {
|
|
86158
|
+
listener(event);
|
|
86159
|
+
}
|
|
86160
|
+
}
|
|
86161
|
+
emitDelta(messageId, delta, partType) {
|
|
86162
|
+
if (!delta)
|
|
86163
|
+
return;
|
|
86164
|
+
this.emit({
|
|
86165
|
+
type: "message.part.delta",
|
|
86166
|
+
payload: { messageID: messageId, delta, partType },
|
|
86167
|
+
timestamp: Date.now()
|
|
86168
|
+
});
|
|
86169
|
+
}
|
|
86170
|
+
captureProviderSessionId(message) {
|
|
86171
|
+
if (!("session_id" in message) || typeof message.session_id !== "string") {
|
|
86172
|
+
return;
|
|
86173
|
+
}
|
|
86174
|
+
const sessionId = message.session_id;
|
|
86175
|
+
if (this.providerSessionId === sessionId) {
|
|
86176
|
+
return;
|
|
86177
|
+
}
|
|
86178
|
+
const isFirstAllocation = !this.providerSessionId;
|
|
86179
|
+
this.providerSessionId = sessionId;
|
|
86180
|
+
if (isFirstAllocation) {
|
|
86181
|
+
this.emit({
|
|
86182
|
+
type: "session.provider_id",
|
|
86183
|
+
payload: { sessionId },
|
|
86184
|
+
timestamp: Date.now()
|
|
86185
|
+
});
|
|
86186
|
+
}
|
|
86187
|
+
}
|
|
86188
|
+
emitFromSdkMessage(message, messageId) {
|
|
86189
|
+
switch (message.type) {
|
|
86190
|
+
case "stream_event": {
|
|
86191
|
+
const event = message.event;
|
|
86192
|
+
if (event.type === "content_block_delta") {
|
|
86193
|
+
const delta = event.delta;
|
|
86194
|
+
if (delta.type === "text_delta") {
|
|
86195
|
+
this.sawTextDelta = true;
|
|
86196
|
+
this.emitDelta(messageId, delta.text, "text");
|
|
86197
|
+
} else if (delta.type === "thinking_delta") {
|
|
86198
|
+
this.sawThinkingDelta = true;
|
|
86199
|
+
this.emitDelta(messageId, delta.thinking, "reasoning");
|
|
86200
|
+
}
|
|
86201
|
+
}
|
|
86202
|
+
break;
|
|
86203
|
+
}
|
|
86204
|
+
case "assistant":
|
|
86205
|
+
for (const block of message.message.content) {
|
|
86206
|
+
if (block.type === "text" && block.text) {
|
|
86207
|
+
if (!this.sawTextDelta) {
|
|
86208
|
+
this.emitDelta(messageId, block.text, "text");
|
|
86209
|
+
}
|
|
86210
|
+
} else if (block.type === "thinking" && block.thinking) {
|
|
86211
|
+
if (!this.sawThinkingDelta) {
|
|
86212
|
+
this.emitDelta(messageId, block.thinking, "reasoning");
|
|
86213
|
+
}
|
|
86214
|
+
}
|
|
86215
|
+
}
|
|
86216
|
+
break;
|
|
86217
|
+
default:
|
|
86218
|
+
break;
|
|
86219
|
+
}
|
|
86220
|
+
}
|
|
86221
|
+
}
|
|
86222
|
+
function resolveClaudeModel(defaultModel, promptModel) {
|
|
86223
|
+
if (promptModel) {
|
|
86224
|
+
if (promptModel.providerID === "anthropic")
|
|
86225
|
+
return promptModel.modelID;
|
|
86226
|
+
return promptModel.modelID;
|
|
86227
|
+
}
|
|
86228
|
+
if (defaultModel) {
|
|
86229
|
+
const slash = defaultModel.indexOf("/");
|
|
86230
|
+
if (slash === -1)
|
|
86231
|
+
return defaultModel;
|
|
86232
|
+
const provider = defaultModel.slice(0, slash);
|
|
86233
|
+
const modelId = defaultModel.slice(slash + 1);
|
|
86234
|
+
if (provider === "anthropic")
|
|
86235
|
+
return modelId;
|
|
86236
|
+
return modelId;
|
|
86237
|
+
}
|
|
86238
|
+
return "sonnet";
|
|
86239
|
+
}
|
|
86240
|
+
var DEFAULT_MAX_TURNS3 = 200, DEFAULT_EFFORT2 = "medium", QUERY_TIMEOUT_MS = 3600000;
|
|
86241
|
+
var init_claude_session = () => {};
|
|
86242
|
+
|
|
86243
|
+
// src/infrastructure/harnesses/claude-sdk/claude-harness.ts
|
|
86244
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
86245
|
+
async function loadSdk4() {
|
|
86246
|
+
if (_sdkCache4)
|
|
86247
|
+
return _sdkCache4;
|
|
86248
|
+
if (_sdkLoadError4)
|
|
86249
|
+
throw _sdkLoadError4;
|
|
86250
|
+
try {
|
|
86251
|
+
_sdkCache4 = await importBundledClaudeSdk();
|
|
86252
|
+
return _sdkCache4;
|
|
86253
|
+
} catch (err) {
|
|
86254
|
+
_sdkLoadError4 = err;
|
|
86255
|
+
throw err;
|
|
86256
|
+
}
|
|
86257
|
+
}
|
|
86258
|
+
async function loadExecutablePath() {
|
|
86259
|
+
if (_executablePathCache)
|
|
86260
|
+
return _executablePathCache;
|
|
86261
|
+
_executablePathCache = await resolvePathToClaudeCodeExecutable();
|
|
86262
|
+
return _executablePathCache;
|
|
86263
|
+
}
|
|
86264
|
+
|
|
86265
|
+
class ClaudeSdkHarness {
|
|
86266
|
+
type = "claude-sdk";
|
|
86267
|
+
displayName = "Claude (SDK)";
|
|
86268
|
+
cwd;
|
|
86269
|
+
query;
|
|
86270
|
+
executablePath;
|
|
86271
|
+
closed = false;
|
|
86272
|
+
sessions = new Map;
|
|
86273
|
+
constructor(cwd, sdk, executablePath) {
|
|
86274
|
+
this.cwd = cwd;
|
|
86275
|
+
this.query = sdk.query;
|
|
86276
|
+
this.executablePath = executablePath;
|
|
86277
|
+
}
|
|
86278
|
+
async models() {
|
|
86279
|
+
const providers = await this.listProviders();
|
|
86280
|
+
const models = [];
|
|
86281
|
+
for (const provider of providers) {
|
|
86282
|
+
for (const model of provider.models) {
|
|
86283
|
+
models.push({
|
|
86284
|
+
id: `${provider.providerID}/${model.modelID}`,
|
|
86285
|
+
name: model.name,
|
|
86286
|
+
provider: provider.name
|
|
86287
|
+
});
|
|
86288
|
+
}
|
|
86289
|
+
}
|
|
86290
|
+
return models;
|
|
86291
|
+
}
|
|
86292
|
+
async listAgents() {
|
|
86293
|
+
return [{ name: "builder", mode: "primary" }];
|
|
86294
|
+
}
|
|
86295
|
+
async listProviders() {
|
|
86296
|
+
const dynamic = await fetchClaudeModels();
|
|
86297
|
+
const modelIds = dynamic ?? [...CLAUDE_FALLBACK_MODELS];
|
|
86298
|
+
return [
|
|
86299
|
+
{
|
|
86300
|
+
providerID: "anthropic",
|
|
86301
|
+
name: "Anthropic",
|
|
86302
|
+
models: modelIds.map((modelID) => ({ modelID, name: modelID }))
|
|
86303
|
+
}
|
|
86304
|
+
];
|
|
86305
|
+
}
|
|
86306
|
+
async newSession(config3) {
|
|
86307
|
+
if (this.closed)
|
|
86308
|
+
throw new Error("Harness is closed");
|
|
86309
|
+
const opencodeSessionId = randomUUID5();
|
|
86310
|
+
const session2 = new ClaudeSdkSession({
|
|
86311
|
+
cwd: this.cwd,
|
|
86312
|
+
executablePath: this.executablePath,
|
|
86313
|
+
query: this.query,
|
|
86314
|
+
opencodeSessionId,
|
|
86315
|
+
sessionTitle: config3.title ?? "",
|
|
86316
|
+
defaultModel: config3.model ?? DEFAULT_MODEL2,
|
|
86317
|
+
systemPrompt: config3.systemPrompt,
|
|
86318
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
86319
|
+
});
|
|
86320
|
+
this.sessions.set(opencodeSessionId, session2);
|
|
86321
|
+
return session2;
|
|
86322
|
+
}
|
|
86323
|
+
async resumeSession(sessionId, _options) {
|
|
86324
|
+
if (this.closed)
|
|
86325
|
+
throw new Error("Harness is closed");
|
|
86326
|
+
const existing = this.sessions.get(sessionId);
|
|
86327
|
+
if (existing)
|
|
86328
|
+
return existing;
|
|
86329
|
+
const session2 = new ClaudeSdkSession({
|
|
86330
|
+
cwd: this.cwd,
|
|
86331
|
+
executablePath: this.executablePath,
|
|
86332
|
+
query: this.query,
|
|
86333
|
+
opencodeSessionId: sessionId,
|
|
86334
|
+
sessionTitle: "",
|
|
86335
|
+
providerSessionId: sessionId,
|
|
86336
|
+
resumeOnFirstQuery: true,
|
|
86337
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
86338
|
+
});
|
|
86339
|
+
this.sessions.set(sessionId, session2);
|
|
86340
|
+
return session2;
|
|
86341
|
+
}
|
|
86342
|
+
async fetchSessionTitle(_opencodeSessionId) {
|
|
86343
|
+
return;
|
|
86344
|
+
}
|
|
86345
|
+
isAlive() {
|
|
86346
|
+
return !this.closed;
|
|
86347
|
+
}
|
|
86348
|
+
async close() {
|
|
86349
|
+
if (this.closed)
|
|
86350
|
+
return;
|
|
86351
|
+
this.closed = true;
|
|
86352
|
+
const closing = [...this.sessions.values()].map((s) => s.close().catch(() => {}));
|
|
86353
|
+
await Promise.all(closing);
|
|
86354
|
+
this.sessions.clear();
|
|
86355
|
+
}
|
|
86356
|
+
}
|
|
86357
|
+
var DEFAULT_MODEL2 = "anthropic/sonnet", _sdkCache4, _sdkLoadError4, _executablePathCache, startClaudeSdkHarness = async (config3) => {
|
|
86358
|
+
try {
|
|
86359
|
+
const sdk = await loadSdk4();
|
|
86360
|
+
const executablePath = await loadExecutablePath();
|
|
86361
|
+
return new ClaudeSdkHarness(config3.workingDir, sdk, executablePath);
|
|
86362
|
+
} catch (err) {
|
|
86363
|
+
throw new Error(`claude-sdk unavailable: ${formatClaudeSdkLoadError(err)}`);
|
|
86364
|
+
}
|
|
86365
|
+
};
|
|
86366
|
+
var init_claude_harness = __esm(() => {
|
|
86367
|
+
init_claude_session();
|
|
86368
|
+
init_claude_models();
|
|
86369
|
+
init_claude_sdk_package();
|
|
86370
|
+
});
|
|
86371
|
+
|
|
86372
|
+
// src/infrastructure/harnesses/shared-chunk-extractor.ts
|
|
86373
|
+
function createStandardSdkChunkExtractor() {
|
|
86374
|
+
return function extract(event) {
|
|
86375
|
+
if (event.type !== "message.part.delta")
|
|
86376
|
+
return null;
|
|
86377
|
+
const payload = event.payload;
|
|
86378
|
+
const delta = payload?.delta;
|
|
86379
|
+
if (!delta || delta.length === 0)
|
|
86380
|
+
return null;
|
|
86381
|
+
const messageId = payload?.messageID;
|
|
86382
|
+
if (!messageId)
|
|
86383
|
+
return null;
|
|
86384
|
+
return {
|
|
86385
|
+
content: delta,
|
|
86386
|
+
messageId,
|
|
86387
|
+
partType: payload?.partType ?? "text"
|
|
86388
|
+
};
|
|
86389
|
+
};
|
|
86390
|
+
}
|
|
86391
|
+
|
|
86392
|
+
// src/infrastructure/harnesses/claude-sdk/event-extractor.ts
|
|
86393
|
+
function createClaudeSdkChunkExtractor() {
|
|
86394
|
+
return createStandardSdkChunkExtractor();
|
|
86395
|
+
}
|
|
86396
|
+
var init_event_extractor = () => {};
|
|
86397
|
+
|
|
86398
|
+
// src/infrastructure/harnesses/claude-sdk/index.ts
|
|
86399
|
+
var init_claude_sdk2 = __esm(() => {
|
|
86400
|
+
init_claude_harness();
|
|
86401
|
+
init_claude_session();
|
|
86402
|
+
init_event_extractor();
|
|
86403
|
+
});
|
|
86404
|
+
|
|
86405
|
+
// src/infrastructure/harnesses/cursor-sdk/cursor-session.ts
|
|
86406
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
86407
|
+
|
|
86034
86408
|
class CursorSdkSession {
|
|
86035
86409
|
opencodeSessionId;
|
|
86036
86410
|
_sessionTitle;
|
|
@@ -86056,13 +86430,13 @@ class CursorSdkSession {
|
|
|
86056
86430
|
throw new Error("Session is closed");
|
|
86057
86431
|
const text = input.parts.map((p) => p.text).join(`
|
|
86058
86432
|
`);
|
|
86059
|
-
const messageId =
|
|
86433
|
+
const messageId = randomUUID6();
|
|
86060
86434
|
const isFirstTurn = this.turnCount === 0;
|
|
86061
86435
|
this.turnCount += 1;
|
|
86062
86436
|
const modelId = input.model ? resolveModelFromPrompt(input.model.providerID, input.model.modelID) : undefined;
|
|
86063
86437
|
const run3 = await withTimeout(this.agent.send(text, {
|
|
86064
86438
|
local: { force: isFirstTurn },
|
|
86065
|
-
idempotencyKey:
|
|
86439
|
+
idempotencyKey: randomUUID6(),
|
|
86066
86440
|
...modelId ? { model: { id: modelId } } : {}
|
|
86067
86441
|
}), SEND_TIMEOUT_MS2, "agent.send");
|
|
86068
86442
|
for await (const message of run3.stream()) {
|
|
@@ -86135,16 +86509,16 @@ var SEND_TIMEOUT_MS2 = 60000, RUN_WAIT_TIMEOUT_MS2 = 3600000;
|
|
|
86135
86509
|
var init_cursor_session = () => {};
|
|
86136
86510
|
|
|
86137
86511
|
// src/infrastructure/harnesses/cursor-sdk/cursor-harness.ts
|
|
86138
|
-
async function
|
|
86139
|
-
if (
|
|
86140
|
-
return
|
|
86141
|
-
if (
|
|
86142
|
-
throw
|
|
86512
|
+
async function loadSdk5() {
|
|
86513
|
+
if (_sdkCache5)
|
|
86514
|
+
return _sdkCache5;
|
|
86515
|
+
if (_sdkLoadError5)
|
|
86516
|
+
throw _sdkLoadError5;
|
|
86143
86517
|
try {
|
|
86144
|
-
|
|
86145
|
-
return
|
|
86518
|
+
_sdkCache5 = await importBundledCursorSdk();
|
|
86519
|
+
return _sdkCache5;
|
|
86146
86520
|
} catch (err) {
|
|
86147
|
-
|
|
86521
|
+
_sdkLoadError5 = err;
|
|
86148
86522
|
throw err;
|
|
86149
86523
|
}
|
|
86150
86524
|
}
|
|
@@ -86179,7 +86553,7 @@ class CursorSdkHarness {
|
|
|
86179
86553
|
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
86180
86554
|
if (!apiKey)
|
|
86181
86555
|
return [];
|
|
86182
|
-
const { Cursor } = await
|
|
86556
|
+
const { Cursor } = await loadSdk5();
|
|
86183
86557
|
const listed = await withTimeout(Cursor.models.list({ apiKey }), MODELS_LIST_TIMEOUT_MS2, "Cursor.models.list");
|
|
86184
86558
|
const modelIds = normalizeCursorSdkListedModels(listed.map((m) => m.id).filter((id3) => id3.length > 0));
|
|
86185
86559
|
return [
|
|
@@ -86196,8 +86570,8 @@ class CursorSdkHarness {
|
|
|
86196
86570
|
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
86197
86571
|
if (!apiKey)
|
|
86198
86572
|
throw new Error("CURSOR_API_KEY is not set");
|
|
86199
|
-
const modelId = resolveCursorSdkModel(config3.model ??
|
|
86200
|
-
const { Agent } = await
|
|
86573
|
+
const modelId = resolveCursorSdkModel(config3.model ?? DEFAULT_MODEL3);
|
|
86574
|
+
const { Agent } = await loadSdk5();
|
|
86201
86575
|
const agent = await withTimeout(Agent.create({
|
|
86202
86576
|
apiKey,
|
|
86203
86577
|
model: { id: modelId },
|
|
@@ -86221,10 +86595,10 @@ class CursorSdkHarness {
|
|
|
86221
86595
|
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
86222
86596
|
if (!apiKey)
|
|
86223
86597
|
throw new Error("CURSOR_API_KEY is not set");
|
|
86224
|
-
const { Agent } = await
|
|
86598
|
+
const { Agent } = await loadSdk5();
|
|
86225
86599
|
const agent = await withTimeout(Agent.resume(sessionId, {
|
|
86226
86600
|
apiKey,
|
|
86227
|
-
model: { id:
|
|
86601
|
+
model: { id: DEFAULT_MODEL3 },
|
|
86228
86602
|
local: { cwd: this.cwd, settingSources: [] }
|
|
86229
86603
|
}), AGENT_CREATE_TIMEOUT_MS2, "Agent.resume");
|
|
86230
86604
|
const session2 = new CursorSdkSession({
|
|
@@ -86251,9 +86625,9 @@ class CursorSdkHarness {
|
|
|
86251
86625
|
this.sessions.clear();
|
|
86252
86626
|
}
|
|
86253
86627
|
}
|
|
86254
|
-
var
|
|
86628
|
+
var DEFAULT_MODEL3 = "composer-2.5", MODELS_LIST_TIMEOUT_MS2 = 60000, AGENT_CREATE_TIMEOUT_MS2 = 60000, _sdkCache5, _sdkLoadError5, startCursorSdkHarness = async (config3) => {
|
|
86255
86629
|
try {
|
|
86256
|
-
await
|
|
86630
|
+
await loadSdk5();
|
|
86257
86631
|
} catch (err) {
|
|
86258
86632
|
throw new Error(`cursor-sdk unavailable: ${formatCursorSdkLoadError(err)}`);
|
|
86259
86633
|
}
|
|
@@ -86267,37 +86641,17 @@ var init_cursor_harness = __esm(() => {
|
|
|
86267
86641
|
init_cursor_sdk_package();
|
|
86268
86642
|
});
|
|
86269
86643
|
|
|
86270
|
-
// src/infrastructure/harnesses/shared-chunk-extractor.ts
|
|
86271
|
-
function createStandardSdkChunkExtractor() {
|
|
86272
|
-
return function extract(event) {
|
|
86273
|
-
if (event.type !== "message.part.delta")
|
|
86274
|
-
return null;
|
|
86275
|
-
const payload = event.payload;
|
|
86276
|
-
const delta = payload?.delta;
|
|
86277
|
-
if (!delta || delta.length === 0)
|
|
86278
|
-
return null;
|
|
86279
|
-
const messageId = payload?.messageID;
|
|
86280
|
-
if (!messageId)
|
|
86281
|
-
return null;
|
|
86282
|
-
return {
|
|
86283
|
-
content: delta,
|
|
86284
|
-
messageId,
|
|
86285
|
-
partType: payload?.partType ?? "text"
|
|
86286
|
-
};
|
|
86287
|
-
};
|
|
86288
|
-
}
|
|
86289
|
-
|
|
86290
86644
|
// src/infrastructure/harnesses/cursor-sdk/event-extractor.ts
|
|
86291
86645
|
function createCursorSdkChunkExtractor() {
|
|
86292
86646
|
return createStandardSdkChunkExtractor();
|
|
86293
86647
|
}
|
|
86294
|
-
var
|
|
86648
|
+
var init_event_extractor2 = () => {};
|
|
86295
86649
|
|
|
86296
86650
|
// src/infrastructure/harnesses/cursor-sdk/index.ts
|
|
86297
86651
|
var init_cursor_sdk2 = __esm(() => {
|
|
86298
86652
|
init_cursor_harness();
|
|
86299
86653
|
init_cursor_session();
|
|
86300
|
-
|
|
86654
|
+
init_event_extractor2();
|
|
86301
86655
|
});
|
|
86302
86656
|
|
|
86303
86657
|
// src/infrastructure/harnesses/opencode-sdk/event-extractor.ts
|
|
@@ -86831,7 +87185,7 @@ var init_opencode_harness = __esm(() => {
|
|
|
86831
87185
|
});
|
|
86832
87186
|
|
|
86833
87187
|
// src/infrastructure/harnesses/pi-sdk/pi-session.ts
|
|
86834
|
-
import { randomUUID as
|
|
87188
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
86835
87189
|
|
|
86836
87190
|
class PiSdkSession {
|
|
86837
87191
|
opencodeSessionId;
|
|
@@ -86858,7 +87212,7 @@ class PiSdkSession {
|
|
|
86858
87212
|
throw new Error("Session is closed");
|
|
86859
87213
|
const text = input.parts.map((p) => p.text).join(`
|
|
86860
87214
|
`);
|
|
86861
|
-
const messageId =
|
|
87215
|
+
const messageId = randomUUID7();
|
|
86862
87216
|
const onSessionEvent = (event) => {
|
|
86863
87217
|
if (this.closed)
|
|
86864
87218
|
return;
|
|
@@ -86918,16 +87272,16 @@ var PROMPT_TIMEOUT_MS2 = 3600000;
|
|
|
86918
87272
|
var init_pi_session = () => {};
|
|
86919
87273
|
|
|
86920
87274
|
// src/infrastructure/harnesses/pi-sdk/pi-harness.ts
|
|
86921
|
-
async function
|
|
86922
|
-
if (
|
|
86923
|
-
return
|
|
86924
|
-
if (
|
|
86925
|
-
throw
|
|
87275
|
+
async function loadSdk6() {
|
|
87276
|
+
if (_sdkCache6)
|
|
87277
|
+
return _sdkCache6;
|
|
87278
|
+
if (_sdkLoadError6)
|
|
87279
|
+
throw _sdkLoadError6;
|
|
86926
87280
|
try {
|
|
86927
|
-
|
|
86928
|
-
return
|
|
87281
|
+
_sdkCache6 = await importBundledPiSdk();
|
|
87282
|
+
return _sdkCache6;
|
|
86929
87283
|
} catch (err) {
|
|
86930
|
-
|
|
87284
|
+
_sdkLoadError6 = err;
|
|
86931
87285
|
throw err;
|
|
86932
87286
|
}
|
|
86933
87287
|
}
|
|
@@ -86999,7 +87353,7 @@ class PiSdkHarness {
|
|
|
86999
87353
|
const existing = this.sessions.get(sessionId);
|
|
87000
87354
|
if (existing)
|
|
87001
87355
|
return existing;
|
|
87002
|
-
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await
|
|
87356
|
+
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk6();
|
|
87003
87357
|
const sessions = await SessionManager.list(this.cwd, getPiSessionDir(this.cwd));
|
|
87004
87358
|
const match17 = sessions.find((s) => s.id === sessionId);
|
|
87005
87359
|
if (!match17) {
|
|
@@ -87047,8 +87401,8 @@ class PiSdkHarness {
|
|
|
87047
87401
|
this.sessions.clear();
|
|
87048
87402
|
}
|
|
87049
87403
|
async createAgentSession(systemPrompt, model) {
|
|
87050
|
-
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await
|
|
87051
|
-
const resolvedModel = resolveModel2(this.modelRegistry, model ??
|
|
87404
|
+
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk6();
|
|
87405
|
+
const resolvedModel = resolveModel2(this.modelRegistry, model ?? DEFAULT_MODEL4);
|
|
87052
87406
|
if (!resolvedModel) {
|
|
87053
87407
|
throw new Error("No Pi model available — configure provider credentials in ~/.pi/agent/auth.json");
|
|
87054
87408
|
}
|
|
@@ -87069,9 +87423,9 @@ class PiSdkHarness {
|
|
|
87069
87423
|
return session2;
|
|
87070
87424
|
}
|
|
87071
87425
|
}
|
|
87072
|
-
var SESSION_CREATE_TIMEOUT_MS3 = 60000,
|
|
87426
|
+
var SESSION_CREATE_TIMEOUT_MS3 = 60000, DEFAULT_MODEL4 = "opencode/big-pickle", _sdkCache6, _sdkLoadError6, startPiSdkHarness = async (config3) => {
|
|
87073
87427
|
try {
|
|
87074
|
-
const { AuthStorage, ModelRegistry } = await
|
|
87428
|
+
const { AuthStorage, ModelRegistry } = await loadSdk6();
|
|
87075
87429
|
const authStorage = AuthStorage.create();
|
|
87076
87430
|
const modelRegistry = ModelRegistry.create(authStorage);
|
|
87077
87431
|
if (modelRegistry.getAvailable().length === 0) {
|
|
@@ -87092,13 +87446,13 @@ var init_pi_harness = __esm(() => {
|
|
|
87092
87446
|
function createPiSdkChunkExtractor() {
|
|
87093
87447
|
return createStandardSdkChunkExtractor();
|
|
87094
87448
|
}
|
|
87095
|
-
var
|
|
87449
|
+
var init_event_extractor3 = () => {};
|
|
87096
87450
|
|
|
87097
87451
|
// src/infrastructure/harnesses/pi-sdk/index.ts
|
|
87098
87452
|
var init_pi_sdk2 = __esm(() => {
|
|
87099
87453
|
init_pi_harness();
|
|
87100
87454
|
init_pi_session();
|
|
87101
|
-
|
|
87455
|
+
init_event_extractor3();
|
|
87102
87456
|
});
|
|
87103
87457
|
|
|
87104
87458
|
// src/infrastructure/harnesses/registry.ts
|
|
@@ -87111,6 +87465,8 @@ async function startBoundHarness(config3) {
|
|
|
87111
87465
|
return startCursorSdkHarness(config3);
|
|
87112
87466
|
case "pi-sdk":
|
|
87113
87467
|
return startPiSdkHarness(config3);
|
|
87468
|
+
case "claude-sdk":
|
|
87469
|
+
return startClaudeSdkHarness(config3);
|
|
87114
87470
|
default: {
|
|
87115
87471
|
const _exhaustive = config3.harnessName;
|
|
87116
87472
|
throw new Error(`Unsupported direct harness: ${String(_exhaustive)}`);
|
|
@@ -87125,6 +87481,8 @@ function createChunkExtractor(harnessName) {
|
|
|
87125
87481
|
return createCursorSdkChunkExtractor();
|
|
87126
87482
|
case "pi-sdk":
|
|
87127
87483
|
return createPiSdkChunkExtractor();
|
|
87484
|
+
case "claude-sdk":
|
|
87485
|
+
return createClaudeSdkChunkExtractor();
|
|
87128
87486
|
default:
|
|
87129
87487
|
return createStandardSdkChunkExtractor();
|
|
87130
87488
|
}
|
|
@@ -87159,6 +87517,16 @@ async function isPiSdkInstalled() {
|
|
|
87159
87517
|
return false;
|
|
87160
87518
|
}
|
|
87161
87519
|
}
|
|
87520
|
+
async function isClaudeSdkInstalled() {
|
|
87521
|
+
try {
|
|
87522
|
+
const { importBundledClaudeSdk: importBundledClaudeSdk2, resolvePathToClaudeCodeExecutable: resolvePathToClaudeCodeExecutable2 } = await Promise.resolve().then(() => (init_claude_sdk_package(), exports_claude_sdk_package));
|
|
87523
|
+
await importBundledClaudeSdk2();
|
|
87524
|
+
await resolvePathToClaudeCodeExecutable2();
|
|
87525
|
+
return true;
|
|
87526
|
+
} catch {
|
|
87527
|
+
return false;
|
|
87528
|
+
}
|
|
87529
|
+
}
|
|
87162
87530
|
async function listInstalledNativeDirectHarnesses() {
|
|
87163
87531
|
const installed2 = [];
|
|
87164
87532
|
if (opencodeOnPath())
|
|
@@ -87167,9 +87535,12 @@ async function listInstalledNativeDirectHarnesses() {
|
|
|
87167
87535
|
installed2.push("cursor-sdk");
|
|
87168
87536
|
if (await isPiSdkInstalled())
|
|
87169
87537
|
installed2.push("pi-sdk");
|
|
87538
|
+
if (await isClaudeSdkInstalled())
|
|
87539
|
+
installed2.push("claude-sdk");
|
|
87170
87540
|
return installed2;
|
|
87171
87541
|
}
|
|
87172
87542
|
var init_registry4 = __esm(() => {
|
|
87543
|
+
init_claude_sdk2();
|
|
87173
87544
|
init_cursor_sdk2();
|
|
87174
87545
|
init_opencode_harness();
|
|
87175
87546
|
init_pi_sdk2();
|
|
@@ -87808,6 +88179,14 @@ function recordLiveSessionChunk(event, handle, journal, extractChunk, deps) {
|
|
|
87808
88179
|
deps.sessionRepository.bindTurnMessageId(handle.currentTurn.turnId, chunk2.messageId).catch((err) => console.warn("[direct-harness] bindTurnMessageId error:", err));
|
|
87809
88180
|
}
|
|
87810
88181
|
}
|
|
88182
|
+
function handleLiveSessionProviderId(event, deps, rowId, handle, liveSession) {
|
|
88183
|
+
if (event.type !== "session.provider_id")
|
|
88184
|
+
return;
|
|
88185
|
+
const sessionId = event.payload.sessionId;
|
|
88186
|
+
if (!sessionId || sessionId === handle.opencodeSessionId)
|
|
88187
|
+
return;
|
|
88188
|
+
deps.sessionRepository.associateOpenCodeSessionId(rowId, sessionId, liveSession.sessionTitle ?? "").catch((err) => console.warn("[direct-harness] associateOpenCodeSessionId (provider id) error:", err));
|
|
88189
|
+
}
|
|
87811
88190
|
function handleLiveSessionTitleUpdate(event, deps, rowId, liveSession) {
|
|
87812
88191
|
if (event.type !== "session.updated") {
|
|
87813
88192
|
return;
|
|
@@ -87827,6 +88206,7 @@ function handleLiveSessionEvent(event, ctx) {
|
|
|
87827
88206
|
handleSessionIdle(handle, journal, idleConfig, deps.sessionRepository).catch((err) => console.warn("[direct-harness] idle handler error:", err));
|
|
87828
88207
|
}
|
|
87829
88208
|
handleLiveSessionTitleUpdate(event, deps, rowId, liveSession);
|
|
88209
|
+
handleLiveSessionProviderId(event, deps, rowId, handle, liveSession);
|
|
87830
88210
|
}
|
|
87831
88211
|
async function processOne(daemonSession, deps, session2) {
|
|
87832
88212
|
const rowId = session2._id;
|
|
@@ -90962,7 +91342,7 @@ function diffPathIndexes(previous, next4) {
|
|
|
90962
91342
|
}
|
|
90963
91343
|
|
|
90964
91344
|
// src/infrastructure/services/workspace/workspace-sync-state.ts
|
|
90965
|
-
import { createHash as createHash6, randomUUID as
|
|
91345
|
+
import { createHash as createHash6, randomUUID as randomUUID8 } from "node:crypto";
|
|
90966
91346
|
import * as fs11 from "node:fs/promises";
|
|
90967
91347
|
import { homedir as homedir7 } from "node:os";
|
|
90968
91348
|
import { join as join20 } from "node:path";
|
|
@@ -91024,7 +91404,7 @@ function createManifestFromTree(args2) {
|
|
|
91024
91404
|
version: SYNC_STATE_VERSION,
|
|
91025
91405
|
machineId: args2.machineId,
|
|
91026
91406
|
workingDir: normalizeWorkingDirForLookup(args2.workingDir),
|
|
91027
|
-
syncGeneration:
|
|
91407
|
+
syncGeneration: randomUUID8(),
|
|
91028
91408
|
completedAt: Date.now(),
|
|
91029
91409
|
scanner: args2.scanner,
|
|
91030
91410
|
dataHash: args2.dataHash,
|
|
@@ -91046,7 +91426,7 @@ var init_workspace_sync_state = __esm(() => {
|
|
|
91046
91426
|
});
|
|
91047
91427
|
|
|
91048
91428
|
// src/infrastructure/services/workspace/workspace-file-tree-coordinator.ts
|
|
91049
|
-
import { randomUUID as
|
|
91429
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
91050
91430
|
import path6 from "node:path";
|
|
91051
91431
|
function deltaEntry(paths, pathValue) {
|
|
91052
91432
|
const type = paths[pathValue];
|
|
@@ -91073,7 +91453,7 @@ function buildPendingDeltas(previous, next4) {
|
|
|
91073
91453
|
const result = [];
|
|
91074
91454
|
for (let offset = 0;offset < operations.length; offset += MAX_DELTA_OPERATIONS) {
|
|
91075
91455
|
const delta = {
|
|
91076
|
-
operationId:
|
|
91456
|
+
operationId: randomUUID9(),
|
|
91077
91457
|
added: [],
|
|
91078
91458
|
removed: [],
|
|
91079
91459
|
typeChanged: [],
|
|
@@ -91297,7 +91677,7 @@ var init_workspace_file_tree_coordinator = __esm(() => {
|
|
|
91297
91677
|
});
|
|
91298
91678
|
|
|
91299
91679
|
// src/commands/machine/daemon-start/file-tree-subscription.ts
|
|
91300
|
-
import { randomUUID as
|
|
91680
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
91301
91681
|
import { gzipSync as gzipSync4 } from "node:zlib";
|
|
91302
91682
|
function logSubscriptionWarn(label, err) {
|
|
91303
91683
|
console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage2(err)}`);
|
|
@@ -91339,7 +91719,7 @@ function toDeltaOperations(delta) {
|
|
|
91339
91719
|
}
|
|
91340
91720
|
async function publishCheckpoint(session2, normalizedWorkingDir, tree, revision) {
|
|
91341
91721
|
const dataHash = computeFileTreeDataHash(tree);
|
|
91342
|
-
const syncGeneration =
|
|
91722
|
+
const syncGeneration = randomUUID10();
|
|
91343
91723
|
const snapshot = await syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, syncGeneration);
|
|
91344
91724
|
let checkpointRevision = revision;
|
|
91345
91725
|
let result = await session2.backend.mutation(api.workspaceFiles.publishFileTreeCheckpoint, {
|
|
@@ -91868,6 +92248,8 @@ async function pushAvailableGitState(ctx, workingDir, stateKey, branchResult) {
|
|
|
91868
92248
|
...pipeline2.toMutationArgs(values3, false)
|
|
91869
92249
|
});
|
|
91870
92250
|
ctx.lastPushedGitState.set(stateKey, stateHash);
|
|
92251
|
+
lastPushedBranch.set(stateKey, branch);
|
|
92252
|
+
lastFullPushMs.set(stateKey, Date.now());
|
|
91871
92253
|
console.log(`[${formatTimestamp()}] \uD83D\uDD00 Git state pushed: ${workingDir} (${branch}${values3.get("isDirty") ? ", dirty" : ", clean"})`);
|
|
91872
92254
|
}
|
|
91873
92255
|
if (ctx.lastPushedGitState.get(commitsKey) !== commitsHash) {
|
|
@@ -91919,6 +92301,7 @@ function pushObservedBranchErrorEffect(session2, lastPushedGitState, stateKey, w
|
|
|
91919
92301
|
function pushObservedFullGitStateEffect(session2, lastPushedGitState, stateKey, workingDir, branch, reason) {
|
|
91920
92302
|
return exports_Effect.gen(function* () {
|
|
91921
92303
|
yield* exports_Effect.promise(() => pushSingleWorkspaceGitStateImpl(buildGitStateDeps(session2, lastPushedGitState), workingDir));
|
|
92304
|
+
lastPushedBranch.set(stateKey, branch);
|
|
91922
92305
|
lastFullPushMs.set(stateKey, Date.now());
|
|
91923
92306
|
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed full git state pushed: ${workingDir} (${branch})${reason === "refresh" ? " [refresh]" : ""}`);
|
|
91924
92307
|
});
|
|
@@ -91948,7 +92331,7 @@ function pushObservedSlimGitSummaryEffect(session2, lastPushedGitState, stateKey
|
|
|
91948
92331
|
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed git summary pushed: ${workingDir} (${branch}${values3.get("isDirty") ? ", dirty" : ", clean"})${reason === "refresh" ? " [refresh]" : ""}`);
|
|
91949
92332
|
});
|
|
91950
92333
|
}
|
|
91951
|
-
var lastFullPushMs, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummaryForObservedEffect = (workingDir, reason = "safety-poll") => exports_Effect.gen(function* pushObservedGitSummaryForObserved() {
|
|
92334
|
+
var lastFullPushMs, lastPushedBranch, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummaryForObservedEffect = (workingDir, reason = "safety-poll") => exports_Effect.gen(function* pushObservedGitSummaryForObserved() {
|
|
91952
92335
|
const session2 = yield* DaemonSessionService;
|
|
91953
92336
|
const mutable2 = yield* DaemonMutableStateService;
|
|
91954
92337
|
const lastPushedGitState = yield* exports_Ref.get(mutable2.lastPushedGitState);
|
|
@@ -91969,7 +92352,10 @@ var lastFullPushMs, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummary
|
|
|
91969
92352
|
const branch = branchResult.branch;
|
|
91970
92353
|
const now = Date.now();
|
|
91971
92354
|
const lastFull = lastFullPushMs.get(stateKey) ?? 0;
|
|
91972
|
-
|
|
92355
|
+
const previousBranch = lastPushedBranch.get(stateKey);
|
|
92356
|
+
const branchChanged = previousBranch !== undefined && previousBranch !== branch;
|
|
92357
|
+
const needsFullPush = reason === "refresh" || branchChanged || now - lastFull >= OBSERVED_FULL_PUSH_INTERVAL_MS;
|
|
92358
|
+
if (needsFullPush) {
|
|
91973
92359
|
yield* pushObservedFullGitStateEffect(session2, lastPushedGitState, stateKey, workingDir, branch, reason);
|
|
91974
92360
|
return;
|
|
91975
92361
|
}
|
|
@@ -91990,6 +92376,7 @@ var init_git_heartbeat = __esm(() => {
|
|
|
91990
92376
|
init_git_state_pipeline();
|
|
91991
92377
|
init_convex_error();
|
|
91992
92378
|
lastFullPushMs = new Map;
|
|
92379
|
+
lastPushedBranch = new Map;
|
|
91993
92380
|
branchField = {
|
|
91994
92381
|
key: "branch",
|
|
91995
92382
|
includeInSlim: true,
|
|
@@ -93171,7 +93558,8 @@ var init_decide_resume_path = __esm(() => {
|
|
|
93171
93558
|
"platform.team_switch",
|
|
93172
93559
|
"platform.resume_storm",
|
|
93173
93560
|
"daemon.shutdown",
|
|
93174
|
-
"daemon.respawn"
|
|
93561
|
+
"daemon.respawn",
|
|
93562
|
+
"daemon.stop_timeout"
|
|
93175
93563
|
]);
|
|
93176
93564
|
});
|
|
93177
93565
|
|
|
@@ -93338,21 +93726,14 @@ function classifyResumeStormReason(logLines) {
|
|
|
93338
93726
|
}
|
|
93339
93727
|
return "unknown";
|
|
93340
93728
|
}
|
|
93341
|
-
function isPermanentHarnessFailure(logLines) {
|
|
93342
|
-
if (isTerminalProviderFailureInLogs(logLines)) {
|
|
93343
|
-
return true;
|
|
93344
|
-
}
|
|
93345
|
-
return PERMANENT_FAILURE_REASONS.has(classifyResumeStormReason(logLines));
|
|
93346
|
-
}
|
|
93347
93729
|
function formatPermanentHarnessFailureMessage(logLines) {
|
|
93348
93730
|
const reason = classifyResumeStormReason(logLines);
|
|
93349
93731
|
const blob = logLines.join(`
|
|
93350
93732
|
`).trim();
|
|
93351
|
-
return blob ? `
|
|
93733
|
+
return blob ? `Crash recovery limit (${reason}): ${blob.slice(-500)}` : `Crash recovery limit (${reason})`;
|
|
93352
93734
|
}
|
|
93353
93735
|
var CLASSIFICATION_RULES, PERMANENT_FAILURE_REASONS;
|
|
93354
93736
|
var init_classify_resume_storm_reason = __esm(() => {
|
|
93355
|
-
init_terminal_provider_error();
|
|
93356
93737
|
CLASSIFICATION_RULES = [
|
|
93357
93738
|
{
|
|
93358
93739
|
reason: "rate_limit",
|
|
@@ -93456,27 +93837,11 @@ async function handleTurnCompleted(deps, input, slot) {
|
|
|
93456
93837
|
if (await tryAbortResumeStorm(deps, input, slot)) {
|
|
93457
93838
|
return { outcome: "storm_aborted" };
|
|
93458
93839
|
}
|
|
93459
|
-
if (isTerminalProviderFailureInLogs(slot?.recentLogLines ?? [])) {
|
|
93460
|
-
if (slot) {
|
|
93461
|
-
slot.terminalProviderFailureHandled = true;
|
|
93462
|
-
}
|
|
93463
|
-
const error = formatTerminalProviderFailureMessage(slot?.recentLogLines ?? []);
|
|
93464
|
-
try {
|
|
93465
|
-
await deps.backend.emitAgentStartFailed({
|
|
93466
|
-
chatroomId: input.chatroomId,
|
|
93467
|
-
role: input.role,
|
|
93468
|
-
error
|
|
93469
|
-
});
|
|
93470
|
-
} catch {}
|
|
93471
|
-
deps.killProcess(input.pid);
|
|
93472
|
-
return { outcome: "killed_terminal_provider_error" };
|
|
93473
|
-
}
|
|
93474
93840
|
deps.killProcess(input.pid);
|
|
93475
93841
|
return { outcome: "killed" };
|
|
93476
93842
|
}
|
|
93477
93843
|
var init_handle_turn_completed = __esm(() => {
|
|
93478
93844
|
init_abort_resume_storm();
|
|
93479
|
-
init_terminal_provider_error();
|
|
93480
93845
|
});
|
|
93481
93846
|
|
|
93482
93847
|
// src/infrastructure/deps/process.ts
|
|
@@ -93894,19 +94259,30 @@ class AgentProcessManager {
|
|
|
93894
94259
|
whenTurnEndsIdle() {
|
|
93895
94260
|
return this.turnEndQueue.whenIdle();
|
|
93896
94261
|
}
|
|
94262
|
+
clearSlotRuntimeState(slot) {
|
|
94263
|
+
slot.state = "idle";
|
|
94264
|
+
slot.pid = undefined;
|
|
94265
|
+
slot.harness = undefined;
|
|
94266
|
+
slot.harnessSessionId = undefined;
|
|
94267
|
+
slot.resumableHarnessSessionId = undefined;
|
|
94268
|
+
slot.model = undefined;
|
|
94269
|
+
slot.workingDir = undefined;
|
|
94270
|
+
slot.startedAt = undefined;
|
|
94271
|
+
slot.pendingOperation = undefined;
|
|
94272
|
+
slot.stoppingSince = undefined;
|
|
94273
|
+
}
|
|
94274
|
+
bumpStopGeneration(slot) {
|
|
94275
|
+
slot.stopGeneration = (slot.stopGeneration ?? 0) + 1;
|
|
94276
|
+
return slot.stopGeneration;
|
|
94277
|
+
}
|
|
93897
94278
|
async ensureRunning(opts) {
|
|
93898
94279
|
const key = agentKey3(opts.chatroomId, opts.role);
|
|
93899
94280
|
const slot = this.getOrCreateSlot(key);
|
|
93900
94281
|
if (slot.state === "running" && slot.pid && !isProcessAlive(this.deps.processes.kill, slot.pid)) {
|
|
93901
|
-
slot
|
|
93902
|
-
|
|
93903
|
-
|
|
93904
|
-
slot.
|
|
93905
|
-
slot.resumableHarnessSessionId = undefined;
|
|
93906
|
-
slot.model = undefined;
|
|
93907
|
-
slot.workingDir = undefined;
|
|
93908
|
-
slot.startedAt = undefined;
|
|
93909
|
-
slot.pendingOperation = undefined;
|
|
94282
|
+
this.clearSlotRuntimeState(slot);
|
|
94283
|
+
}
|
|
94284
|
+
if (slot.state === "stopping" && (slot.stoppingSince === undefined || this.deps.clock.now() - slot.stoppingSince >= STOPPING_TIMEOUT_MS)) {
|
|
94285
|
+
await this.forceClearStuckStoppingSlot(key, slot, opts.chatroomId, opts.role, "daemon.stop_timeout");
|
|
93910
94286
|
}
|
|
93911
94287
|
if (slot.pendingOperation) {
|
|
93912
94288
|
if (slot.state === "stopping") {
|
|
@@ -93970,7 +94346,9 @@ class AgentProcessManager {
|
|
|
93970
94346
|
return { success: true };
|
|
93971
94347
|
}
|
|
93972
94348
|
slot.state = "stopping";
|
|
93973
|
-
const
|
|
94349
|
+
const stopGeneration = this.bumpStopGeneration(slot);
|
|
94350
|
+
slot.stoppingSince = this.deps.clock.now();
|
|
94351
|
+
const operation = this.doStop(key, slot, pid, opts, stopGeneration);
|
|
93974
94352
|
slot.pendingOperation = operation;
|
|
93975
94353
|
return null;
|
|
93976
94354
|
}
|
|
@@ -94053,24 +94431,6 @@ class AgentProcessManager {
|
|
|
94053
94431
|
console.log(`[AgentProcessManager] ✅ Handled rapid resume storm for ${opts.role}`);
|
|
94054
94432
|
return;
|
|
94055
94433
|
}
|
|
94056
|
-
if (isTerminalProviderFailureInLogs(slot?.recentLogLines ?? [])) {
|
|
94057
|
-
if (slot) {
|
|
94058
|
-
slot.terminalProviderFailureHandled = true;
|
|
94059
|
-
}
|
|
94060
|
-
const error = formatTerminalProviderFailureMessage(slot?.recentLogLines ?? []);
|
|
94061
|
-
try {
|
|
94062
|
-
await createTurnCompletedBackend(this.deps).emitAgentStartFailed({
|
|
94063
|
-
chatroomId: opts.chatroomId,
|
|
94064
|
-
role: opts.role,
|
|
94065
|
-
error
|
|
94066
|
-
});
|
|
94067
|
-
} catch {}
|
|
94068
|
-
try {
|
|
94069
|
-
this.deps.processes.kill(-opts.pid, "SIGTERM");
|
|
94070
|
-
} catch {}
|
|
94071
|
-
console.log(`[AgentProcessManager] ⛔ Terminal provider error for ${opts.role} — emitted agent.startFailed`);
|
|
94072
|
-
return;
|
|
94073
|
-
}
|
|
94074
94434
|
try {
|
|
94075
94435
|
const result = await this.deps.backend.mutation(api.participants.handleNativeAgentEnd, {
|
|
94076
94436
|
sessionId: this.deps.sessionId,
|
|
@@ -94217,16 +94577,12 @@ class AgentProcessManager {
|
|
|
94217
94577
|
console.log(`[AgentProcessManager] ⚠️ Cannot restart — missing harness or workingDir ` + `(role: ${opts.role}, harness: ${harness ?? "none"}, workingDir: ${workingDir ?? "none"})`);
|
|
94218
94578
|
return;
|
|
94219
94579
|
}
|
|
94220
|
-
if (isPermanentHarnessFailure(logs)) {
|
|
94221
|
-
this.handlePermanentFailureForRestart(opts, recentLogLines, ctx.terminalProviderFailureHandled);
|
|
94222
|
-
return;
|
|
94223
|
-
}
|
|
94224
94580
|
const hadRunError = this.hasCursorSdkRunErrorInContext(logs);
|
|
94225
94581
|
if (harness === "cursor-sdk") {
|
|
94226
94582
|
this.retryCursorSdkSessionReopen(opts, ctx, hadRunError);
|
|
94227
94583
|
return;
|
|
94228
94584
|
}
|
|
94229
|
-
this.
|
|
94585
|
+
this.attemptCrashRecoveryRestart(opts, ctx, {
|
|
94230
94586
|
chatroomId: opts.chatroomId,
|
|
94231
94587
|
role: opts.role,
|
|
94232
94588
|
agentHarness: harness,
|
|
@@ -94234,15 +94590,54 @@ class AgentProcessManager {
|
|
|
94234
94590
|
workingDir,
|
|
94235
94591
|
reason: "platform.crash_recovery",
|
|
94236
94592
|
wantResume: hadRunError ? false : ctx.wantResume ?? true
|
|
94237
|
-
}).then((result) => {
|
|
94238
|
-
if (!result.success) {
|
|
94239
|
-
console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${opts.role}: ${result.error ?? "unknown"}`);
|
|
94240
|
-
}
|
|
94241
|
-
}).catch((err) => {
|
|
94242
|
-
console.log(` ⚠️ Failed to restart agent: ${err.message}`);
|
|
94243
|
-
this.emitStartFailedEvent(opts.role, opts.chatroomId, err.message);
|
|
94244
94593
|
});
|
|
94245
94594
|
}
|
|
94595
|
+
async attemptCrashRecoveryRestart(exitOpts, ctx, ensureOpts) {
|
|
94596
|
+
try {
|
|
94597
|
+
const result = await this.ensureRunning(ensureOpts);
|
|
94598
|
+
if (result.success)
|
|
94599
|
+
return;
|
|
94600
|
+
if (result.error === "backoff") {
|
|
94601
|
+
await this.retryCrashRecoveryAfterBackoff(exitOpts, ctx, ensureOpts, result.retryAfterMs);
|
|
94602
|
+
return;
|
|
94603
|
+
}
|
|
94604
|
+
if (result.error === "crash_loop") {
|
|
94605
|
+
this.handleCrashLoopLimitReached(exitOpts, ctx.recentLogLines);
|
|
94606
|
+
return;
|
|
94607
|
+
}
|
|
94608
|
+
console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${exitOpts.role}: ${result.error ?? "unknown"}`);
|
|
94609
|
+
} catch (err) {
|
|
94610
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
94611
|
+
console.log(` ⚠️ Failed to restart agent: ${message}`);
|
|
94612
|
+
this.emitStartFailedEvent(exitOpts.role, exitOpts.chatroomId, message);
|
|
94613
|
+
}
|
|
94614
|
+
}
|
|
94615
|
+
async retryCrashRecoveryAfterBackoff(exitOpts, ctx, ensureOpts, retryAfterMs) {
|
|
94616
|
+
if (retryAfterMs === undefined || retryAfterMs <= 0) {
|
|
94617
|
+
return;
|
|
94618
|
+
}
|
|
94619
|
+
const classified = classifyResumeStormReason(ctx.recentLogLines ?? []);
|
|
94620
|
+
console.log(`[AgentProcessManager] ⏳ Crash recovery backoff for ${exitOpts.role} (${classified}): waiting ${retryAfterMs}ms`);
|
|
94621
|
+
await this.deps.clock.delay(retryAfterMs);
|
|
94622
|
+
const retry4 = await this.ensureRunning(ensureOpts);
|
|
94623
|
+
if (retry4.success)
|
|
94624
|
+
return;
|
|
94625
|
+
if (retry4.error === "crash_loop") {
|
|
94626
|
+
this.handleCrashLoopLimitReached(exitOpts, ctx.recentLogLines);
|
|
94627
|
+
return;
|
|
94628
|
+
}
|
|
94629
|
+
if (!retry4.success) {
|
|
94630
|
+
console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${exitOpts.role}: ${retry4.error ?? "unknown"}`);
|
|
94631
|
+
}
|
|
94632
|
+
}
|
|
94633
|
+
handleCrashLoopLimitReached(opts, recentLogLines) {
|
|
94634
|
+
const error = formatPermanentHarnessFailureMessage(recentLogLines ?? []);
|
|
94635
|
+
console.log(`[AgentProcessManager] ⛔ Crash recovery limit reached — ${error}`);
|
|
94636
|
+
this.deps.crashLoop.clear(opts.chatroomId, opts.role);
|
|
94637
|
+
const key = agentKey3(opts.chatroomId, opts.role);
|
|
94638
|
+
this.clearLastHarnessSession(key);
|
|
94639
|
+
this.emitStartFailedEvent(opts.role, opts.chatroomId, error);
|
|
94640
|
+
}
|
|
94246
94641
|
clearHarnessSessionAfterResumePhaseFailure(key, opts) {
|
|
94247
94642
|
const stored = this.lastHarnessSessions.get(key);
|
|
94248
94643
|
this.clearLastHarnessSession(key);
|
|
@@ -94310,25 +94705,6 @@ class AgentProcessManager {
|
|
|
94310
94705
|
this.sessionReopenRetryInFlight.delete(key);
|
|
94311
94706
|
}
|
|
94312
94707
|
}
|
|
94313
|
-
handlePermanentFailureForRestart(opts, recentLogLines, startFailedAlreadyEmitted) {
|
|
94314
|
-
const error = isTerminalProviderFailureInLogs(recentLogLines ?? []) ? formatTerminalProviderFailureMessage(recentLogLines ?? []) : formatPermanentHarnessFailureMessage(recentLogLines ?? []);
|
|
94315
|
-
console.log(`[AgentProcessManager] ⛔ Skipping restart — ${error}`);
|
|
94316
|
-
this.deps.crashLoop.clear(opts.chatroomId, opts.role);
|
|
94317
|
-
const key = agentKey3(opts.chatroomId, opts.role);
|
|
94318
|
-
this.clearLastHarnessSession(key);
|
|
94319
|
-
if (startFailedAlreadyEmitted) {
|
|
94320
|
-
return;
|
|
94321
|
-
}
|
|
94322
|
-
this.deps.backend.mutation(api.machines.emitAgentStartFailed, {
|
|
94323
|
-
sessionId: this.deps.sessionId,
|
|
94324
|
-
machineId: this.deps.machineId,
|
|
94325
|
-
chatroomId: opts.chatroomId,
|
|
94326
|
-
role: opts.role,
|
|
94327
|
-
error
|
|
94328
|
-
}).catch((emitErr) => {
|
|
94329
|
-
console.log(` ⚠️ Failed to emit startFailed event: ${emitErr.message}`);
|
|
94330
|
-
});
|
|
94331
|
-
}
|
|
94332
94708
|
emitStartFailedEvent(role, chatroomId, error) {
|
|
94333
94709
|
this.deps.backend.mutation(api.machines.emitAgentStartFailed, {
|
|
94334
94710
|
sessionId: this.deps.sessionId,
|
|
@@ -94355,6 +94731,37 @@ class AgentProcessManager {
|
|
|
94355
94731
|
}
|
|
94356
94732
|
return result;
|
|
94357
94733
|
}
|
|
94734
|
+
listAllSlots() {
|
|
94735
|
+
const result = [];
|
|
94736
|
+
for (const [key, slot] of this.slots) {
|
|
94737
|
+
const [chatroomId, role] = key.split(":");
|
|
94738
|
+
result.push({ chatroomId, role, slot });
|
|
94739
|
+
}
|
|
94740
|
+
return result;
|
|
94741
|
+
}
|
|
94742
|
+
async clearStuckStoppingSlot(chatroomId, role) {
|
|
94743
|
+
const key = agentKey3(chatroomId, role);
|
|
94744
|
+
const slot = this.slots.get(key);
|
|
94745
|
+
if (!slot || slot.state !== "stopping") {
|
|
94746
|
+
return false;
|
|
94747
|
+
}
|
|
94748
|
+
const elapsed3 = slot.stoppingSince ? this.deps.clock.now() - slot.stoppingSince : STOPPING_TIMEOUT_MS;
|
|
94749
|
+
if (elapsed3 < STOPPING_TIMEOUT_MS) {
|
|
94750
|
+
return false;
|
|
94751
|
+
}
|
|
94752
|
+
await this.forceClearStuckStoppingSlot(key, slot, chatroomId, role, "daemon.stop_timeout");
|
|
94753
|
+
console.warn(`[AgentProcessManager] ⚠️ Cleared stuck stopping slot for ${role}@${chatroomId}`);
|
|
94754
|
+
return true;
|
|
94755
|
+
}
|
|
94756
|
+
async clearAllStuckStoppingSlots() {
|
|
94757
|
+
let cleared = 0;
|
|
94758
|
+
for (const { chatroomId, role } of this.listAllSlots()) {
|
|
94759
|
+
if (await this.clearStuckStoppingSlot(chatroomId, role)) {
|
|
94760
|
+
cleared++;
|
|
94761
|
+
}
|
|
94762
|
+
}
|
|
94763
|
+
return cleared;
|
|
94764
|
+
}
|
|
94358
94765
|
async recover() {
|
|
94359
94766
|
let entries2 = [];
|
|
94360
94767
|
try {
|
|
@@ -94387,6 +94794,10 @@ class AgentProcessManager {
|
|
|
94387
94794
|
}
|
|
94388
94795
|
}
|
|
94389
94796
|
console.log(`[AgentProcessManager] Recovery: ${killed} killed, ${cleaned} cleaned up`);
|
|
94797
|
+
const clearedCount = await this.clearAllStuckStoppingSlots();
|
|
94798
|
+
if (clearedCount > 0) {
|
|
94799
|
+
console.log(`[AgentProcessManager] Recovery: cleared ${clearedCount} stuck stopping slot(s)`);
|
|
94800
|
+
}
|
|
94390
94801
|
}
|
|
94391
94802
|
getOrCreateSlot(key) {
|
|
94392
94803
|
let slot = this.slots.get(key);
|
|
@@ -94423,7 +94834,9 @@ class AgentProcessManager {
|
|
|
94423
94834
|
if (slot?.pid && isProcessAlive(this.deps.processes.kill, slot.pid) && (slot.state === "running" || slot.state === "spawning")) {
|
|
94424
94835
|
const pid = slot.pid;
|
|
94425
94836
|
slot.state = "stopping";
|
|
94426
|
-
|
|
94837
|
+
const stopGeneration = this.bumpStopGeneration(slot);
|
|
94838
|
+
slot.stoppingSince = this.deps.clock.now();
|
|
94839
|
+
await this.doStop(key, slot, pid, { chatroomId, role, reason: "daemon.respawn" }, stopGeneration);
|
|
94427
94840
|
}
|
|
94428
94841
|
}
|
|
94429
94842
|
async killPersistedProcessIfAlive(chatroomId, role) {
|
|
@@ -94693,7 +95106,7 @@ class AgentProcessManager {
|
|
|
94693
95106
|
if (loopCheck.waitMs !== undefined && loopCheck.waitMs > 0) {
|
|
94694
95107
|
console.log(` ⏳ Agent restart backoff: waiting ${loopCheck.waitMs}ms before retry`);
|
|
94695
95108
|
this.resetSlotIdle(slot);
|
|
94696
|
-
return { success: false, error: "backoff" };
|
|
95109
|
+
return { success: false, error: "backoff", retryAfterMs: loopCheck.waitMs };
|
|
94697
95110
|
}
|
|
94698
95111
|
this.deps.backend.mutation(api.machines.emitRestartLimitReached, {
|
|
94699
95112
|
sessionId: this.deps.sessionId,
|
|
@@ -95018,6 +95431,42 @@ class AgentProcessManager {
|
|
|
95018
95431
|
slot.pid = undefined;
|
|
95019
95432
|
slot.startedAt = undefined;
|
|
95020
95433
|
slot.pendingOperation = undefined;
|
|
95434
|
+
slot.stoppingSince = undefined;
|
|
95435
|
+
}
|
|
95436
|
+
async forceClearStuckStoppingSlot(key, slot, chatroomId, role, reason) {
|
|
95437
|
+
const pid = slot.pid;
|
|
95438
|
+
const harness = slot.harness;
|
|
95439
|
+
const durationMs = slot.stoppingSince ? this.deps.clock.now() - slot.stoppingSince : STOPPING_TIMEOUT_MS;
|
|
95440
|
+
this.bumpStopGeneration(slot);
|
|
95441
|
+
this.clearSlotRuntimeState(slot);
|
|
95442
|
+
this.deps.backend.mutation(api.machines.emitAgentStopTimeout, {
|
|
95443
|
+
sessionId: this.deps.sessionId,
|
|
95444
|
+
machineId: this.deps.machineId,
|
|
95445
|
+
chatroomId,
|
|
95446
|
+
role,
|
|
95447
|
+
pid,
|
|
95448
|
+
durationMs
|
|
95449
|
+
}).catch((err) => {
|
|
95450
|
+
console.log(` ⚠️ Failed to emit agent.stopTimeout event: ${err.message}`);
|
|
95451
|
+
});
|
|
95452
|
+
if (pid) {
|
|
95453
|
+
try {
|
|
95454
|
+
this.deps.processes.kill(-pid, "SIGKILL");
|
|
95455
|
+
} catch {}
|
|
95456
|
+
const exitArgs = {
|
|
95457
|
+
sessionId: this.deps.sessionId,
|
|
95458
|
+
machineId: this.deps.machineId,
|
|
95459
|
+
chatroomId,
|
|
95460
|
+
role,
|
|
95461
|
+
pid,
|
|
95462
|
+
stopReason: reason,
|
|
95463
|
+
exitCode: undefined,
|
|
95464
|
+
signal: "SIGKILL",
|
|
95465
|
+
agentHarness: harness
|
|
95466
|
+
};
|
|
95467
|
+
this.recordAgentExitedOrQueueRetry(role, exitArgs, "Failed to record stop-timeout exit");
|
|
95468
|
+
}
|
|
95469
|
+
await this.clearAgentPidQuietly(chatroomId, role);
|
|
95021
95470
|
}
|
|
95022
95471
|
recordStopExit(slot, pid, opts) {
|
|
95023
95472
|
const exitArgs3 = {
|
|
@@ -95036,7 +95485,7 @@ class AgentProcessManager {
|
|
|
95036
95485
|
this.queueExitRetry({ role: opts.role, args: exitArgs3 });
|
|
95037
95486
|
});
|
|
95038
95487
|
}
|
|
95039
|
-
async doStop(key, slot, pid, opts) {
|
|
95488
|
+
async doStop(key, slot, pid, opts, stopGeneration) {
|
|
95040
95489
|
try {
|
|
95041
95490
|
const harness = slot.harness;
|
|
95042
95491
|
const service3 = harness ? this.deps.agentServices.get(harness) : undefined;
|
|
@@ -95048,6 +95497,9 @@ class AgentProcessManager {
|
|
|
95048
95497
|
await this.killProcessWithFallback(pid);
|
|
95049
95498
|
}
|
|
95050
95499
|
} catch {}
|
|
95500
|
+
if (slot.stopGeneration !== stopGeneration) {
|
|
95501
|
+
return { success: true };
|
|
95502
|
+
}
|
|
95051
95503
|
this.resetSlotAfterStop(slot);
|
|
95052
95504
|
this.recordStopExit(slot, pid, opts);
|
|
95053
95505
|
try {
|
|
@@ -95056,7 +95508,7 @@ class AgentProcessManager {
|
|
|
95056
95508
|
return { success: true };
|
|
95057
95509
|
}
|
|
95058
95510
|
}
|
|
95059
|
-
var AGENT_EXIT_RETRY_INTERVAL_MS = 1e4;
|
|
95511
|
+
var AGENT_EXIT_RETRY_INTERVAL_MS = 1e4, STOPPING_TIMEOUT_MS = 30000;
|
|
95060
95512
|
var init_agent_process_manager = __esm(() => {
|
|
95061
95513
|
init_types();
|
|
95062
95514
|
init_participant();
|
|
@@ -95069,7 +95521,6 @@ var init_agent_process_manager = __esm(() => {
|
|
|
95069
95521
|
init_agent_lifecycle();
|
|
95070
95522
|
init_abort_resume_storm();
|
|
95071
95523
|
init_classify_resume_storm_reason();
|
|
95072
|
-
init_terminal_provider_error();
|
|
95073
95524
|
init_handle_turn_completed();
|
|
95074
95525
|
init_spawn_policy();
|
|
95075
95526
|
init_agent_lifecycle_runtime();
|
|
@@ -108577,10 +109028,19 @@ function isPendingAliveRunningTask(task) {
|
|
|
108577
109028
|
const { agentConfig, status: status3 } = task;
|
|
108578
109029
|
return status3 === "pending" && agentConfig.spawnedAgentPid != null && agentConfig.desiredState === "running";
|
|
108579
109030
|
}
|
|
108580
|
-
function isSlotUnavailableForPid(slot, pid, isPidAlive) {
|
|
108581
|
-
if (!slot
|
|
109031
|
+
function isSlotUnavailableForPid(slot, pid, isPidAlive, now = Date.now()) {
|
|
109032
|
+
if (!slot) {
|
|
109033
|
+
return true;
|
|
109034
|
+
}
|
|
109035
|
+
if (slot.state === "idle") {
|
|
108582
109036
|
return true;
|
|
108583
109037
|
}
|
|
109038
|
+
if (slot.state === "stopping") {
|
|
109039
|
+
if (!slot.stoppingSince || now - slot.stoppingSince >= STOPPING_TIMEOUT_MS) {
|
|
109040
|
+
return true;
|
|
109041
|
+
}
|
|
109042
|
+
return false;
|
|
109043
|
+
}
|
|
108584
109044
|
if (slot.pid !== pid) {
|
|
108585
109045
|
return true;
|
|
108586
109046
|
}
|
|
@@ -108596,7 +109056,7 @@ function isNativeRevivableTaskStatus(task) {
|
|
|
108596
109056
|
}
|
|
108597
109057
|
return false;
|
|
108598
109058
|
}
|
|
108599
|
-
function isNativeAgentSlotDown(task, health) {
|
|
109059
|
+
function isNativeAgentSlotDown(task, health, now = Date.now()) {
|
|
108600
109060
|
const slot = health.getSlot(task.chatroomId, task.agentConfig.role);
|
|
108601
109061
|
if (slot?.state === "spawning")
|
|
108602
109062
|
return false;
|
|
@@ -108604,20 +109064,20 @@ function isNativeAgentSlotDown(task, health) {
|
|
|
108604
109064
|
if (pid == null) {
|
|
108605
109065
|
return slot?.state !== "running";
|
|
108606
109066
|
}
|
|
108607
|
-
return isSlotUnavailableForPid(slot, pid, health.isPidAlive);
|
|
109067
|
+
return isSlotUnavailableForPid(slot, pid, health.isPidAlive, now);
|
|
108608
109068
|
}
|
|
108609
|
-
function isNativeActiveTaskAgentDown(task, health) {
|
|
109069
|
+
function isNativeActiveTaskAgentDown(task, health, now) {
|
|
108610
109070
|
if (!isNativeHarness(task.agentConfig.agentHarness))
|
|
108611
109071
|
return false;
|
|
108612
109072
|
if (task.agentConfig.desiredState !== "running")
|
|
108613
109073
|
return false;
|
|
108614
109074
|
if (!isNativeRevivableTaskStatus(task))
|
|
108615
109075
|
return false;
|
|
108616
|
-
return isNativeAgentSlotDown(task, health);
|
|
109076
|
+
return isNativeAgentSlotDown(task, health, now);
|
|
108617
109077
|
}
|
|
108618
109078
|
function listNativeTasksNeedingRevive(tasks, health, now, cooldown) {
|
|
108619
109079
|
return tasks.filter((task) => {
|
|
108620
|
-
if (!isNativeActiveTaskAgentDown(task, health))
|
|
109080
|
+
if (!isNativeActiveTaskAgentDown(task, health, now))
|
|
108621
109081
|
return false;
|
|
108622
109082
|
const { chatroomId, agentConfig } = task;
|
|
108623
109083
|
if (!agentConfig.workingDir)
|
|
@@ -108677,6 +109137,7 @@ var PENDING_IDLE_NUDGE_MS = 15000, NUDGE_COOLDOWN_MS = 60000;
|
|
|
108677
109137
|
var init_task_monitor_logic = __esm(() => {
|
|
108678
109138
|
init_native_task_injector_logic();
|
|
108679
109139
|
init_predicates();
|
|
109140
|
+
init_agent_process_manager();
|
|
108680
109141
|
});
|
|
108681
109142
|
// ../../services/backend/src/domain/usecase/machine/assigned-task-monitor-row.ts
|
|
108682
109143
|
function applyAssignedTaskSignal(existing, signal) {
|
|
@@ -109319,8 +109780,15 @@ function runCliNudgeEffect(task, runtime4, effectContext2, agentMgr, sessionDeps
|
|
|
109319
109780
|
console.log(buildCliNudgeLogLine(task));
|
|
109320
109781
|
executeCliNudge(task, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
|
|
109321
109782
|
}
|
|
109783
|
+
async function clearStuckStoppingSlotIfNeeded(agentMgr, chatroomId, role) {
|
|
109784
|
+
const cleared = await agentMgr.clearStuckStoppingSlot(chatroomId, role);
|
|
109785
|
+
if (cleared) {
|
|
109786
|
+
console.log(`[TaskMonitor] cleared stuck stopping slot for ${role}@${chatroomId}`);
|
|
109787
|
+
}
|
|
109788
|
+
}
|
|
109322
109789
|
async function nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
|
|
109323
109790
|
for (const row of listTasksReadyForNudge(tasks, now, cooldown)) {
|
|
109791
|
+
await clearStuckStoppingSlotIfNeeded(agentMgr, row.chatroomId, row.agentConfig.role);
|
|
109324
109792
|
const full = await fetchTaskForAction(sessionDeps, machineId, row);
|
|
109325
109793
|
if (!full)
|
|
109326
109794
|
continue;
|
|
@@ -109329,6 +109797,7 @@ async function nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, a
|
|
|
109329
109797
|
}
|
|
109330
109798
|
async function reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
|
|
109331
109799
|
for (const row of listNativeTasksNeedingRevive(tasks, localHealth, now, cooldown)) {
|
|
109800
|
+
await clearStuckStoppingSlotIfNeeded(agentMgr, row.chatroomId, row.agentConfig.role);
|
|
109332
109801
|
const full = await fetchTaskForAction(sessionDeps, machineId, row);
|
|
109333
109802
|
if (!full)
|
|
109334
109803
|
continue;
|
|
@@ -109579,7 +110048,7 @@ function handleGitRefreshCommandEffect(event, tracker) {
|
|
|
109579
110048
|
const lastPushedGitState = yield* exports_Ref.get(mutable2.lastPushedGitState);
|
|
109580
110049
|
lastPushedGitState.delete(makeGitStateKey(session2.machineId, typedEvent.workingDir));
|
|
109581
110050
|
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Git refresh requested for ${typedEvent.workingDir}`);
|
|
109582
|
-
yield*
|
|
110051
|
+
yield* pushSingleWorkspaceGitStateEffect(typedEvent.workingDir);
|
|
109583
110052
|
tracker.gitRefreshIds.set(eventId, Date.now());
|
|
109584
110053
|
});
|
|
109585
110054
|
}
|
|
@@ -110988,4 +111457,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
110988
111457
|
});
|
|
110989
111458
|
program2.parse();
|
|
110990
111459
|
|
|
110991
|
-
//# debugId=
|
|
111460
|
+
//# debugId=B0C2AFBAB3CD49E664756E2164756E21
|