chatroom-cli 1.65.2 → 1.65.5
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 +730 -247
- package/dist/index.js.map +32 -28
- 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,10 +36595,10 @@ 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;
|
|
36601
|
+
outputCallbacksByPid = new Map;
|
|
36601
36602
|
id = "opencode-sdk";
|
|
36602
36603
|
displayName = "OpenCode (SDK)";
|
|
36603
36604
|
listModelsHarnessId = "opencode-sdk";
|
|
@@ -36638,7 +36639,7 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36638
36639
|
await super.stop(pid);
|
|
36639
36640
|
}
|
|
36640
36641
|
spawnServeProcess(workingDir, resolvedConvexUrl) {
|
|
36641
|
-
const childProcess = this.deps.spawn(OPENCODE_COMMAND2, ["serve", "--print-logs"], {
|
|
36642
|
+
const childProcess = this.deps.spawn(OPENCODE_COMMAND2, ["serve", "--print-logs", "--log-level", "WARN"], {
|
|
36642
36643
|
cwd: workingDir,
|
|
36643
36644
|
stdio: ["pipe", "pipe", "pipe"],
|
|
36644
36645
|
shell: false,
|
|
@@ -36677,11 +36678,8 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36677
36678
|
}
|
|
36678
36679
|
if (childProcess.stderr) {
|
|
36679
36680
|
const stderrBuffer = new StderrLineBuffer((line) => {
|
|
36680
|
-
|
|
36681
|
-
|
|
36682
|
-
if (activeForwarder && isNonRetryableHarnessFailureText(line)) {
|
|
36683
|
-
activeForwarder.abortTerminalProviderError();
|
|
36684
|
-
}
|
|
36681
|
+
if (!isInfoLine(line))
|
|
36682
|
+
emitLogLine(line);
|
|
36685
36683
|
});
|
|
36686
36684
|
childProcess.stderr.on("data", (chunk2) => {
|
|
36687
36685
|
entry.lastOutputAt = Date.now();
|
|
@@ -36694,6 +36692,18 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36694
36692
|
});
|
|
36695
36693
|
}
|
|
36696
36694
|
}
|
|
36695
|
+
createSessionForwarder(client4, sessionId, context5, emitLogLine, emitAssistantText, outputCallbacks) {
|
|
36696
|
+
return startSessionEventForwarder(client4, {
|
|
36697
|
+
sessionId,
|
|
36698
|
+
role: context5.role,
|
|
36699
|
+
onLogLine: emitLogLine,
|
|
36700
|
+
onAssistantText: emitAssistantText,
|
|
36701
|
+
onActivity: () => {
|
|
36702
|
+
for (const cb of outputCallbacks)
|
|
36703
|
+
cb();
|
|
36704
|
+
}
|
|
36705
|
+
});
|
|
36706
|
+
}
|
|
36697
36707
|
registerRunningSession(args2) {
|
|
36698
36708
|
const {
|
|
36699
36709
|
childProcess,
|
|
@@ -36726,6 +36736,9 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36726
36736
|
if (args2.assistantTextCallbacks) {
|
|
36727
36737
|
this.assistantTextCallbacksByPid.set(pid, args2.assistantTextCallbacks);
|
|
36728
36738
|
}
|
|
36739
|
+
if (args2.outputCallbacks) {
|
|
36740
|
+
this.outputCallbacksByPid.set(pid, args2.outputCallbacks);
|
|
36741
|
+
}
|
|
36729
36742
|
const outputCallbacks = args2.outputCallbacks ?? [];
|
|
36730
36743
|
this.wireChildOutput(childProcess, pid, entry, emitLogLine, outputCallbacks);
|
|
36731
36744
|
return {
|
|
@@ -36745,6 +36758,7 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36745
36758
|
this.sessionStore.remove(sessionId);
|
|
36746
36759
|
this.agentEndCallbacksByPid.delete(pid);
|
|
36747
36760
|
this.assistantTextCallbacksByPid.delete(pid);
|
|
36761
|
+
this.outputCallbacksByPid.delete(pid);
|
|
36748
36762
|
this.deleteProcess(pid);
|
|
36749
36763
|
cb({ code: code2, signal, context: context5 });
|
|
36750
36764
|
});
|
|
@@ -36834,13 +36848,20 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36834
36848
|
throw new Error("Failed to create session during resume fallback");
|
|
36835
36849
|
}
|
|
36836
36850
|
const newSessionId2 = sessionCreateResult.data.id;
|
|
36851
|
+
const { emitLogLine } = this.createLogLineEmitter();
|
|
36852
|
+
const pidOutputCallbacks = this.outputCallbacksByPid.get(args2.pid) ?? [];
|
|
36837
36853
|
const forwarder = startSessionEventForwarder(client4, {
|
|
36838
36854
|
sessionId: newSessionId2,
|
|
36839
36855
|
role: args2.context.role,
|
|
36856
|
+
onLogLine: emitLogLine,
|
|
36840
36857
|
onAssistantText: (text) => {
|
|
36841
36858
|
const callbacks2 = this.assistantTextCallbacksByPid.get(args2.pid) ?? [];
|
|
36842
36859
|
for (const cb of callbacks2)
|
|
36843
36860
|
cb(text);
|
|
36861
|
+
},
|
|
36862
|
+
onActivity: () => {
|
|
36863
|
+
for (const cb of pidOutputCallbacks)
|
|
36864
|
+
cb();
|
|
36844
36865
|
}
|
|
36845
36866
|
});
|
|
36846
36867
|
const callbacks = this.agentEndCallbacksByPid.get(args2.pid) ?? [];
|
|
@@ -36884,16 +36905,7 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36884
36905
|
if (!sessionInfo.data?.id) {
|
|
36885
36906
|
throw new Error(`OpenCode session ${sessionId} not found (sessions may not survive serve restart)`);
|
|
36886
36907
|
}
|
|
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
|
-
});
|
|
36908
|
+
forwarder = this.createSessionForwarder(client4, sessionId, context5, emitLogLine, emitAssistantText, outputCallbacks);
|
|
36897
36909
|
const availableAgents = await this.listAvailableAgents(client4);
|
|
36898
36910
|
const agentDef = availableAgents.find((a) => a.name === agentName);
|
|
36899
36911
|
const composedSystem = composeSystemPrompt(agentDef?.prompt, systemPrompt);
|
|
@@ -36941,16 +36953,7 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
36941
36953
|
throw new Error("Failed to create session");
|
|
36942
36954
|
}
|
|
36943
36955
|
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
|
-
});
|
|
36956
|
+
forwarder = this.createSessionForwarder(client4, sessionId, context5, emitLogLine, emitAssistantText, outputCallbacks);
|
|
36954
36957
|
const availableAgents = await this.listAvailableAgents(client4);
|
|
36955
36958
|
const selected = selectAgent(availableAgents);
|
|
36956
36959
|
agentName = selected.name;
|
|
@@ -37772,10 +37775,17 @@ var init_detection = __esm(() => {
|
|
|
37772
37775
|
var MACHINE_CONFIG_VERSION = "1";
|
|
37773
37776
|
|
|
37774
37777
|
// src/infrastructure/machine/storage.ts
|
|
37775
|
-
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
37778
|
+
import { randomBytes, randomUUID as randomUUID3 } from "node:crypto";
|
|
37776
37779
|
import * as fs4 from "node:fs/promises";
|
|
37777
37780
|
import { homedir as homedir3, hostname as hostname2 } from "node:os";
|
|
37778
37781
|
import { join as join11 } from "node:path";
|
|
37782
|
+
function enqueueMachineConfigSave(task) {
|
|
37783
|
+
const run3 = saveChain.then(task, task);
|
|
37784
|
+
saveChain = run3.catch(() => {
|
|
37785
|
+
return;
|
|
37786
|
+
});
|
|
37787
|
+
return run3;
|
|
37788
|
+
}
|
|
37779
37789
|
function chatroomConfigDir() {
|
|
37780
37790
|
return join11(homedir3(), ".chatroom");
|
|
37781
37791
|
}
|
|
@@ -37801,13 +37811,20 @@ async function loadConfigFile() {
|
|
|
37801
37811
|
return null;
|
|
37802
37812
|
}
|
|
37803
37813
|
}
|
|
37804
|
-
async function
|
|
37814
|
+
async function writeConfigFileAtomically(configFile) {
|
|
37805
37815
|
await ensureConfigDir2();
|
|
37806
37816
|
const configPath = getMachineConfigPath();
|
|
37807
|
-
const tempPath = `${configPath}.tmp`;
|
|
37817
|
+
const tempPath = `${configPath}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
|
|
37808
37818
|
const content = JSON.stringify(configFile, null, 2);
|
|
37809
37819
|
await fs4.writeFile(tempPath, content, { mode: 384 });
|
|
37810
|
-
|
|
37820
|
+
try {
|
|
37821
|
+
await fs4.rename(tempPath, configPath);
|
|
37822
|
+
} catch (error) {
|
|
37823
|
+
await fs4.unlink(tempPath).catch(() => {
|
|
37824
|
+
return;
|
|
37825
|
+
});
|
|
37826
|
+
throw error;
|
|
37827
|
+
}
|
|
37811
37828
|
}
|
|
37812
37829
|
async function loadMachineConfig() {
|
|
37813
37830
|
const configFile = await loadConfigFile();
|
|
@@ -37817,13 +37834,15 @@ async function loadMachineConfig() {
|
|
|
37817
37834
|
return configFile.machines[convexUrl] ?? null;
|
|
37818
37835
|
}
|
|
37819
37836
|
async function saveMachineConfig(config2) {
|
|
37820
|
-
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
|
|
37824
|
-
|
|
37825
|
-
|
|
37826
|
-
|
|
37837
|
+
await enqueueMachineConfigSave(async () => {
|
|
37838
|
+
const configFile = await loadConfigFile() ?? {
|
|
37839
|
+
version: MACHINE_CONFIG_VERSION,
|
|
37840
|
+
machines: {}
|
|
37841
|
+
};
|
|
37842
|
+
const convexUrl = getConvexUrl();
|
|
37843
|
+
configFile.machines[convexUrl] = config2;
|
|
37844
|
+
await writeConfigFileAtomically(configFile);
|
|
37845
|
+
});
|
|
37827
37846
|
}
|
|
37828
37847
|
async function createNewEndpointConfig() {
|
|
37829
37848
|
const now = new Date().toISOString();
|
|
@@ -37867,10 +37886,11 @@ async function getMachineId() {
|
|
|
37867
37886
|
const config2 = await loadMachineConfig();
|
|
37868
37887
|
return config2?.machineId ?? null;
|
|
37869
37888
|
}
|
|
37870
|
-
var MACHINE_FILE = "machine.json";
|
|
37889
|
+
var MACHINE_FILE = "machine.json", saveChain;
|
|
37871
37890
|
var init_storage2 = __esm(() => {
|
|
37872
37891
|
init_detection();
|
|
37873
37892
|
init_client2();
|
|
37893
|
+
saveChain = Promise.resolve();
|
|
37874
37894
|
});
|
|
37875
37895
|
|
|
37876
37896
|
// src/infrastructure/machine/daemon-state.ts
|
|
@@ -80480,6 +80500,8 @@ ${getRoleGuidanceDisclosureBlock(roleGuidanceContext)}
|
|
|
80480
80500
|
<!-- Demonstrate adherence to:
|
|
80481
80501
|
- Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
|
|
80482
80502
|
- 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.
|
|
80503
|
+
- No Revisit: implemented in a way so the user does not have to revisit this implementation again.
|
|
80504
|
+
- Leave It Better: leave the code in a slightly better state than before when touching files.
|
|
80483
80505
|
-->
|
|
80484
80506
|
<how this work follows the principles above — localized changes, readable structure, correctness provable from source then tests>
|
|
80485
80507
|
|
|
@@ -80641,6 +80663,8 @@ ${getRoleGuidanceDisclosureBlock(roleGuidanceContext)}
|
|
|
80641
80663
|
<!-- Demonstrate adherence to:
|
|
80642
80664
|
- Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
|
|
80643
80665
|
- 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.
|
|
80666
|
+
- No Revisit: implemented in a way so the user does not have to revisit this implementation again.
|
|
80667
|
+
- Leave It Better: leave the code in a slightly better state than before when touching files.
|
|
80644
80668
|
-->
|
|
80645
80669
|
<how this work follows the principles above — localized changes, readable structure, correctness provable from source then tests>
|
|
80646
80670
|
|
|
@@ -80741,6 +80765,8 @@ ${getRoleGuidanceDisclosureBlock(roleGuidanceContext)}
|
|
|
80741
80765
|
<!-- Demonstrate adherence to:
|
|
80742
80766
|
- Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
|
|
80743
80767
|
- 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.
|
|
80768
|
+
- No Revisit: implemented in a way so the user does not have to revisit this implementation again.
|
|
80769
|
+
- Leave It Better: leave the code in a slightly better state than before when touching files.
|
|
80744
80770
|
-->
|
|
80745
80771
|
<how this work follows the principles above — localized changes, readable structure, correctness provable from source then tests>
|
|
80746
80772
|
|
|
@@ -84686,6 +84712,7 @@ var DaemonMachineService, DaemonMachineServiceLive = (ops) => exports_Layer.succ
|
|
|
84686
84712
|
recover: () => exports_Effect.promise(() => mgr.recover()),
|
|
84687
84713
|
getSlot: (chatroomId, role) => mgr.getSlot(chatroomId, role),
|
|
84688
84714
|
listActive: () => mgr.listActive(),
|
|
84715
|
+
clearStuckStoppingSlot: (chatroomId, role) => exports_Effect.promise(() => mgr.clearStuckStoppingSlot(chatroomId, role)),
|
|
84689
84716
|
whenTurnEndsIdle: () => exports_Effect.promise(() => mgr.whenTurnEndsIdle()),
|
|
84690
84717
|
resumeTurnForSlot: (args2) => exports_Effect.promise(() => mgr.resumeTurnForSlot(args2)),
|
|
84691
84718
|
setLastInFlightTask: (chatroomId, role, taskId) => exports_Effect.sync(() => mgr.setLastInFlightTask(chatroomId, role, taskId))
|
|
@@ -86028,9 +86055,369 @@ var init_pid = __esm(() => {
|
|
|
86028
86055
|
CHATROOM_DIR4 = join17(homedir6(), ".chatroom");
|
|
86029
86056
|
});
|
|
86030
86057
|
|
|
86031
|
-
// src/infrastructure/harnesses/
|
|
86058
|
+
// src/infrastructure/harnesses/claude-sdk/claude-session.ts
|
|
86032
86059
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
86033
86060
|
|
|
86061
|
+
class ClaudeSdkSession {
|
|
86062
|
+
opencodeSessionId;
|
|
86063
|
+
_sessionTitle;
|
|
86064
|
+
get sessionTitle() {
|
|
86065
|
+
return this._sessionTitle;
|
|
86066
|
+
}
|
|
86067
|
+
cwd;
|
|
86068
|
+
executablePath;
|
|
86069
|
+
query;
|
|
86070
|
+
defaultModel;
|
|
86071
|
+
storedSystemPrompt;
|
|
86072
|
+
onClose;
|
|
86073
|
+
listeners = new Set;
|
|
86074
|
+
closed = false;
|
|
86075
|
+
providerSessionId;
|
|
86076
|
+
resumeOnFirstQuery;
|
|
86077
|
+
isFirstQuery = true;
|
|
86078
|
+
activeQuery;
|
|
86079
|
+
sawTextDelta = false;
|
|
86080
|
+
sawThinkingDelta = false;
|
|
86081
|
+
constructor(options) {
|
|
86082
|
+
this.cwd = options.cwd;
|
|
86083
|
+
this.executablePath = options.executablePath;
|
|
86084
|
+
this.query = options.query;
|
|
86085
|
+
this.opencodeSessionId = options.opencodeSessionId;
|
|
86086
|
+
this._sessionTitle = options.sessionTitle;
|
|
86087
|
+
this.defaultModel = options.defaultModel;
|
|
86088
|
+
this.storedSystemPrompt = options.systemPrompt;
|
|
86089
|
+
this.providerSessionId = options.providerSessionId;
|
|
86090
|
+
this.resumeOnFirstQuery = options.resumeOnFirstQuery ?? false;
|
|
86091
|
+
this.onClose = options.onClose;
|
|
86092
|
+
}
|
|
86093
|
+
setTitle(title) {
|
|
86094
|
+
this._sessionTitle = title;
|
|
86095
|
+
}
|
|
86096
|
+
async prompt(input) {
|
|
86097
|
+
if (this.closed)
|
|
86098
|
+
throw new Error("Session is closed");
|
|
86099
|
+
const text = input.parts.map((p) => p.text).join(`
|
|
86100
|
+
`);
|
|
86101
|
+
const messageId = randomUUID4();
|
|
86102
|
+
const model = resolveClaudeModel(this.defaultModel, input.model);
|
|
86103
|
+
const useResume = Boolean(this.providerSessionId) && (!this.isFirstQuery || this.resumeOnFirstQuery);
|
|
86104
|
+
this.sawTextDelta = false;
|
|
86105
|
+
this.sawThinkingDelta = false;
|
|
86106
|
+
const queryInstance = this.query({
|
|
86107
|
+
prompt: text,
|
|
86108
|
+
options: {
|
|
86109
|
+
cwd: this.cwd,
|
|
86110
|
+
model,
|
|
86111
|
+
maxTurns: DEFAULT_MAX_TURNS3,
|
|
86112
|
+
pathToClaudeCodeExecutable: this.executablePath,
|
|
86113
|
+
includePartialMessages: true,
|
|
86114
|
+
systemPrompt: this.isFirstQuery && !this.resumeOnFirstQuery ? this.storedSystemPrompt : undefined,
|
|
86115
|
+
resume: useResume ? this.providerSessionId : undefined,
|
|
86116
|
+
settingSources: [],
|
|
86117
|
+
permissionMode: "bypassPermissions",
|
|
86118
|
+
allowDangerouslySkipPermissions: true,
|
|
86119
|
+
effort: DEFAULT_EFFORT2,
|
|
86120
|
+
canUseTool: async (_toolName, toolInput) => ({
|
|
86121
|
+
behavior: "allow",
|
|
86122
|
+
updatedInput: toolInput
|
|
86123
|
+
})
|
|
86124
|
+
}
|
|
86125
|
+
});
|
|
86126
|
+
this.activeQuery = queryInstance;
|
|
86127
|
+
if (this.resumeOnFirstQuery) {
|
|
86128
|
+
this.resumeOnFirstQuery = false;
|
|
86129
|
+
}
|
|
86130
|
+
this.isFirstQuery = false;
|
|
86131
|
+
try {
|
|
86132
|
+
await withTimeout((async () => {
|
|
86133
|
+
for await (const message of queryInstance) {
|
|
86134
|
+
if (this.closed)
|
|
86135
|
+
break;
|
|
86136
|
+
this.captureProviderSessionId(message);
|
|
86137
|
+
this.emitFromSdkMessage(message, messageId);
|
|
86138
|
+
if (message.type === "result") {
|
|
86139
|
+
if (message.is_error) {
|
|
86140
|
+
const errors2 = "errors" in message && Array.isArray(message.errors) ? message.errors.join("; ") : "turn failed";
|
|
86141
|
+
throw new Error(errors2);
|
|
86142
|
+
}
|
|
86143
|
+
break;
|
|
86144
|
+
}
|
|
86145
|
+
}
|
|
86146
|
+
})(), QUERY_TIMEOUT_MS, "query");
|
|
86147
|
+
} finally {
|
|
86148
|
+
this.activeQuery = undefined;
|
|
86149
|
+
}
|
|
86150
|
+
this.emit({ type: "session.idle", payload: {}, timestamp: Date.now() });
|
|
86151
|
+
}
|
|
86152
|
+
onEvent(listener) {
|
|
86153
|
+
this.listeners.add(listener);
|
|
86154
|
+
return () => {
|
|
86155
|
+
this.listeners.delete(listener);
|
|
86156
|
+
};
|
|
86157
|
+
}
|
|
86158
|
+
async close() {
|
|
86159
|
+
if (this.closed)
|
|
86160
|
+
return;
|
|
86161
|
+
this.closed = true;
|
|
86162
|
+
try {
|
|
86163
|
+
await this.activeQuery?.interrupt();
|
|
86164
|
+
} catch {}
|
|
86165
|
+
this.activeQuery = undefined;
|
|
86166
|
+
this.onClose?.(this.opencodeSessionId);
|
|
86167
|
+
this.listeners.clear();
|
|
86168
|
+
}
|
|
86169
|
+
emit(event) {
|
|
86170
|
+
for (const listener of this.listeners) {
|
|
86171
|
+
listener(event);
|
|
86172
|
+
}
|
|
86173
|
+
}
|
|
86174
|
+
emitDelta(messageId, delta, partType) {
|
|
86175
|
+
if (!delta)
|
|
86176
|
+
return;
|
|
86177
|
+
this.emit({
|
|
86178
|
+
type: "message.part.delta",
|
|
86179
|
+
payload: { messageID: messageId, delta, partType },
|
|
86180
|
+
timestamp: Date.now()
|
|
86181
|
+
});
|
|
86182
|
+
}
|
|
86183
|
+
captureProviderSessionId(message) {
|
|
86184
|
+
if (!("session_id" in message) || typeof message.session_id !== "string") {
|
|
86185
|
+
return;
|
|
86186
|
+
}
|
|
86187
|
+
const sessionId = message.session_id;
|
|
86188
|
+
if (this.providerSessionId === sessionId) {
|
|
86189
|
+
return;
|
|
86190
|
+
}
|
|
86191
|
+
const isFirstAllocation = !this.providerSessionId;
|
|
86192
|
+
this.providerSessionId = sessionId;
|
|
86193
|
+
if (isFirstAllocation) {
|
|
86194
|
+
this.emit({
|
|
86195
|
+
type: "session.provider_id",
|
|
86196
|
+
payload: { sessionId },
|
|
86197
|
+
timestamp: Date.now()
|
|
86198
|
+
});
|
|
86199
|
+
}
|
|
86200
|
+
}
|
|
86201
|
+
emitFromSdkMessage(message, messageId) {
|
|
86202
|
+
switch (message.type) {
|
|
86203
|
+
case "stream_event": {
|
|
86204
|
+
const event = message.event;
|
|
86205
|
+
if (event.type === "content_block_delta") {
|
|
86206
|
+
const delta = event.delta;
|
|
86207
|
+
if (delta.type === "text_delta") {
|
|
86208
|
+
this.sawTextDelta = true;
|
|
86209
|
+
this.emitDelta(messageId, delta.text, "text");
|
|
86210
|
+
} else if (delta.type === "thinking_delta") {
|
|
86211
|
+
this.sawThinkingDelta = true;
|
|
86212
|
+
this.emitDelta(messageId, delta.thinking, "reasoning");
|
|
86213
|
+
}
|
|
86214
|
+
}
|
|
86215
|
+
break;
|
|
86216
|
+
}
|
|
86217
|
+
case "assistant":
|
|
86218
|
+
for (const block of message.message.content) {
|
|
86219
|
+
if (block.type === "text" && block.text) {
|
|
86220
|
+
if (!this.sawTextDelta) {
|
|
86221
|
+
this.emitDelta(messageId, block.text, "text");
|
|
86222
|
+
}
|
|
86223
|
+
} else if (block.type === "thinking" && block.thinking) {
|
|
86224
|
+
if (!this.sawThinkingDelta) {
|
|
86225
|
+
this.emitDelta(messageId, block.thinking, "reasoning");
|
|
86226
|
+
}
|
|
86227
|
+
}
|
|
86228
|
+
}
|
|
86229
|
+
break;
|
|
86230
|
+
default:
|
|
86231
|
+
break;
|
|
86232
|
+
}
|
|
86233
|
+
}
|
|
86234
|
+
}
|
|
86235
|
+
function resolveClaudeModel(defaultModel, promptModel) {
|
|
86236
|
+
if (promptModel) {
|
|
86237
|
+
if (promptModel.providerID === "anthropic")
|
|
86238
|
+
return promptModel.modelID;
|
|
86239
|
+
return promptModel.modelID;
|
|
86240
|
+
}
|
|
86241
|
+
if (defaultModel) {
|
|
86242
|
+
const slash = defaultModel.indexOf("/");
|
|
86243
|
+
if (slash === -1)
|
|
86244
|
+
return defaultModel;
|
|
86245
|
+
const provider = defaultModel.slice(0, slash);
|
|
86246
|
+
const modelId = defaultModel.slice(slash + 1);
|
|
86247
|
+
if (provider === "anthropic")
|
|
86248
|
+
return modelId;
|
|
86249
|
+
return modelId;
|
|
86250
|
+
}
|
|
86251
|
+
return "sonnet";
|
|
86252
|
+
}
|
|
86253
|
+
var DEFAULT_MAX_TURNS3 = 200, DEFAULT_EFFORT2 = "medium", QUERY_TIMEOUT_MS = 3600000;
|
|
86254
|
+
var init_claude_session = () => {};
|
|
86255
|
+
|
|
86256
|
+
// src/infrastructure/harnesses/claude-sdk/claude-harness.ts
|
|
86257
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
86258
|
+
async function loadSdk4() {
|
|
86259
|
+
if (_sdkCache4)
|
|
86260
|
+
return _sdkCache4;
|
|
86261
|
+
if (_sdkLoadError4)
|
|
86262
|
+
throw _sdkLoadError4;
|
|
86263
|
+
try {
|
|
86264
|
+
_sdkCache4 = await importBundledClaudeSdk();
|
|
86265
|
+
return _sdkCache4;
|
|
86266
|
+
} catch (err) {
|
|
86267
|
+
_sdkLoadError4 = err;
|
|
86268
|
+
throw err;
|
|
86269
|
+
}
|
|
86270
|
+
}
|
|
86271
|
+
async function loadExecutablePath() {
|
|
86272
|
+
if (_executablePathCache)
|
|
86273
|
+
return _executablePathCache;
|
|
86274
|
+
_executablePathCache = await resolvePathToClaudeCodeExecutable();
|
|
86275
|
+
return _executablePathCache;
|
|
86276
|
+
}
|
|
86277
|
+
|
|
86278
|
+
class ClaudeSdkHarness {
|
|
86279
|
+
type = "claude-sdk";
|
|
86280
|
+
displayName = "Claude (SDK)";
|
|
86281
|
+
cwd;
|
|
86282
|
+
query;
|
|
86283
|
+
executablePath;
|
|
86284
|
+
closed = false;
|
|
86285
|
+
sessions = new Map;
|
|
86286
|
+
constructor(cwd, sdk, executablePath) {
|
|
86287
|
+
this.cwd = cwd;
|
|
86288
|
+
this.query = sdk.query;
|
|
86289
|
+
this.executablePath = executablePath;
|
|
86290
|
+
}
|
|
86291
|
+
async models() {
|
|
86292
|
+
const providers = await this.listProviders();
|
|
86293
|
+
const models = [];
|
|
86294
|
+
for (const provider of providers) {
|
|
86295
|
+
for (const model of provider.models) {
|
|
86296
|
+
models.push({
|
|
86297
|
+
id: `${provider.providerID}/${model.modelID}`,
|
|
86298
|
+
name: model.name,
|
|
86299
|
+
provider: provider.name
|
|
86300
|
+
});
|
|
86301
|
+
}
|
|
86302
|
+
}
|
|
86303
|
+
return models;
|
|
86304
|
+
}
|
|
86305
|
+
async listAgents() {
|
|
86306
|
+
return [{ name: "builder", mode: "primary" }];
|
|
86307
|
+
}
|
|
86308
|
+
async listProviders() {
|
|
86309
|
+
const dynamic = await fetchClaudeModels();
|
|
86310
|
+
const modelIds = dynamic ?? [...CLAUDE_FALLBACK_MODELS];
|
|
86311
|
+
return [
|
|
86312
|
+
{
|
|
86313
|
+
providerID: "anthropic",
|
|
86314
|
+
name: "Anthropic",
|
|
86315
|
+
models: modelIds.map((modelID) => ({ modelID, name: modelID }))
|
|
86316
|
+
}
|
|
86317
|
+
];
|
|
86318
|
+
}
|
|
86319
|
+
async newSession(config3) {
|
|
86320
|
+
if (this.closed)
|
|
86321
|
+
throw new Error("Harness is closed");
|
|
86322
|
+
const opencodeSessionId = randomUUID5();
|
|
86323
|
+
const session2 = new ClaudeSdkSession({
|
|
86324
|
+
cwd: this.cwd,
|
|
86325
|
+
executablePath: this.executablePath,
|
|
86326
|
+
query: this.query,
|
|
86327
|
+
opencodeSessionId,
|
|
86328
|
+
sessionTitle: config3.title ?? "",
|
|
86329
|
+
defaultModel: config3.model ?? DEFAULT_MODEL2,
|
|
86330
|
+
systemPrompt: config3.systemPrompt,
|
|
86331
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
86332
|
+
});
|
|
86333
|
+
this.sessions.set(opencodeSessionId, session2);
|
|
86334
|
+
return session2;
|
|
86335
|
+
}
|
|
86336
|
+
async resumeSession(sessionId, _options) {
|
|
86337
|
+
if (this.closed)
|
|
86338
|
+
throw new Error("Harness is closed");
|
|
86339
|
+
const existing = this.sessions.get(sessionId);
|
|
86340
|
+
if (existing)
|
|
86341
|
+
return existing;
|
|
86342
|
+
const session2 = new ClaudeSdkSession({
|
|
86343
|
+
cwd: this.cwd,
|
|
86344
|
+
executablePath: this.executablePath,
|
|
86345
|
+
query: this.query,
|
|
86346
|
+
opencodeSessionId: sessionId,
|
|
86347
|
+
sessionTitle: "",
|
|
86348
|
+
providerSessionId: sessionId,
|
|
86349
|
+
resumeOnFirstQuery: true,
|
|
86350
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
86351
|
+
});
|
|
86352
|
+
this.sessions.set(sessionId, session2);
|
|
86353
|
+
return session2;
|
|
86354
|
+
}
|
|
86355
|
+
async fetchSessionTitle(_opencodeSessionId) {
|
|
86356
|
+
return;
|
|
86357
|
+
}
|
|
86358
|
+
isAlive() {
|
|
86359
|
+
return !this.closed;
|
|
86360
|
+
}
|
|
86361
|
+
async close() {
|
|
86362
|
+
if (this.closed)
|
|
86363
|
+
return;
|
|
86364
|
+
this.closed = true;
|
|
86365
|
+
const closing = [...this.sessions.values()].map((s) => s.close().catch(() => {}));
|
|
86366
|
+
await Promise.all(closing);
|
|
86367
|
+
this.sessions.clear();
|
|
86368
|
+
}
|
|
86369
|
+
}
|
|
86370
|
+
var DEFAULT_MODEL2 = "anthropic/sonnet", _sdkCache4, _sdkLoadError4, _executablePathCache, startClaudeSdkHarness = async (config3) => {
|
|
86371
|
+
try {
|
|
86372
|
+
const sdk = await loadSdk4();
|
|
86373
|
+
const executablePath = await loadExecutablePath();
|
|
86374
|
+
return new ClaudeSdkHarness(config3.workingDir, sdk, executablePath);
|
|
86375
|
+
} catch (err) {
|
|
86376
|
+
throw new Error(`claude-sdk unavailable: ${formatClaudeSdkLoadError(err)}`);
|
|
86377
|
+
}
|
|
86378
|
+
};
|
|
86379
|
+
var init_claude_harness = __esm(() => {
|
|
86380
|
+
init_claude_session();
|
|
86381
|
+
init_claude_models();
|
|
86382
|
+
init_claude_sdk_package();
|
|
86383
|
+
});
|
|
86384
|
+
|
|
86385
|
+
// src/infrastructure/harnesses/shared-chunk-extractor.ts
|
|
86386
|
+
function createStandardSdkChunkExtractor() {
|
|
86387
|
+
return function extract(event) {
|
|
86388
|
+
if (event.type !== "message.part.delta")
|
|
86389
|
+
return null;
|
|
86390
|
+
const payload = event.payload;
|
|
86391
|
+
const delta = payload?.delta;
|
|
86392
|
+
if (!delta || delta.length === 0)
|
|
86393
|
+
return null;
|
|
86394
|
+
const messageId = payload?.messageID;
|
|
86395
|
+
if (!messageId)
|
|
86396
|
+
return null;
|
|
86397
|
+
return {
|
|
86398
|
+
content: delta,
|
|
86399
|
+
messageId,
|
|
86400
|
+
partType: payload?.partType ?? "text"
|
|
86401
|
+
};
|
|
86402
|
+
};
|
|
86403
|
+
}
|
|
86404
|
+
|
|
86405
|
+
// src/infrastructure/harnesses/claude-sdk/event-extractor.ts
|
|
86406
|
+
function createClaudeSdkChunkExtractor() {
|
|
86407
|
+
return createStandardSdkChunkExtractor();
|
|
86408
|
+
}
|
|
86409
|
+
var init_event_extractor = () => {};
|
|
86410
|
+
|
|
86411
|
+
// src/infrastructure/harnesses/claude-sdk/index.ts
|
|
86412
|
+
var init_claude_sdk2 = __esm(() => {
|
|
86413
|
+
init_claude_harness();
|
|
86414
|
+
init_claude_session();
|
|
86415
|
+
init_event_extractor();
|
|
86416
|
+
});
|
|
86417
|
+
|
|
86418
|
+
// src/infrastructure/harnesses/cursor-sdk/cursor-session.ts
|
|
86419
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
86420
|
+
|
|
86034
86421
|
class CursorSdkSession {
|
|
86035
86422
|
opencodeSessionId;
|
|
86036
86423
|
_sessionTitle;
|
|
@@ -86056,13 +86443,13 @@ class CursorSdkSession {
|
|
|
86056
86443
|
throw new Error("Session is closed");
|
|
86057
86444
|
const text = input.parts.map((p) => p.text).join(`
|
|
86058
86445
|
`);
|
|
86059
|
-
const messageId =
|
|
86446
|
+
const messageId = randomUUID6();
|
|
86060
86447
|
const isFirstTurn = this.turnCount === 0;
|
|
86061
86448
|
this.turnCount += 1;
|
|
86062
86449
|
const modelId = input.model ? resolveModelFromPrompt(input.model.providerID, input.model.modelID) : undefined;
|
|
86063
86450
|
const run3 = await withTimeout(this.agent.send(text, {
|
|
86064
86451
|
local: { force: isFirstTurn },
|
|
86065
|
-
idempotencyKey:
|
|
86452
|
+
idempotencyKey: randomUUID6(),
|
|
86066
86453
|
...modelId ? { model: { id: modelId } } : {}
|
|
86067
86454
|
}), SEND_TIMEOUT_MS2, "agent.send");
|
|
86068
86455
|
for await (const message of run3.stream()) {
|
|
@@ -86135,16 +86522,16 @@ var SEND_TIMEOUT_MS2 = 60000, RUN_WAIT_TIMEOUT_MS2 = 3600000;
|
|
|
86135
86522
|
var init_cursor_session = () => {};
|
|
86136
86523
|
|
|
86137
86524
|
// src/infrastructure/harnesses/cursor-sdk/cursor-harness.ts
|
|
86138
|
-
async function
|
|
86139
|
-
if (
|
|
86140
|
-
return
|
|
86141
|
-
if (
|
|
86142
|
-
throw
|
|
86525
|
+
async function loadSdk5() {
|
|
86526
|
+
if (_sdkCache5)
|
|
86527
|
+
return _sdkCache5;
|
|
86528
|
+
if (_sdkLoadError5)
|
|
86529
|
+
throw _sdkLoadError5;
|
|
86143
86530
|
try {
|
|
86144
|
-
|
|
86145
|
-
return
|
|
86531
|
+
_sdkCache5 = await importBundledCursorSdk();
|
|
86532
|
+
return _sdkCache5;
|
|
86146
86533
|
} catch (err) {
|
|
86147
|
-
|
|
86534
|
+
_sdkLoadError5 = err;
|
|
86148
86535
|
throw err;
|
|
86149
86536
|
}
|
|
86150
86537
|
}
|
|
@@ -86179,7 +86566,7 @@ class CursorSdkHarness {
|
|
|
86179
86566
|
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
86180
86567
|
if (!apiKey)
|
|
86181
86568
|
return [];
|
|
86182
|
-
const { Cursor } = await
|
|
86569
|
+
const { Cursor } = await loadSdk5();
|
|
86183
86570
|
const listed = await withTimeout(Cursor.models.list({ apiKey }), MODELS_LIST_TIMEOUT_MS2, "Cursor.models.list");
|
|
86184
86571
|
const modelIds = normalizeCursorSdkListedModels(listed.map((m) => m.id).filter((id3) => id3.length > 0));
|
|
86185
86572
|
return [
|
|
@@ -86196,8 +86583,8 @@ class CursorSdkHarness {
|
|
|
86196
86583
|
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
86197
86584
|
if (!apiKey)
|
|
86198
86585
|
throw new Error("CURSOR_API_KEY is not set");
|
|
86199
|
-
const modelId = resolveCursorSdkModel(config3.model ??
|
|
86200
|
-
const { Agent } = await
|
|
86586
|
+
const modelId = resolveCursorSdkModel(config3.model ?? DEFAULT_MODEL3);
|
|
86587
|
+
const { Agent } = await loadSdk5();
|
|
86201
86588
|
const agent = await withTimeout(Agent.create({
|
|
86202
86589
|
apiKey,
|
|
86203
86590
|
model: { id: modelId },
|
|
@@ -86221,10 +86608,10 @@ class CursorSdkHarness {
|
|
|
86221
86608
|
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
86222
86609
|
if (!apiKey)
|
|
86223
86610
|
throw new Error("CURSOR_API_KEY is not set");
|
|
86224
|
-
const { Agent } = await
|
|
86611
|
+
const { Agent } = await loadSdk5();
|
|
86225
86612
|
const agent = await withTimeout(Agent.resume(sessionId, {
|
|
86226
86613
|
apiKey,
|
|
86227
|
-
model: { id:
|
|
86614
|
+
model: { id: DEFAULT_MODEL3 },
|
|
86228
86615
|
local: { cwd: this.cwd, settingSources: [] }
|
|
86229
86616
|
}), AGENT_CREATE_TIMEOUT_MS2, "Agent.resume");
|
|
86230
86617
|
const session2 = new CursorSdkSession({
|
|
@@ -86251,9 +86638,9 @@ class CursorSdkHarness {
|
|
|
86251
86638
|
this.sessions.clear();
|
|
86252
86639
|
}
|
|
86253
86640
|
}
|
|
86254
|
-
var
|
|
86641
|
+
var DEFAULT_MODEL3 = "composer-2.5", MODELS_LIST_TIMEOUT_MS2 = 60000, AGENT_CREATE_TIMEOUT_MS2 = 60000, _sdkCache5, _sdkLoadError5, startCursorSdkHarness = async (config3) => {
|
|
86255
86642
|
try {
|
|
86256
|
-
await
|
|
86643
|
+
await loadSdk5();
|
|
86257
86644
|
} catch (err) {
|
|
86258
86645
|
throw new Error(`cursor-sdk unavailable: ${formatCursorSdkLoadError(err)}`);
|
|
86259
86646
|
}
|
|
@@ -86267,37 +86654,17 @@ var init_cursor_harness = __esm(() => {
|
|
|
86267
86654
|
init_cursor_sdk_package();
|
|
86268
86655
|
});
|
|
86269
86656
|
|
|
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
86657
|
// src/infrastructure/harnesses/cursor-sdk/event-extractor.ts
|
|
86291
86658
|
function createCursorSdkChunkExtractor() {
|
|
86292
86659
|
return createStandardSdkChunkExtractor();
|
|
86293
86660
|
}
|
|
86294
|
-
var
|
|
86661
|
+
var init_event_extractor2 = () => {};
|
|
86295
86662
|
|
|
86296
86663
|
// src/infrastructure/harnesses/cursor-sdk/index.ts
|
|
86297
86664
|
var init_cursor_sdk2 = __esm(() => {
|
|
86298
86665
|
init_cursor_harness();
|
|
86299
86666
|
init_cursor_session();
|
|
86300
|
-
|
|
86667
|
+
init_event_extractor2();
|
|
86301
86668
|
});
|
|
86302
86669
|
|
|
86303
86670
|
// src/infrastructure/harnesses/opencode-sdk/event-extractor.ts
|
|
@@ -86797,7 +87164,7 @@ class OpencodeSdkHarness {
|
|
|
86797
87164
|
}
|
|
86798
87165
|
}
|
|
86799
87166
|
var OPENCODE_COMMAND3 = "opencode", SERVE_STARTUP_TIMEOUT_MS2 = 1e4, startOpencodeSdkHarness = async (config3) => {
|
|
86800
|
-
const childProcess = spawn5(OPENCODE_COMMAND3, ["serve", "--print-logs"], {
|
|
87167
|
+
const childProcess = spawn5(OPENCODE_COMMAND3, ["serve", "--print-logs", "--log-level", "WARN"], {
|
|
86801
87168
|
cwd: config3.workingDir,
|
|
86802
87169
|
stdio: ["pipe", "pipe", "pipe"],
|
|
86803
87170
|
shell: false,
|
|
@@ -86831,7 +87198,7 @@ var init_opencode_harness = __esm(() => {
|
|
|
86831
87198
|
});
|
|
86832
87199
|
|
|
86833
87200
|
// src/infrastructure/harnesses/pi-sdk/pi-session.ts
|
|
86834
|
-
import { randomUUID as
|
|
87201
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
86835
87202
|
|
|
86836
87203
|
class PiSdkSession {
|
|
86837
87204
|
opencodeSessionId;
|
|
@@ -86858,7 +87225,7 @@ class PiSdkSession {
|
|
|
86858
87225
|
throw new Error("Session is closed");
|
|
86859
87226
|
const text = input.parts.map((p) => p.text).join(`
|
|
86860
87227
|
`);
|
|
86861
|
-
const messageId =
|
|
87228
|
+
const messageId = randomUUID7();
|
|
86862
87229
|
const onSessionEvent = (event) => {
|
|
86863
87230
|
if (this.closed)
|
|
86864
87231
|
return;
|
|
@@ -86918,16 +87285,16 @@ var PROMPT_TIMEOUT_MS2 = 3600000;
|
|
|
86918
87285
|
var init_pi_session = () => {};
|
|
86919
87286
|
|
|
86920
87287
|
// src/infrastructure/harnesses/pi-sdk/pi-harness.ts
|
|
86921
|
-
async function
|
|
86922
|
-
if (
|
|
86923
|
-
return
|
|
86924
|
-
if (
|
|
86925
|
-
throw
|
|
87288
|
+
async function loadSdk6() {
|
|
87289
|
+
if (_sdkCache6)
|
|
87290
|
+
return _sdkCache6;
|
|
87291
|
+
if (_sdkLoadError6)
|
|
87292
|
+
throw _sdkLoadError6;
|
|
86926
87293
|
try {
|
|
86927
|
-
|
|
86928
|
-
return
|
|
87294
|
+
_sdkCache6 = await importBundledPiSdk();
|
|
87295
|
+
return _sdkCache6;
|
|
86929
87296
|
} catch (err) {
|
|
86930
|
-
|
|
87297
|
+
_sdkLoadError6 = err;
|
|
86931
87298
|
throw err;
|
|
86932
87299
|
}
|
|
86933
87300
|
}
|
|
@@ -86999,7 +87366,7 @@ class PiSdkHarness {
|
|
|
86999
87366
|
const existing = this.sessions.get(sessionId);
|
|
87000
87367
|
if (existing)
|
|
87001
87368
|
return existing;
|
|
87002
|
-
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await
|
|
87369
|
+
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk6();
|
|
87003
87370
|
const sessions = await SessionManager.list(this.cwd, getPiSessionDir(this.cwd));
|
|
87004
87371
|
const match17 = sessions.find((s) => s.id === sessionId);
|
|
87005
87372
|
if (!match17) {
|
|
@@ -87047,8 +87414,8 @@ class PiSdkHarness {
|
|
|
87047
87414
|
this.sessions.clear();
|
|
87048
87415
|
}
|
|
87049
87416
|
async createAgentSession(systemPrompt, model) {
|
|
87050
|
-
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await
|
|
87051
|
-
const resolvedModel = resolveModel2(this.modelRegistry, model ??
|
|
87417
|
+
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk6();
|
|
87418
|
+
const resolvedModel = resolveModel2(this.modelRegistry, model ?? DEFAULT_MODEL4);
|
|
87052
87419
|
if (!resolvedModel) {
|
|
87053
87420
|
throw new Error("No Pi model available — configure provider credentials in ~/.pi/agent/auth.json");
|
|
87054
87421
|
}
|
|
@@ -87069,9 +87436,9 @@ class PiSdkHarness {
|
|
|
87069
87436
|
return session2;
|
|
87070
87437
|
}
|
|
87071
87438
|
}
|
|
87072
|
-
var SESSION_CREATE_TIMEOUT_MS3 = 60000,
|
|
87439
|
+
var SESSION_CREATE_TIMEOUT_MS3 = 60000, DEFAULT_MODEL4 = "opencode/big-pickle", _sdkCache6, _sdkLoadError6, startPiSdkHarness = async (config3) => {
|
|
87073
87440
|
try {
|
|
87074
|
-
const { AuthStorage, ModelRegistry } = await
|
|
87441
|
+
const { AuthStorage, ModelRegistry } = await loadSdk6();
|
|
87075
87442
|
const authStorage = AuthStorage.create();
|
|
87076
87443
|
const modelRegistry = ModelRegistry.create(authStorage);
|
|
87077
87444
|
if (modelRegistry.getAvailable().length === 0) {
|
|
@@ -87092,13 +87459,13 @@ var init_pi_harness = __esm(() => {
|
|
|
87092
87459
|
function createPiSdkChunkExtractor() {
|
|
87093
87460
|
return createStandardSdkChunkExtractor();
|
|
87094
87461
|
}
|
|
87095
|
-
var
|
|
87462
|
+
var init_event_extractor3 = () => {};
|
|
87096
87463
|
|
|
87097
87464
|
// src/infrastructure/harnesses/pi-sdk/index.ts
|
|
87098
87465
|
var init_pi_sdk2 = __esm(() => {
|
|
87099
87466
|
init_pi_harness();
|
|
87100
87467
|
init_pi_session();
|
|
87101
|
-
|
|
87468
|
+
init_event_extractor3();
|
|
87102
87469
|
});
|
|
87103
87470
|
|
|
87104
87471
|
// src/infrastructure/harnesses/registry.ts
|
|
@@ -87111,6 +87478,8 @@ async function startBoundHarness(config3) {
|
|
|
87111
87478
|
return startCursorSdkHarness(config3);
|
|
87112
87479
|
case "pi-sdk":
|
|
87113
87480
|
return startPiSdkHarness(config3);
|
|
87481
|
+
case "claude-sdk":
|
|
87482
|
+
return startClaudeSdkHarness(config3);
|
|
87114
87483
|
default: {
|
|
87115
87484
|
const _exhaustive = config3.harnessName;
|
|
87116
87485
|
throw new Error(`Unsupported direct harness: ${String(_exhaustive)}`);
|
|
@@ -87125,6 +87494,8 @@ function createChunkExtractor(harnessName) {
|
|
|
87125
87494
|
return createCursorSdkChunkExtractor();
|
|
87126
87495
|
case "pi-sdk":
|
|
87127
87496
|
return createPiSdkChunkExtractor();
|
|
87497
|
+
case "claude-sdk":
|
|
87498
|
+
return createClaudeSdkChunkExtractor();
|
|
87128
87499
|
default:
|
|
87129
87500
|
return createStandardSdkChunkExtractor();
|
|
87130
87501
|
}
|
|
@@ -87159,6 +87530,16 @@ async function isPiSdkInstalled() {
|
|
|
87159
87530
|
return false;
|
|
87160
87531
|
}
|
|
87161
87532
|
}
|
|
87533
|
+
async function isClaudeSdkInstalled() {
|
|
87534
|
+
try {
|
|
87535
|
+
const { importBundledClaudeSdk: importBundledClaudeSdk2, resolvePathToClaudeCodeExecutable: resolvePathToClaudeCodeExecutable2 } = await Promise.resolve().then(() => (init_claude_sdk_package(), exports_claude_sdk_package));
|
|
87536
|
+
await importBundledClaudeSdk2();
|
|
87537
|
+
await resolvePathToClaudeCodeExecutable2();
|
|
87538
|
+
return true;
|
|
87539
|
+
} catch {
|
|
87540
|
+
return false;
|
|
87541
|
+
}
|
|
87542
|
+
}
|
|
87162
87543
|
async function listInstalledNativeDirectHarnesses() {
|
|
87163
87544
|
const installed2 = [];
|
|
87164
87545
|
if (opencodeOnPath())
|
|
@@ -87167,9 +87548,12 @@ async function listInstalledNativeDirectHarnesses() {
|
|
|
87167
87548
|
installed2.push("cursor-sdk");
|
|
87168
87549
|
if (await isPiSdkInstalled())
|
|
87169
87550
|
installed2.push("pi-sdk");
|
|
87551
|
+
if (await isClaudeSdkInstalled())
|
|
87552
|
+
installed2.push("claude-sdk");
|
|
87170
87553
|
return installed2;
|
|
87171
87554
|
}
|
|
87172
87555
|
var init_registry4 = __esm(() => {
|
|
87556
|
+
init_claude_sdk2();
|
|
87173
87557
|
init_cursor_sdk2();
|
|
87174
87558
|
init_opencode_harness();
|
|
87175
87559
|
init_pi_sdk2();
|
|
@@ -87808,6 +88192,14 @@ function recordLiveSessionChunk(event, handle, journal, extractChunk, deps) {
|
|
|
87808
88192
|
deps.sessionRepository.bindTurnMessageId(handle.currentTurn.turnId, chunk2.messageId).catch((err) => console.warn("[direct-harness] bindTurnMessageId error:", err));
|
|
87809
88193
|
}
|
|
87810
88194
|
}
|
|
88195
|
+
function handleLiveSessionProviderId(event, deps, rowId, handle, liveSession) {
|
|
88196
|
+
if (event.type !== "session.provider_id")
|
|
88197
|
+
return;
|
|
88198
|
+
const sessionId = event.payload.sessionId;
|
|
88199
|
+
if (!sessionId || sessionId === handle.opencodeSessionId)
|
|
88200
|
+
return;
|
|
88201
|
+
deps.sessionRepository.associateOpenCodeSessionId(rowId, sessionId, liveSession.sessionTitle ?? "").catch((err) => console.warn("[direct-harness] associateOpenCodeSessionId (provider id) error:", err));
|
|
88202
|
+
}
|
|
87811
88203
|
function handleLiveSessionTitleUpdate(event, deps, rowId, liveSession) {
|
|
87812
88204
|
if (event.type !== "session.updated") {
|
|
87813
88205
|
return;
|
|
@@ -87827,6 +88219,7 @@ function handleLiveSessionEvent(event, ctx) {
|
|
|
87827
88219
|
handleSessionIdle(handle, journal, idleConfig, deps.sessionRepository).catch((err) => console.warn("[direct-harness] idle handler error:", err));
|
|
87828
88220
|
}
|
|
87829
88221
|
handleLiveSessionTitleUpdate(event, deps, rowId, liveSession);
|
|
88222
|
+
handleLiveSessionProviderId(event, deps, rowId, handle, liveSession);
|
|
87830
88223
|
}
|
|
87831
88224
|
async function processOne(daemonSession, deps, session2) {
|
|
87832
88225
|
const rowId = session2._id;
|
|
@@ -90962,7 +91355,7 @@ function diffPathIndexes(previous, next4) {
|
|
|
90962
91355
|
}
|
|
90963
91356
|
|
|
90964
91357
|
// src/infrastructure/services/workspace/workspace-sync-state.ts
|
|
90965
|
-
import { createHash as createHash6, randomUUID as
|
|
91358
|
+
import { createHash as createHash6, randomUUID as randomUUID8 } from "node:crypto";
|
|
90966
91359
|
import * as fs11 from "node:fs/promises";
|
|
90967
91360
|
import { homedir as homedir7 } from "node:os";
|
|
90968
91361
|
import { join as join20 } from "node:path";
|
|
@@ -91024,7 +91417,7 @@ function createManifestFromTree(args2) {
|
|
|
91024
91417
|
version: SYNC_STATE_VERSION,
|
|
91025
91418
|
machineId: args2.machineId,
|
|
91026
91419
|
workingDir: normalizeWorkingDirForLookup(args2.workingDir),
|
|
91027
|
-
syncGeneration:
|
|
91420
|
+
syncGeneration: randomUUID8(),
|
|
91028
91421
|
completedAt: Date.now(),
|
|
91029
91422
|
scanner: args2.scanner,
|
|
91030
91423
|
dataHash: args2.dataHash,
|
|
@@ -91046,7 +91439,7 @@ var init_workspace_sync_state = __esm(() => {
|
|
|
91046
91439
|
});
|
|
91047
91440
|
|
|
91048
91441
|
// src/infrastructure/services/workspace/workspace-file-tree-coordinator.ts
|
|
91049
|
-
import { randomUUID as
|
|
91442
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
91050
91443
|
import path6 from "node:path";
|
|
91051
91444
|
function deltaEntry(paths, pathValue) {
|
|
91052
91445
|
const type = paths[pathValue];
|
|
@@ -91073,7 +91466,7 @@ function buildPendingDeltas(previous, next4) {
|
|
|
91073
91466
|
const result = [];
|
|
91074
91467
|
for (let offset = 0;offset < operations.length; offset += MAX_DELTA_OPERATIONS) {
|
|
91075
91468
|
const delta = {
|
|
91076
|
-
operationId:
|
|
91469
|
+
operationId: randomUUID9(),
|
|
91077
91470
|
added: [],
|
|
91078
91471
|
removed: [],
|
|
91079
91472
|
typeChanged: [],
|
|
@@ -91297,7 +91690,7 @@ var init_workspace_file_tree_coordinator = __esm(() => {
|
|
|
91297
91690
|
});
|
|
91298
91691
|
|
|
91299
91692
|
// src/commands/machine/daemon-start/file-tree-subscription.ts
|
|
91300
|
-
import { randomUUID as
|
|
91693
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
91301
91694
|
import { gzipSync as gzipSync4 } from "node:zlib";
|
|
91302
91695
|
function logSubscriptionWarn(label, err) {
|
|
91303
91696
|
console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage2(err)}`);
|
|
@@ -91339,7 +91732,7 @@ function toDeltaOperations(delta) {
|
|
|
91339
91732
|
}
|
|
91340
91733
|
async function publishCheckpoint(session2, normalizedWorkingDir, tree, revision) {
|
|
91341
91734
|
const dataHash = computeFileTreeDataHash(tree);
|
|
91342
|
-
const syncGeneration =
|
|
91735
|
+
const syncGeneration = randomUUID10();
|
|
91343
91736
|
const snapshot = await syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, syncGeneration);
|
|
91344
91737
|
let checkpointRevision = revision;
|
|
91345
91738
|
let result = await session2.backend.mutation(api.workspaceFiles.publishFileTreeCheckpoint, {
|
|
@@ -91868,6 +92261,8 @@ async function pushAvailableGitState(ctx, workingDir, stateKey, branchResult) {
|
|
|
91868
92261
|
...pipeline2.toMutationArgs(values3, false)
|
|
91869
92262
|
});
|
|
91870
92263
|
ctx.lastPushedGitState.set(stateKey, stateHash);
|
|
92264
|
+
lastPushedBranch.set(stateKey, branch);
|
|
92265
|
+
lastFullPushMs.set(stateKey, Date.now());
|
|
91871
92266
|
console.log(`[${formatTimestamp()}] \uD83D\uDD00 Git state pushed: ${workingDir} (${branch}${values3.get("isDirty") ? ", dirty" : ", clean"})`);
|
|
91872
92267
|
}
|
|
91873
92268
|
if (ctx.lastPushedGitState.get(commitsKey) !== commitsHash) {
|
|
@@ -91919,6 +92314,7 @@ function pushObservedBranchErrorEffect(session2, lastPushedGitState, stateKey, w
|
|
|
91919
92314
|
function pushObservedFullGitStateEffect(session2, lastPushedGitState, stateKey, workingDir, branch, reason) {
|
|
91920
92315
|
return exports_Effect.gen(function* () {
|
|
91921
92316
|
yield* exports_Effect.promise(() => pushSingleWorkspaceGitStateImpl(buildGitStateDeps(session2, lastPushedGitState), workingDir));
|
|
92317
|
+
lastPushedBranch.set(stateKey, branch);
|
|
91922
92318
|
lastFullPushMs.set(stateKey, Date.now());
|
|
91923
92319
|
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed full git state pushed: ${workingDir} (${branch})${reason === "refresh" ? " [refresh]" : ""}`);
|
|
91924
92320
|
});
|
|
@@ -91948,7 +92344,7 @@ function pushObservedSlimGitSummaryEffect(session2, lastPushedGitState, stateKey
|
|
|
91948
92344
|
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed git summary pushed: ${workingDir} (${branch}${values3.get("isDirty") ? ", dirty" : ", clean"})${reason === "refresh" ? " [refresh]" : ""}`);
|
|
91949
92345
|
});
|
|
91950
92346
|
}
|
|
91951
|
-
var lastFullPushMs, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummaryForObservedEffect = (workingDir, reason = "safety-poll") => exports_Effect.gen(function* pushObservedGitSummaryForObserved() {
|
|
92347
|
+
var lastFullPushMs, lastPushedBranch, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummaryForObservedEffect = (workingDir, reason = "safety-poll") => exports_Effect.gen(function* pushObservedGitSummaryForObserved() {
|
|
91952
92348
|
const session2 = yield* DaemonSessionService;
|
|
91953
92349
|
const mutable2 = yield* DaemonMutableStateService;
|
|
91954
92350
|
const lastPushedGitState = yield* exports_Ref.get(mutable2.lastPushedGitState);
|
|
@@ -91969,7 +92365,10 @@ var lastFullPushMs, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummary
|
|
|
91969
92365
|
const branch = branchResult.branch;
|
|
91970
92366
|
const now = Date.now();
|
|
91971
92367
|
const lastFull = lastFullPushMs.get(stateKey) ?? 0;
|
|
91972
|
-
|
|
92368
|
+
const previousBranch = lastPushedBranch.get(stateKey);
|
|
92369
|
+
const branchChanged = previousBranch !== undefined && previousBranch !== branch;
|
|
92370
|
+
const needsFullPush = reason === "refresh" || branchChanged || now - lastFull >= OBSERVED_FULL_PUSH_INTERVAL_MS;
|
|
92371
|
+
if (needsFullPush) {
|
|
91973
92372
|
yield* pushObservedFullGitStateEffect(session2, lastPushedGitState, stateKey, workingDir, branch, reason);
|
|
91974
92373
|
return;
|
|
91975
92374
|
}
|
|
@@ -91990,6 +92389,7 @@ var init_git_heartbeat = __esm(() => {
|
|
|
91990
92389
|
init_git_state_pipeline();
|
|
91991
92390
|
init_convex_error();
|
|
91992
92391
|
lastFullPushMs = new Map;
|
|
92392
|
+
lastPushedBranch = new Map;
|
|
91993
92393
|
branchField = {
|
|
91994
92394
|
key: "branch",
|
|
91995
92395
|
includeInSlim: true,
|
|
@@ -92705,7 +93105,8 @@ var init_participant = __esm(() => {
|
|
|
92705
93105
|
"task.acknowledged",
|
|
92706
93106
|
"task.inProgress",
|
|
92707
93107
|
"task.completed",
|
|
92708
|
-
"agent.requestStop"
|
|
93108
|
+
"agent.requestStop",
|
|
93109
|
+
"agent.awaitingHandoff"
|
|
92709
93110
|
]);
|
|
92710
93111
|
});
|
|
92711
93112
|
|
|
@@ -93171,7 +93572,8 @@ var init_decide_resume_path = __esm(() => {
|
|
|
93171
93572
|
"platform.team_switch",
|
|
93172
93573
|
"platform.resume_storm",
|
|
93173
93574
|
"daemon.shutdown",
|
|
93174
|
-
"daemon.respawn"
|
|
93575
|
+
"daemon.respawn",
|
|
93576
|
+
"daemon.stop_timeout"
|
|
93175
93577
|
]);
|
|
93176
93578
|
});
|
|
93177
93579
|
|
|
@@ -93338,21 +93740,14 @@ function classifyResumeStormReason(logLines) {
|
|
|
93338
93740
|
}
|
|
93339
93741
|
return "unknown";
|
|
93340
93742
|
}
|
|
93341
|
-
function isPermanentHarnessFailure(logLines) {
|
|
93342
|
-
if (isTerminalProviderFailureInLogs(logLines)) {
|
|
93343
|
-
return true;
|
|
93344
|
-
}
|
|
93345
|
-
return PERMANENT_FAILURE_REASONS.has(classifyResumeStormReason(logLines));
|
|
93346
|
-
}
|
|
93347
93743
|
function formatPermanentHarnessFailureMessage(logLines) {
|
|
93348
93744
|
const reason = classifyResumeStormReason(logLines);
|
|
93349
93745
|
const blob = logLines.join(`
|
|
93350
93746
|
`).trim();
|
|
93351
|
-
return blob ? `
|
|
93747
|
+
return blob ? `Crash recovery limit (${reason}): ${blob.slice(-500)}` : `Crash recovery limit (${reason})`;
|
|
93352
93748
|
}
|
|
93353
93749
|
var CLASSIFICATION_RULES, PERMANENT_FAILURE_REASONS;
|
|
93354
93750
|
var init_classify_resume_storm_reason = __esm(() => {
|
|
93355
|
-
init_terminal_provider_error();
|
|
93356
93751
|
CLASSIFICATION_RULES = [
|
|
93357
93752
|
{
|
|
93358
93753
|
reason: "rate_limit",
|
|
@@ -93456,27 +93851,11 @@ async function handleTurnCompleted(deps, input, slot) {
|
|
|
93456
93851
|
if (await tryAbortResumeStorm(deps, input, slot)) {
|
|
93457
93852
|
return { outcome: "storm_aborted" };
|
|
93458
93853
|
}
|
|
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
93854
|
deps.killProcess(input.pid);
|
|
93475
93855
|
return { outcome: "killed" };
|
|
93476
93856
|
}
|
|
93477
93857
|
var init_handle_turn_completed = __esm(() => {
|
|
93478
93858
|
init_abort_resume_storm();
|
|
93479
|
-
init_terminal_provider_error();
|
|
93480
93859
|
});
|
|
93481
93860
|
|
|
93482
93861
|
// src/infrastructure/deps/process.ts
|
|
@@ -93894,19 +94273,30 @@ class AgentProcessManager {
|
|
|
93894
94273
|
whenTurnEndsIdle() {
|
|
93895
94274
|
return this.turnEndQueue.whenIdle();
|
|
93896
94275
|
}
|
|
94276
|
+
clearSlotRuntimeState(slot) {
|
|
94277
|
+
slot.state = "idle";
|
|
94278
|
+
slot.pid = undefined;
|
|
94279
|
+
slot.harness = undefined;
|
|
94280
|
+
slot.harnessSessionId = undefined;
|
|
94281
|
+
slot.resumableHarnessSessionId = undefined;
|
|
94282
|
+
slot.model = undefined;
|
|
94283
|
+
slot.workingDir = undefined;
|
|
94284
|
+
slot.startedAt = undefined;
|
|
94285
|
+
slot.pendingOperation = undefined;
|
|
94286
|
+
slot.stoppingSince = undefined;
|
|
94287
|
+
}
|
|
94288
|
+
bumpStopGeneration(slot) {
|
|
94289
|
+
slot.stopGeneration = (slot.stopGeneration ?? 0) + 1;
|
|
94290
|
+
return slot.stopGeneration;
|
|
94291
|
+
}
|
|
93897
94292
|
async ensureRunning(opts) {
|
|
93898
94293
|
const key = agentKey3(opts.chatroomId, opts.role);
|
|
93899
94294
|
const slot = this.getOrCreateSlot(key);
|
|
93900
94295
|
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;
|
|
94296
|
+
this.clearSlotRuntimeState(slot);
|
|
94297
|
+
}
|
|
94298
|
+
if (slot.state === "stopping" && (slot.stoppingSince === undefined || this.deps.clock.now() - slot.stoppingSince >= STOPPING_TIMEOUT_MS)) {
|
|
94299
|
+
await this.forceClearStuckStoppingSlot(key, slot, opts.chatroomId, opts.role, "daemon.stop_timeout");
|
|
93910
94300
|
}
|
|
93911
94301
|
if (slot.pendingOperation) {
|
|
93912
94302
|
if (slot.state === "stopping") {
|
|
@@ -93970,7 +94360,9 @@ class AgentProcessManager {
|
|
|
93970
94360
|
return { success: true };
|
|
93971
94361
|
}
|
|
93972
94362
|
slot.state = "stopping";
|
|
93973
|
-
const
|
|
94363
|
+
const stopGeneration = this.bumpStopGeneration(slot);
|
|
94364
|
+
slot.stoppingSince = this.deps.clock.now();
|
|
94365
|
+
const operation = this.doStop(key, slot, pid, opts, stopGeneration);
|
|
93974
94366
|
slot.pendingOperation = operation;
|
|
93975
94367
|
return null;
|
|
93976
94368
|
}
|
|
@@ -94053,24 +94445,6 @@ class AgentProcessManager {
|
|
|
94053
94445
|
console.log(`[AgentProcessManager] ✅ Handled rapid resume storm for ${opts.role}`);
|
|
94054
94446
|
return;
|
|
94055
94447
|
}
|
|
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
94448
|
try {
|
|
94075
94449
|
const result = await this.deps.backend.mutation(api.participants.handleNativeAgentEnd, {
|
|
94076
94450
|
sessionId: this.deps.sessionId,
|
|
@@ -94217,16 +94591,12 @@ class AgentProcessManager {
|
|
|
94217
94591
|
console.log(`[AgentProcessManager] ⚠️ Cannot restart — missing harness or workingDir ` + `(role: ${opts.role}, harness: ${harness ?? "none"}, workingDir: ${workingDir ?? "none"})`);
|
|
94218
94592
|
return;
|
|
94219
94593
|
}
|
|
94220
|
-
if (isPermanentHarnessFailure(logs)) {
|
|
94221
|
-
this.handlePermanentFailureForRestart(opts, recentLogLines, ctx.terminalProviderFailureHandled);
|
|
94222
|
-
return;
|
|
94223
|
-
}
|
|
94224
94594
|
const hadRunError = this.hasCursorSdkRunErrorInContext(logs);
|
|
94225
94595
|
if (harness === "cursor-sdk") {
|
|
94226
94596
|
this.retryCursorSdkSessionReopen(opts, ctx, hadRunError);
|
|
94227
94597
|
return;
|
|
94228
94598
|
}
|
|
94229
|
-
this.
|
|
94599
|
+
this.attemptCrashRecoveryRestart(opts, ctx, {
|
|
94230
94600
|
chatroomId: opts.chatroomId,
|
|
94231
94601
|
role: opts.role,
|
|
94232
94602
|
agentHarness: harness,
|
|
@@ -94234,15 +94604,54 @@ class AgentProcessManager {
|
|
|
94234
94604
|
workingDir,
|
|
94235
94605
|
reason: "platform.crash_recovery",
|
|
94236
94606
|
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
94607
|
});
|
|
94245
94608
|
}
|
|
94609
|
+
async attemptCrashRecoveryRestart(exitOpts, ctx, ensureOpts) {
|
|
94610
|
+
try {
|
|
94611
|
+
const result = await this.ensureRunning(ensureOpts);
|
|
94612
|
+
if (result.success)
|
|
94613
|
+
return;
|
|
94614
|
+
if (result.error === "backoff") {
|
|
94615
|
+
await this.retryCrashRecoveryAfterBackoff(exitOpts, ctx, ensureOpts, result.retryAfterMs);
|
|
94616
|
+
return;
|
|
94617
|
+
}
|
|
94618
|
+
if (result.error === "crash_loop") {
|
|
94619
|
+
this.handleCrashLoopLimitReached(exitOpts, ctx.recentLogLines);
|
|
94620
|
+
return;
|
|
94621
|
+
}
|
|
94622
|
+
console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${exitOpts.role}: ${result.error ?? "unknown"}`);
|
|
94623
|
+
} catch (err) {
|
|
94624
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
94625
|
+
console.log(` ⚠️ Failed to restart agent: ${message}`);
|
|
94626
|
+
this.emitStartFailedEvent(exitOpts.role, exitOpts.chatroomId, message);
|
|
94627
|
+
}
|
|
94628
|
+
}
|
|
94629
|
+
async retryCrashRecoveryAfterBackoff(exitOpts, ctx, ensureOpts, retryAfterMs) {
|
|
94630
|
+
if (retryAfterMs === undefined || retryAfterMs <= 0) {
|
|
94631
|
+
return;
|
|
94632
|
+
}
|
|
94633
|
+
const classified = classifyResumeStormReason(ctx.recentLogLines ?? []);
|
|
94634
|
+
console.log(`[AgentProcessManager] ⏳ Crash recovery backoff for ${exitOpts.role} (${classified}): waiting ${retryAfterMs}ms`);
|
|
94635
|
+
await this.deps.clock.delay(retryAfterMs);
|
|
94636
|
+
const retry4 = await this.ensureRunning(ensureOpts);
|
|
94637
|
+
if (retry4.success)
|
|
94638
|
+
return;
|
|
94639
|
+
if (retry4.error === "crash_loop") {
|
|
94640
|
+
this.handleCrashLoopLimitReached(exitOpts, ctx.recentLogLines);
|
|
94641
|
+
return;
|
|
94642
|
+
}
|
|
94643
|
+
if (!retry4.success) {
|
|
94644
|
+
console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${exitOpts.role}: ${retry4.error ?? "unknown"}`);
|
|
94645
|
+
}
|
|
94646
|
+
}
|
|
94647
|
+
handleCrashLoopLimitReached(opts, recentLogLines) {
|
|
94648
|
+
const error = formatPermanentHarnessFailureMessage(recentLogLines ?? []);
|
|
94649
|
+
console.log(`[AgentProcessManager] ⛔ Crash recovery limit reached — ${error}`);
|
|
94650
|
+
this.deps.crashLoop.clear(opts.chatroomId, opts.role);
|
|
94651
|
+
const key = agentKey3(opts.chatroomId, opts.role);
|
|
94652
|
+
this.clearLastHarnessSession(key);
|
|
94653
|
+
this.emitStartFailedEvent(opts.role, opts.chatroomId, error);
|
|
94654
|
+
}
|
|
94246
94655
|
clearHarnessSessionAfterResumePhaseFailure(key, opts) {
|
|
94247
94656
|
const stored = this.lastHarnessSessions.get(key);
|
|
94248
94657
|
this.clearLastHarnessSession(key);
|
|
@@ -94310,25 +94719,6 @@ class AgentProcessManager {
|
|
|
94310
94719
|
this.sessionReopenRetryInFlight.delete(key);
|
|
94311
94720
|
}
|
|
94312
94721
|
}
|
|
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
94722
|
emitStartFailedEvent(role, chatroomId, error) {
|
|
94333
94723
|
this.deps.backend.mutation(api.machines.emitAgentStartFailed, {
|
|
94334
94724
|
sessionId: this.deps.sessionId,
|
|
@@ -94355,6 +94745,37 @@ class AgentProcessManager {
|
|
|
94355
94745
|
}
|
|
94356
94746
|
return result;
|
|
94357
94747
|
}
|
|
94748
|
+
listAllSlots() {
|
|
94749
|
+
const result = [];
|
|
94750
|
+
for (const [key, slot] of this.slots) {
|
|
94751
|
+
const [chatroomId, role] = key.split(":");
|
|
94752
|
+
result.push({ chatroomId, role, slot });
|
|
94753
|
+
}
|
|
94754
|
+
return result;
|
|
94755
|
+
}
|
|
94756
|
+
async clearStuckStoppingSlot(chatroomId, role) {
|
|
94757
|
+
const key = agentKey3(chatroomId, role);
|
|
94758
|
+
const slot = this.slots.get(key);
|
|
94759
|
+
if (!slot || slot.state !== "stopping") {
|
|
94760
|
+
return false;
|
|
94761
|
+
}
|
|
94762
|
+
const elapsed3 = slot.stoppingSince ? this.deps.clock.now() - slot.stoppingSince : STOPPING_TIMEOUT_MS;
|
|
94763
|
+
if (elapsed3 < STOPPING_TIMEOUT_MS) {
|
|
94764
|
+
return false;
|
|
94765
|
+
}
|
|
94766
|
+
await this.forceClearStuckStoppingSlot(key, slot, chatroomId, role, "daemon.stop_timeout");
|
|
94767
|
+
console.warn(`[AgentProcessManager] ⚠️ Cleared stuck stopping slot for ${role}@${chatroomId}`);
|
|
94768
|
+
return true;
|
|
94769
|
+
}
|
|
94770
|
+
async clearAllStuckStoppingSlots() {
|
|
94771
|
+
let cleared = 0;
|
|
94772
|
+
for (const { chatroomId, role } of this.listAllSlots()) {
|
|
94773
|
+
if (await this.clearStuckStoppingSlot(chatroomId, role)) {
|
|
94774
|
+
cleared++;
|
|
94775
|
+
}
|
|
94776
|
+
}
|
|
94777
|
+
return cleared;
|
|
94778
|
+
}
|
|
94358
94779
|
async recover() {
|
|
94359
94780
|
let entries2 = [];
|
|
94360
94781
|
try {
|
|
@@ -94387,6 +94808,10 @@ class AgentProcessManager {
|
|
|
94387
94808
|
}
|
|
94388
94809
|
}
|
|
94389
94810
|
console.log(`[AgentProcessManager] Recovery: ${killed} killed, ${cleaned} cleaned up`);
|
|
94811
|
+
const clearedCount = await this.clearAllStuckStoppingSlots();
|
|
94812
|
+
if (clearedCount > 0) {
|
|
94813
|
+
console.log(`[AgentProcessManager] Recovery: cleared ${clearedCount} stuck stopping slot(s)`);
|
|
94814
|
+
}
|
|
94390
94815
|
}
|
|
94391
94816
|
getOrCreateSlot(key) {
|
|
94392
94817
|
let slot = this.slots.get(key);
|
|
@@ -94423,7 +94848,9 @@ class AgentProcessManager {
|
|
|
94423
94848
|
if (slot?.pid && isProcessAlive(this.deps.processes.kill, slot.pid) && (slot.state === "running" || slot.state === "spawning")) {
|
|
94424
94849
|
const pid = slot.pid;
|
|
94425
94850
|
slot.state = "stopping";
|
|
94426
|
-
|
|
94851
|
+
const stopGeneration = this.bumpStopGeneration(slot);
|
|
94852
|
+
slot.stoppingSince = this.deps.clock.now();
|
|
94853
|
+
await this.doStop(key, slot, pid, { chatroomId, role, reason: "daemon.respawn" }, stopGeneration);
|
|
94427
94854
|
}
|
|
94428
94855
|
}
|
|
94429
94856
|
async killPersistedProcessIfAlive(chatroomId, role) {
|
|
@@ -94693,7 +95120,7 @@ class AgentProcessManager {
|
|
|
94693
95120
|
if (loopCheck.waitMs !== undefined && loopCheck.waitMs > 0) {
|
|
94694
95121
|
console.log(` ⏳ Agent restart backoff: waiting ${loopCheck.waitMs}ms before retry`);
|
|
94695
95122
|
this.resetSlotIdle(slot);
|
|
94696
|
-
return { success: false, error: "backoff" };
|
|
95123
|
+
return { success: false, error: "backoff", retryAfterMs: loopCheck.waitMs };
|
|
94697
95124
|
}
|
|
94698
95125
|
this.deps.backend.mutation(api.machines.emitRestartLimitReached, {
|
|
94699
95126
|
sessionId: this.deps.sessionId,
|
|
@@ -95018,6 +95445,42 @@ class AgentProcessManager {
|
|
|
95018
95445
|
slot.pid = undefined;
|
|
95019
95446
|
slot.startedAt = undefined;
|
|
95020
95447
|
slot.pendingOperation = undefined;
|
|
95448
|
+
slot.stoppingSince = undefined;
|
|
95449
|
+
}
|
|
95450
|
+
async forceClearStuckStoppingSlot(key, slot, chatroomId, role, reason) {
|
|
95451
|
+
const pid = slot.pid;
|
|
95452
|
+
const harness = slot.harness;
|
|
95453
|
+
const durationMs = slot.stoppingSince ? this.deps.clock.now() - slot.stoppingSince : STOPPING_TIMEOUT_MS;
|
|
95454
|
+
this.bumpStopGeneration(slot);
|
|
95455
|
+
this.clearSlotRuntimeState(slot);
|
|
95456
|
+
this.deps.backend.mutation(api.machines.emitAgentStopTimeout, {
|
|
95457
|
+
sessionId: this.deps.sessionId,
|
|
95458
|
+
machineId: this.deps.machineId,
|
|
95459
|
+
chatroomId,
|
|
95460
|
+
role,
|
|
95461
|
+
pid,
|
|
95462
|
+
durationMs
|
|
95463
|
+
}).catch((err) => {
|
|
95464
|
+
console.log(` ⚠️ Failed to emit agent.stopTimeout event: ${err.message}`);
|
|
95465
|
+
});
|
|
95466
|
+
if (pid) {
|
|
95467
|
+
try {
|
|
95468
|
+
this.deps.processes.kill(-pid, "SIGKILL");
|
|
95469
|
+
} catch {}
|
|
95470
|
+
const exitArgs = {
|
|
95471
|
+
sessionId: this.deps.sessionId,
|
|
95472
|
+
machineId: this.deps.machineId,
|
|
95473
|
+
chatroomId,
|
|
95474
|
+
role,
|
|
95475
|
+
pid,
|
|
95476
|
+
stopReason: reason,
|
|
95477
|
+
exitCode: undefined,
|
|
95478
|
+
signal: "SIGKILL",
|
|
95479
|
+
agentHarness: harness
|
|
95480
|
+
};
|
|
95481
|
+
this.recordAgentExitedOrQueueRetry(role, exitArgs, "Failed to record stop-timeout exit");
|
|
95482
|
+
}
|
|
95483
|
+
await this.clearAgentPidQuietly(chatroomId, role);
|
|
95021
95484
|
}
|
|
95022
95485
|
recordStopExit(slot, pid, opts) {
|
|
95023
95486
|
const exitArgs3 = {
|
|
@@ -95036,7 +95499,7 @@ class AgentProcessManager {
|
|
|
95036
95499
|
this.queueExitRetry({ role: opts.role, args: exitArgs3 });
|
|
95037
95500
|
});
|
|
95038
95501
|
}
|
|
95039
|
-
async doStop(key, slot, pid, opts) {
|
|
95502
|
+
async doStop(key, slot, pid, opts, stopGeneration) {
|
|
95040
95503
|
try {
|
|
95041
95504
|
const harness = slot.harness;
|
|
95042
95505
|
const service3 = harness ? this.deps.agentServices.get(harness) : undefined;
|
|
@@ -95048,6 +95511,9 @@ class AgentProcessManager {
|
|
|
95048
95511
|
await this.killProcessWithFallback(pid);
|
|
95049
95512
|
}
|
|
95050
95513
|
} catch {}
|
|
95514
|
+
if (slot.stopGeneration !== stopGeneration) {
|
|
95515
|
+
return { success: true };
|
|
95516
|
+
}
|
|
95051
95517
|
this.resetSlotAfterStop(slot);
|
|
95052
95518
|
this.recordStopExit(slot, pid, opts);
|
|
95053
95519
|
try {
|
|
@@ -95056,7 +95522,7 @@ class AgentProcessManager {
|
|
|
95056
95522
|
return { success: true };
|
|
95057
95523
|
}
|
|
95058
95524
|
}
|
|
95059
|
-
var AGENT_EXIT_RETRY_INTERVAL_MS = 1e4;
|
|
95525
|
+
var AGENT_EXIT_RETRY_INTERVAL_MS = 1e4, STOPPING_TIMEOUT_MS = 30000;
|
|
95060
95526
|
var init_agent_process_manager = __esm(() => {
|
|
95061
95527
|
init_types();
|
|
95062
95528
|
init_participant();
|
|
@@ -95069,7 +95535,6 @@ var init_agent_process_manager = __esm(() => {
|
|
|
95069
95535
|
init_agent_lifecycle();
|
|
95070
95536
|
init_abort_resume_storm();
|
|
95071
95537
|
init_classify_resume_storm_reason();
|
|
95072
|
-
init_terminal_provider_error();
|
|
95073
95538
|
init_handle_turn_completed();
|
|
95074
95539
|
init_spawn_policy();
|
|
95075
95540
|
init_agent_lifecycle_runtime();
|
|
@@ -108577,10 +109042,19 @@ function isPendingAliveRunningTask(task) {
|
|
|
108577
109042
|
const { agentConfig, status: status3 } = task;
|
|
108578
109043
|
return status3 === "pending" && agentConfig.spawnedAgentPid != null && agentConfig.desiredState === "running";
|
|
108579
109044
|
}
|
|
108580
|
-
function isSlotUnavailableForPid(slot, pid, isPidAlive) {
|
|
108581
|
-
if (!slot
|
|
109045
|
+
function isSlotUnavailableForPid(slot, pid, isPidAlive, now = Date.now()) {
|
|
109046
|
+
if (!slot) {
|
|
109047
|
+
return true;
|
|
109048
|
+
}
|
|
109049
|
+
if (slot.state === "idle") {
|
|
108582
109050
|
return true;
|
|
108583
109051
|
}
|
|
109052
|
+
if (slot.state === "stopping") {
|
|
109053
|
+
if (!slot.stoppingSince || now - slot.stoppingSince >= STOPPING_TIMEOUT_MS) {
|
|
109054
|
+
return true;
|
|
109055
|
+
}
|
|
109056
|
+
return false;
|
|
109057
|
+
}
|
|
108584
109058
|
if (slot.pid !== pid) {
|
|
108585
109059
|
return true;
|
|
108586
109060
|
}
|
|
@@ -108596,7 +109070,7 @@ function isNativeRevivableTaskStatus(task) {
|
|
|
108596
109070
|
}
|
|
108597
109071
|
return false;
|
|
108598
109072
|
}
|
|
108599
|
-
function isNativeAgentSlotDown(task, health) {
|
|
109073
|
+
function isNativeAgentSlotDown(task, health, now = Date.now()) {
|
|
108600
109074
|
const slot = health.getSlot(task.chatroomId, task.agentConfig.role);
|
|
108601
109075
|
if (slot?.state === "spawning")
|
|
108602
109076
|
return false;
|
|
@@ -108604,20 +109078,20 @@ function isNativeAgentSlotDown(task, health) {
|
|
|
108604
109078
|
if (pid == null) {
|
|
108605
109079
|
return slot?.state !== "running";
|
|
108606
109080
|
}
|
|
108607
|
-
return isSlotUnavailableForPid(slot, pid, health.isPidAlive);
|
|
109081
|
+
return isSlotUnavailableForPid(slot, pid, health.isPidAlive, now);
|
|
108608
109082
|
}
|
|
108609
|
-
function isNativeActiveTaskAgentDown(task, health) {
|
|
109083
|
+
function isNativeActiveTaskAgentDown(task, health, now) {
|
|
108610
109084
|
if (!isNativeHarness(task.agentConfig.agentHarness))
|
|
108611
109085
|
return false;
|
|
108612
109086
|
if (task.agentConfig.desiredState !== "running")
|
|
108613
109087
|
return false;
|
|
108614
109088
|
if (!isNativeRevivableTaskStatus(task))
|
|
108615
109089
|
return false;
|
|
108616
|
-
return isNativeAgentSlotDown(task, health);
|
|
109090
|
+
return isNativeAgentSlotDown(task, health, now);
|
|
108617
109091
|
}
|
|
108618
109092
|
function listNativeTasksNeedingRevive(tasks, health, now, cooldown) {
|
|
108619
109093
|
return tasks.filter((task) => {
|
|
108620
|
-
if (!isNativeActiveTaskAgentDown(task, health))
|
|
109094
|
+
if (!isNativeActiveTaskAgentDown(task, health, now))
|
|
108621
109095
|
return false;
|
|
108622
109096
|
const { chatroomId, agentConfig } = task;
|
|
108623
109097
|
if (!agentConfig.workingDir)
|
|
@@ -108677,6 +109151,7 @@ var PENDING_IDLE_NUDGE_MS = 15000, NUDGE_COOLDOWN_MS = 60000;
|
|
|
108677
109151
|
var init_task_monitor_logic = __esm(() => {
|
|
108678
109152
|
init_native_task_injector_logic();
|
|
108679
109153
|
init_predicates();
|
|
109154
|
+
init_agent_process_manager();
|
|
108680
109155
|
});
|
|
108681
109156
|
// ../../services/backend/src/domain/usecase/machine/assigned-task-monitor-row.ts
|
|
108682
109157
|
function applyAssignedTaskSignal(existing, signal) {
|
|
@@ -109319,8 +109794,15 @@ function runCliNudgeEffect(task, runtime4, effectContext2, agentMgr, sessionDeps
|
|
|
109319
109794
|
console.log(buildCliNudgeLogLine(task));
|
|
109320
109795
|
executeCliNudge(task, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
|
|
109321
109796
|
}
|
|
109797
|
+
async function clearStuckStoppingSlotIfNeeded(agentMgr, chatroomId, role) {
|
|
109798
|
+
const cleared = await agentMgr.clearStuckStoppingSlot(chatroomId, role);
|
|
109799
|
+
if (cleared) {
|
|
109800
|
+
console.log(`[TaskMonitor] cleared stuck stopping slot for ${role}@${chatroomId}`);
|
|
109801
|
+
}
|
|
109802
|
+
}
|
|
109322
109803
|
async function nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
|
|
109323
109804
|
for (const row of listTasksReadyForNudge(tasks, now, cooldown)) {
|
|
109805
|
+
await clearStuckStoppingSlotIfNeeded(agentMgr, row.chatroomId, row.agentConfig.role);
|
|
109324
109806
|
const full = await fetchTaskForAction(sessionDeps, machineId, row);
|
|
109325
109807
|
if (!full)
|
|
109326
109808
|
continue;
|
|
@@ -109329,6 +109811,7 @@ async function nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, a
|
|
|
109329
109811
|
}
|
|
109330
109812
|
async function reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
|
|
109331
109813
|
for (const row of listNativeTasksNeedingRevive(tasks, localHealth, now, cooldown)) {
|
|
109814
|
+
await clearStuckStoppingSlotIfNeeded(agentMgr, row.chatroomId, row.agentConfig.role);
|
|
109332
109815
|
const full = await fetchTaskForAction(sessionDeps, machineId, row);
|
|
109333
109816
|
if (!full)
|
|
109334
109817
|
continue;
|
|
@@ -109579,7 +110062,7 @@ function handleGitRefreshCommandEffect(event, tracker) {
|
|
|
109579
110062
|
const lastPushedGitState = yield* exports_Ref.get(mutable2.lastPushedGitState);
|
|
109580
110063
|
lastPushedGitState.delete(makeGitStateKey(session2.machineId, typedEvent.workingDir));
|
|
109581
110064
|
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Git refresh requested for ${typedEvent.workingDir}`);
|
|
109582
|
-
yield*
|
|
110065
|
+
yield* pushSingleWorkspaceGitStateEffect(typedEvent.workingDir);
|
|
109583
110066
|
tracker.gitRefreshIds.set(eventId, Date.now());
|
|
109584
110067
|
});
|
|
109585
110068
|
}
|
|
@@ -110988,4 +111471,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
110988
111471
|
});
|
|
110989
111472
|
program2.parse();
|
|
110990
111473
|
|
|
110991
|
-
//# debugId=
|
|
111474
|
+
//# debugId=8E7C236B7CEE28C564756E2164756E21
|