@botiverse/raft-daemon 0.67.0 → 0.69.0-play.20260704183824
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/{chunk-H3WRFI54.js → chunk-FRBMWZ3P.js} +688 -117
- package/dist/cli/index.js +15 -0
- package/dist/core.js +5 -1
- package/dist/{dist-TGKVYIA7.js → dist-IHHGSWH2.js} +13 -0
- package/dist/index.js +5 -3
- package/package.json +1 -1
|
@@ -3288,6 +3288,7 @@ var AGENT_ACTIVITY_DETAIL_KINDS = [
|
|
|
3288
3288
|
"compaction_stale",
|
|
3289
3289
|
"reviewing_changes",
|
|
3290
3290
|
"review_finished",
|
|
3291
|
+
"review_stale",
|
|
3291
3292
|
"runtime_reconnecting",
|
|
3292
3293
|
"runtime_error",
|
|
3293
3294
|
"runtime_crashed",
|
|
@@ -3303,6 +3304,14 @@ var AGENT_ACTIVITY_DETAIL_KINDS = [
|
|
|
3303
3304
|
"synthetic_repair",
|
|
3304
3305
|
"slock_action",
|
|
3305
3306
|
"system_message",
|
|
3307
|
+
// Generic structured runtime-progress heartbeat (Claude --include-partial-messages
|
|
3308
|
+
// stream events / system status) — a "working" liveness signal with no rendered
|
|
3309
|
+
// content. NOT a subagent. (APM 1.6 6a)
|
|
3310
|
+
"runtime_progress",
|
|
3311
|
+
// A subagent (Claude `Agent` tool) lifecycle/activity row, marked from explicit
|
|
3312
|
+
// parent_tool_use_id / task-lifecycle lineage — never inferred from display text.
|
|
3313
|
+
// (APM 1.6 6b)
|
|
3314
|
+
"subagent_activity",
|
|
3306
3315
|
"other"
|
|
3307
3316
|
];
|
|
3308
3317
|
var isAgentActivityDetailKind = makeIsMember(AGENT_ACTIVITY_DETAIL_KINDS);
|
|
@@ -4700,6 +4709,19 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
4700
4709
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
4701
4710
|
}
|
|
4702
4711
|
|
|
4712
|
+
// src/authEnv.ts
|
|
4713
|
+
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
4714
|
+
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
4715
|
+
function scrubDaemonAuthEnv(env) {
|
|
4716
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
4717
|
+
return env;
|
|
4718
|
+
}
|
|
4719
|
+
function scrubDaemonChildEnv(env) {
|
|
4720
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
4721
|
+
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
4722
|
+
return env;
|
|
4723
|
+
}
|
|
4724
|
+
|
|
4703
4725
|
// src/agentCredentialProxy.ts
|
|
4704
4726
|
import { randomBytes } from "crypto";
|
|
4705
4727
|
import http from "http";
|
|
@@ -5875,27 +5897,44 @@ function writeProxyFailureResponse(res, failure) {
|
|
|
5875
5897
|
res.destroy();
|
|
5876
5898
|
return;
|
|
5877
5899
|
}
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
code: "agent_proxy_failed",
|
|
5900
|
+
const body = {
|
|
5901
|
+
error: failure.responseError ?? "failed to proxy local agent request",
|
|
5902
|
+
code: failure.responseCode ?? "agent_proxy_failed",
|
|
5882
5903
|
detail: failure.errorMessage
|
|
5883
|
-
}
|
|
5904
|
+
};
|
|
5905
|
+
if (failure.lifecycleInvalidAgentId) body.agent_id = failure.lifecycleInvalidAgentId;
|
|
5906
|
+
if (failure.lifecycleInvalidContext) body.invariant_context = failure.lifecycleInvalidContext;
|
|
5907
|
+
res.writeHead(failure.responseStatusCode ?? 502, { "content-type": "application/json" });
|
|
5908
|
+
res.end(JSON.stringify(body));
|
|
5884
5909
|
}
|
|
5885
5910
|
function proxyFailureForError(method, target, err) {
|
|
5886
5911
|
const queryKeys = target ? [.../* @__PURE__ */ new Set([...target.searchParams.keys()])].sort() : [];
|
|
5887
5912
|
const cause = err instanceof Error ? err.cause : void 0;
|
|
5913
|
+
const errorMessage = truncateProxyErrorMessage(err instanceof Error ? err.message : String(err));
|
|
5914
|
+
const lifecycleInvalid = parseAgentNoProcessResidencyInvariant(errorMessage);
|
|
5888
5915
|
const failure = {
|
|
5889
5916
|
method,
|
|
5890
5917
|
pathname: target?.pathname ?? "unknown",
|
|
5891
5918
|
queryKeys,
|
|
5892
5919
|
errorName: err instanceof Error ? err.name : typeof err,
|
|
5893
|
-
errorMessage
|
|
5920
|
+
errorMessage
|
|
5894
5921
|
};
|
|
5922
|
+
if (lifecycleInvalid) {
|
|
5923
|
+
failure.responseStatusCode = 409;
|
|
5924
|
+
failure.responseCode = "agent_lifecycle_state_invalid";
|
|
5925
|
+
failure.responseError = "local daemon agent lifecycle state invalid";
|
|
5926
|
+
failure.lifecycleInvalidAgentId = lifecycleInvalid.agentId;
|
|
5927
|
+
failure.lifecycleInvalidContext = lifecycleInvalid.context;
|
|
5928
|
+
}
|
|
5895
5929
|
const errorCause = describeProxyErrorCause(cause);
|
|
5896
5930
|
if (errorCause) failure.errorCause = errorCause;
|
|
5897
5931
|
return failure;
|
|
5898
5932
|
}
|
|
5933
|
+
function parseAgentNoProcessResidencyInvariant(message) {
|
|
5934
|
+
const match = /^Agent no-process residency invariant violation after ([^:]+): .+ for ([0-9a-f-]{36})\b/i.exec(message);
|
|
5935
|
+
if (!match) return void 0;
|
|
5936
|
+
return { context: match[1], agentId: match[2] };
|
|
5937
|
+
}
|
|
5899
5938
|
function describeProxyErrorCause(cause) {
|
|
5900
5939
|
if (!cause) return void 0;
|
|
5901
5940
|
if (cause instanceof Error) {
|
|
@@ -5932,18 +5971,21 @@ function transportNormalizedErrorForHttpStatus(target, status, launchId) {
|
|
|
5932
5971
|
};
|
|
5933
5972
|
}
|
|
5934
5973
|
function transportNormalizedErrorForError(target, err, launchId) {
|
|
5974
|
+
const localDaemonStateInvalid = parseAgentNoProcessResidencyInvariant(
|
|
5975
|
+
sanitizeTransportOriginalMessage(err instanceof Error ? err.message : String(err))
|
|
5976
|
+
);
|
|
5935
5977
|
return {
|
|
5936
|
-
normalizedCode: "transport_failure",
|
|
5978
|
+
normalizedCode: localDaemonStateInvalid ? "local_daemon_state_invalid" : "transport_failure",
|
|
5937
5979
|
routeFamily: routeFamilyForPath(target?.pathname ?? "unknown"),
|
|
5938
5980
|
responseStarted: false,
|
|
5939
|
-
upstreamLayer: target ? upstreamLayerForProxyError(err) : "unknown",
|
|
5981
|
+
upstreamLayer: localDaemonStateInvalid ? "unknown" : target ? upstreamLayerForProxyError(err) : "unknown",
|
|
5940
5982
|
originalMessage: sanitizeTransportOriginalMessage(err instanceof Error ? err.message : String(err)),
|
|
5941
5983
|
launchId,
|
|
5942
|
-
targetHostClass: target ? daemonUpstreamTargetHostClass(target) : "custom_server",
|
|
5984
|
+
targetHostClass: localDaemonStateInvalid ? "local_daemon" : target ? daemonUpstreamTargetHostClass(target) : "custom_server",
|
|
5943
5985
|
// Today the local credential proxy is only used by CLI wrappers. If runtime
|
|
5944
5986
|
// or daemon-internal callers use it later, plumb the caller identity here.
|
|
5945
5987
|
downstreamCaller: "cli",
|
|
5946
|
-
upstream: "server"
|
|
5988
|
+
upstream: localDaemonStateInvalid ? "local_daemon" : "server"
|
|
5947
5989
|
};
|
|
5948
5990
|
}
|
|
5949
5991
|
function routeFamilyForPath(pathname) {
|
|
@@ -6254,7 +6296,9 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
|
|
|
6254
6296
|
var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
|
|
6255
6297
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
6256
6298
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
6257
|
-
"
|
|
6299
|
+
"SLOCK_AGENT_TOKEN",
|
|
6300
|
+
"SLOCK_AGENT_CREDENTIAL_KEY",
|
|
6301
|
+
"SLOCK_AGENT_CREDENTIAL_KEY_FILE"
|
|
6258
6302
|
];
|
|
6259
6303
|
var WORKSPACE_CLI_TRANSPORT_FILENAMES = [
|
|
6260
6304
|
"agent-token",
|
|
@@ -6609,7 +6653,7 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
|
|
|
6609
6653
|
SLOCK_SERVER_URL: ctx.config.serverUrl,
|
|
6610
6654
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
6611
6655
|
};
|
|
6612
|
-
|
|
6656
|
+
scrubDaemonChildEnv(spawnEnv);
|
|
6613
6657
|
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
6614
6658
|
delete spawnEnv[key];
|
|
6615
6659
|
}
|
|
@@ -6628,6 +6672,28 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
|
|
|
6628
6672
|
}
|
|
6629
6673
|
|
|
6630
6674
|
// src/drivers/claudeEventNormalizer.ts
|
|
6675
|
+
function extractSubagentLineage(event) {
|
|
6676
|
+
const parentToolUseId = finiteString(event.parent_tool_use_id);
|
|
6677
|
+
const subagentType = finiteString(event.subagent_type);
|
|
6678
|
+
if (!parentToolUseId && !subagentType) return void 0;
|
|
6679
|
+
return {
|
|
6680
|
+
...parentToolUseId ? { parentToolUseId } : {},
|
|
6681
|
+
...subagentType ? { subagentType } : {},
|
|
6682
|
+
phase: "active"
|
|
6683
|
+
};
|
|
6684
|
+
}
|
|
6685
|
+
function taskLifecyclePhase(subtype) {
|
|
6686
|
+
switch (subtype) {
|
|
6687
|
+
case "task_started":
|
|
6688
|
+
return "started";
|
|
6689
|
+
case "task_progress":
|
|
6690
|
+
return "progress";
|
|
6691
|
+
case "task_notification":
|
|
6692
|
+
return "notification";
|
|
6693
|
+
default:
|
|
6694
|
+
return null;
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6631
6697
|
function collectResultErrorDetail(message, fallback) {
|
|
6632
6698
|
const parts = [];
|
|
6633
6699
|
if (Array.isArray(message.errors)) {
|
|
@@ -6801,6 +6867,25 @@ var ClaudeEventNormalizer = class {
|
|
|
6801
6867
|
if (event.subtype === "compact_boundary") {
|
|
6802
6868
|
events.push({ kind: "compaction_finished" });
|
|
6803
6869
|
}
|
|
6870
|
+
{
|
|
6871
|
+
const phase = typeof event.subtype === "string" ? taskLifecyclePhase(event.subtype) : null;
|
|
6872
|
+
if (phase) {
|
|
6873
|
+
events.push({
|
|
6874
|
+
kind: "subagent_progress",
|
|
6875
|
+
source: "claude_task_lifecycle",
|
|
6876
|
+
phase,
|
|
6877
|
+
...finiteString(event.task_id) ? { taskId: finiteString(event.task_id) } : {},
|
|
6878
|
+
// `system` task-lifecycle envelopes carry the outer Agent tool id
|
|
6879
|
+
// as `tool_use_id`; belt-and-suspenders fall back to
|
|
6880
|
+
// `parent_tool_use_id` in case a Claude version names it that way
|
|
6881
|
+
// on the envelope (confirmed field name = tool_use_id, @Huarong).
|
|
6882
|
+
...finiteString(event.tool_use_id) ?? finiteString(event.parent_tool_use_id) ? { parentToolUseId: finiteString(event.tool_use_id) ?? finiteString(event.parent_tool_use_id) } : {},
|
|
6883
|
+
...finiteString(event.subagent_type) ? { subagentType: finiteString(event.subagent_type) } : {},
|
|
6884
|
+
...finiteString(event.last_tool_name) ? { lastToolName: finiteString(event.last_tool_name) } : {},
|
|
6885
|
+
payloadBytes: Buffer.byteLength(line, "utf8")
|
|
6886
|
+
});
|
|
6887
|
+
}
|
|
6888
|
+
}
|
|
6804
6889
|
break;
|
|
6805
6890
|
case "stream_event":
|
|
6806
6891
|
events.push({
|
|
@@ -6812,19 +6897,21 @@ var ClaudeEventNormalizer = class {
|
|
|
6812
6897
|
break;
|
|
6813
6898
|
case "assistant": {
|
|
6814
6899
|
const content = event.message?.content;
|
|
6900
|
+
const subagent = extractSubagentLineage(event);
|
|
6901
|
+
const withLineage = subagent ? { subagent } : {};
|
|
6815
6902
|
if (Array.isArray(content)) {
|
|
6816
6903
|
const hasToolUse = content.some((block) => block?.type === "tool_use");
|
|
6817
6904
|
for (const block of content) {
|
|
6818
6905
|
if (block.type === "thinking" && block.thinking) {
|
|
6819
|
-
events.push({ kind: "thinking", text: block.thinking });
|
|
6906
|
+
events.push({ kind: "thinking", text: block.thinking, ...withLineage });
|
|
6820
6907
|
} else if (block.type === "text" && block.text) {
|
|
6821
6908
|
if (isProviderApiFailureText(block.text, hasToolUse)) {
|
|
6822
6909
|
events.push({ kind: "error", message: block.text });
|
|
6823
6910
|
} else {
|
|
6824
|
-
events.push({ kind: "text", text: block.text });
|
|
6911
|
+
events.push({ kind: "text", text: block.text, ...withLineage });
|
|
6825
6912
|
}
|
|
6826
6913
|
} else if (block.type === "tool_use") {
|
|
6827
|
-
events.push({ kind: "tool_call", name: block.name || "unknown_tool", input: block.input });
|
|
6914
|
+
events.push({ kind: "tool_call", name: block.name || "unknown_tool", input: block.input, ...withLineage });
|
|
6828
6915
|
}
|
|
6829
6916
|
}
|
|
6830
6917
|
}
|
|
@@ -6832,10 +6919,12 @@ var ClaudeEventNormalizer = class {
|
|
|
6832
6919
|
}
|
|
6833
6920
|
case "user": {
|
|
6834
6921
|
const content = event.message?.content;
|
|
6922
|
+
const subagent = extractSubagentLineage(event);
|
|
6923
|
+
const withLineage = subagent ? { subagent } : {};
|
|
6835
6924
|
if (Array.isArray(content)) {
|
|
6836
6925
|
for (const block of content) {
|
|
6837
6926
|
if (block.type === "tool_result") {
|
|
6838
|
-
events.push({ kind: "tool_output", name: block.name || block.tool_use_id || "tool_result" });
|
|
6927
|
+
events.push({ kind: "tool_output", name: block.name || block.tool_use_id || "tool_result", ...withLineage });
|
|
6839
6928
|
}
|
|
6840
6929
|
}
|
|
6841
6930
|
}
|
|
@@ -7132,7 +7221,7 @@ function requiresWindowsShell(command, platform = process.platform) {
|
|
|
7132
7221
|
}
|
|
7133
7222
|
function resolveCommandOnPath(command, deps = {}) {
|
|
7134
7223
|
const platform = deps.platform ?? process.platform;
|
|
7135
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
7224
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
7136
7225
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
7137
7226
|
const existsSyncFn = deps.existsSyncFn ?? existsSync3;
|
|
7138
7227
|
if (platform === "win32") {
|
|
@@ -7158,7 +7247,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
7158
7247
|
return null;
|
|
7159
7248
|
}
|
|
7160
7249
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
7161
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
7250
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
7162
7251
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
7163
7252
|
try {
|
|
7164
7253
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -9242,11 +9331,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
9242
9331
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
9243
9332
|
}
|
|
9244
9333
|
function buildCursorModelProbeEnv(deps = {}) {
|
|
9245
|
-
return withWindowsUserEnvironment({
|
|
9334
|
+
return scrubDaemonChildEnv(withWindowsUserEnvironment({
|
|
9246
9335
|
...deps.env ?? process.env,
|
|
9247
9336
|
FORCE_COLOR: "0",
|
|
9248
9337
|
NO_COLOR: "1"
|
|
9249
|
-
}, deps);
|
|
9338
|
+
}, deps));
|
|
9250
9339
|
}
|
|
9251
9340
|
function runCursorModelsCommand() {
|
|
9252
9341
|
return spawnSync("cursor-agent", ["models"], {
|
|
@@ -9302,7 +9391,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
9302
9391
|
}
|
|
9303
9392
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
9304
9393
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
9305
|
-
const env = deps.env ?? process.env;
|
|
9394
|
+
const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
|
|
9306
9395
|
const winPath = path8.win32;
|
|
9307
9396
|
let geminiEntry = null;
|
|
9308
9397
|
try {
|
|
@@ -9439,12 +9528,15 @@ var GeminiDriver = class {
|
|
|
9439
9528
|
// src/drivers/kimi.ts
|
|
9440
9529
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
9441
9530
|
import { spawn as spawn7 } from "child_process";
|
|
9442
|
-
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
9531
|
+
import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
9443
9532
|
import os4 from "os";
|
|
9444
9533
|
import path9 from "path";
|
|
9445
9534
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
9446
9535
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
9447
9536
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
9537
|
+
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
9538
|
+
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
9539
|
+
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
9448
9540
|
function parseToolArguments(raw) {
|
|
9449
9541
|
if (typeof raw !== "string") return raw;
|
|
9450
9542
|
try {
|
|
@@ -9453,6 +9545,73 @@ function parseToolArguments(raw) {
|
|
|
9453
9545
|
return raw;
|
|
9454
9546
|
}
|
|
9455
9547
|
}
|
|
9548
|
+
function readKimiConfigSource(home = os4.homedir(), env = process.env) {
|
|
9549
|
+
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
9550
|
+
if (inlineConfig && inlineConfig.trim()) {
|
|
9551
|
+
return {
|
|
9552
|
+
raw: inlineConfig,
|
|
9553
|
+
explicitPath: null,
|
|
9554
|
+
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
9555
|
+
};
|
|
9556
|
+
}
|
|
9557
|
+
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
9558
|
+
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path9.join(home, ".kimi", "config.toml");
|
|
9559
|
+
try {
|
|
9560
|
+
return {
|
|
9561
|
+
raw: readFileSync3(configPath, "utf8"),
|
|
9562
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
9563
|
+
sourcePath: configPath
|
|
9564
|
+
};
|
|
9565
|
+
} catch {
|
|
9566
|
+
return {
|
|
9567
|
+
raw: null,
|
|
9568
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
9569
|
+
sourcePath: configPath
|
|
9570
|
+
};
|
|
9571
|
+
}
|
|
9572
|
+
}
|
|
9573
|
+
function buildKimiSpawnEnv(env = process.env) {
|
|
9574
|
+
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
9575
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
9576
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
9577
|
+
return scrubDaemonChildEnv(spawnEnv);
|
|
9578
|
+
}
|
|
9579
|
+
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
9580
|
+
return {
|
|
9581
|
+
...process.env,
|
|
9582
|
+
...ctx.config.envVars || {},
|
|
9583
|
+
...overrideEnv || {}
|
|
9584
|
+
};
|
|
9585
|
+
}
|
|
9586
|
+
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
9587
|
+
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
9588
|
+
const source = readKimiConfigSource(opts.home ?? os4.homedir(), env);
|
|
9589
|
+
const args = [];
|
|
9590
|
+
let configFilePath = null;
|
|
9591
|
+
let configContent = null;
|
|
9592
|
+
if (source.explicitPath) {
|
|
9593
|
+
configFilePath = source.explicitPath;
|
|
9594
|
+
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
9595
|
+
configFilePath = path9.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
9596
|
+
configContent = source.raw;
|
|
9597
|
+
if (opts.writeGeneratedConfig !== false) {
|
|
9598
|
+
writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
9599
|
+
chmodSync(configFilePath, 384);
|
|
9600
|
+
}
|
|
9601
|
+
}
|
|
9602
|
+
if (configFilePath) {
|
|
9603
|
+
args.push("--config-file", configFilePath);
|
|
9604
|
+
}
|
|
9605
|
+
if (ctx.config.model && ctx.config.model !== "default") {
|
|
9606
|
+
args.push("--model", ctx.config.model);
|
|
9607
|
+
}
|
|
9608
|
+
return {
|
|
9609
|
+
args,
|
|
9610
|
+
env: buildKimiSpawnEnv(env),
|
|
9611
|
+
configFilePath,
|
|
9612
|
+
configContent
|
|
9613
|
+
};
|
|
9614
|
+
}
|
|
9456
9615
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
9457
9616
|
return {
|
|
9458
9617
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -9476,7 +9635,25 @@ var KimiDriver = class {
|
|
|
9476
9635
|
};
|
|
9477
9636
|
model = {
|
|
9478
9637
|
detectedModelsVerifiedAs: "launchable",
|
|
9479
|
-
toLaunchSpec: (modelId) =>
|
|
9638
|
+
toLaunchSpec: (modelId, ctx, opts) => {
|
|
9639
|
+
if (!ctx) return { args: ["--model", modelId] };
|
|
9640
|
+
const launchCtx = {
|
|
9641
|
+
...ctx,
|
|
9642
|
+
config: {
|
|
9643
|
+
...ctx.config,
|
|
9644
|
+
model: modelId
|
|
9645
|
+
}
|
|
9646
|
+
};
|
|
9647
|
+
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
9648
|
+
home: opts?.home,
|
|
9649
|
+
writeGeneratedConfig: false
|
|
9650
|
+
});
|
|
9651
|
+
return {
|
|
9652
|
+
args: launch.args,
|
|
9653
|
+
env: launch.env,
|
|
9654
|
+
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
9655
|
+
};
|
|
9656
|
+
}
|
|
9480
9657
|
};
|
|
9481
9658
|
supportsStdinNotification = true;
|
|
9482
9659
|
busyDeliveryMode = "direct";
|
|
@@ -9500,21 +9677,23 @@ var KimiDriver = class {
|
|
|
9500
9677
|
` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
|
|
9501
9678
|
""
|
|
9502
9679
|
].join("\n"), "utf8");
|
|
9680
|
+
const launch = buildKimiLaunchOptions(ctx);
|
|
9503
9681
|
const args = [
|
|
9504
9682
|
"--wire",
|
|
9505
9683
|
"--yolo",
|
|
9506
9684
|
"--agent-file",
|
|
9507
9685
|
agentFilePath,
|
|
9508
9686
|
"--session",
|
|
9509
|
-
this.sessionId
|
|
9687
|
+
this.sessionId,
|
|
9688
|
+
...launch.args
|
|
9510
9689
|
];
|
|
9511
9690
|
const launchRuntimeFields = runtimeConfigToLaunchFields(hydrateRuntimeConfig(ctx.config));
|
|
9512
9691
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
|
|
9513
9692
|
args.push("--model", launchRuntimeFields.model);
|
|
9514
9693
|
}
|
|
9515
9694
|
const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
9516
|
-
const
|
|
9517
|
-
const proc = spawn7(
|
|
9695
|
+
const spawnTarget = resolveKimiSpawn(args);
|
|
9696
|
+
const proc = spawn7(spawnTarget.command, spawnTarget.args, {
|
|
9518
9697
|
cwd: ctx.workingDirectory,
|
|
9519
9698
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9520
9699
|
env: spawnEnv,
|
|
@@ -9522,7 +9701,7 @@ var KimiDriver = class {
|
|
|
9522
9701
|
// and has an 8191-character command-line limit. Kimi's official
|
|
9523
9702
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
9524
9703
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
9525
|
-
shell:
|
|
9704
|
+
shell: spawnTarget.shell
|
|
9526
9705
|
});
|
|
9527
9706
|
proc.stdin?.write(JSON.stringify({
|
|
9528
9707
|
jsonrpc: "2.0",
|
|
@@ -9635,14 +9814,9 @@ var KimiDriver = class {
|
|
|
9635
9814
|
return detectKimiModels();
|
|
9636
9815
|
}
|
|
9637
9816
|
};
|
|
9638
|
-
function detectKimiModels(home = os4.homedir()) {
|
|
9639
|
-
const
|
|
9640
|
-
|
|
9641
|
-
try {
|
|
9642
|
-
raw = readFileSync3(configPath, "utf8");
|
|
9643
|
-
} catch {
|
|
9644
|
-
return null;
|
|
9645
|
-
}
|
|
9817
|
+
function detectKimiModels(home = os4.homedir(), opts = {}) {
|
|
9818
|
+
const raw = readKimiConfigSource(home, opts.env).raw;
|
|
9819
|
+
if (raw === null) return null;
|
|
9646
9820
|
const models = [];
|
|
9647
9821
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
9648
9822
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -10308,7 +10482,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
10308
10482
|
const platform = deps.platform ?? process.platform;
|
|
10309
10483
|
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
10310
10484
|
const result = spawnSyncFn("opencode", ["models"], {
|
|
10311
|
-
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
10485
|
+
env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
|
|
10312
10486
|
encoding: "utf8",
|
|
10313
10487
|
timeout: 5e3,
|
|
10314
10488
|
shell: platform === "win32"
|
|
@@ -10465,6 +10639,7 @@ var OpenCodeDriver = class {
|
|
|
10465
10639
|
};
|
|
10466
10640
|
supportsStdinNotification = false;
|
|
10467
10641
|
busyDeliveryMode = "none";
|
|
10642
|
+
supportsNativeStandingPrompt = true;
|
|
10468
10643
|
terminateProcessOnTurnEnd = true;
|
|
10469
10644
|
deferSpawnUntilMessage = true;
|
|
10470
10645
|
shouldDeferWakeMessage(message) {
|
|
@@ -12107,6 +12282,18 @@ var AgentLifecycleRecords = class {
|
|
|
12107
12282
|
pendingSpawnCauses = /* @__PURE__ */ new Map();
|
|
12108
12283
|
runtimeErrorFingerprintFences = /* @__PURE__ */ new Map();
|
|
12109
12284
|
activityClientSeqs = /* @__PURE__ */ new Map();
|
|
12285
|
+
stopEpochs = /* @__PURE__ */ new Map();
|
|
12286
|
+
recordStop(agentId) {
|
|
12287
|
+
const next = (this.stopEpochs.get(agentId) ?? 0) + 1;
|
|
12288
|
+
this.stopEpochs.set(agentId, next);
|
|
12289
|
+
return next;
|
|
12290
|
+
}
|
|
12291
|
+
stopEpoch(agentId) {
|
|
12292
|
+
return this.stopEpochs.get(agentId) ?? 0;
|
|
12293
|
+
}
|
|
12294
|
+
stopEpochChanged(agentId, epoch) {
|
|
12295
|
+
return this.stopEpoch(agentId) !== epoch;
|
|
12296
|
+
}
|
|
12110
12297
|
nextActivityClientSeq(agentId) {
|
|
12111
12298
|
const next = (this.activityClientSeqs.get(agentId) ?? 0) + 1;
|
|
12112
12299
|
this.activityClientSeqs.set(agentId, next);
|
|
@@ -13008,6 +13195,36 @@ var WORKSPACE_IMAGE_MIME_BY_EXTENSION = {
|
|
|
13008
13195
|
".png": "image/png",
|
|
13009
13196
|
".webp": "image/webp"
|
|
13010
13197
|
};
|
|
13198
|
+
var WORKSPACE_NEVER_VISIBLE_HIDDEN_NAMES = /* @__PURE__ */ new Set([
|
|
13199
|
+
".aws",
|
|
13200
|
+
".gnupg",
|
|
13201
|
+
".ssh",
|
|
13202
|
+
".slock",
|
|
13203
|
+
".slock-runtime"
|
|
13204
|
+
]);
|
|
13205
|
+
var WORKSPACE_SECRET_FILE_PATTERNS = [
|
|
13206
|
+
/^\.env(?:\.|$)/i,
|
|
13207
|
+
/(?:^|[._-])secret(?:s)?(?:[._-]|$)/i,
|
|
13208
|
+
/(?:^|[._-])credential(?:s)?(?:[._-]|$)/i,
|
|
13209
|
+
/(?:^|[._-])token(?:s)?(?:[._-]|$)/i
|
|
13210
|
+
];
|
|
13211
|
+
function isWorkspaceNeverVisibleHiddenEntry(name) {
|
|
13212
|
+
return WORKSPACE_NEVER_VISIBLE_HIDDEN_NAMES.has(name) || name.startsWith(".slock-");
|
|
13213
|
+
}
|
|
13214
|
+
function workspacePathParts(relativePath) {
|
|
13215
|
+
return relativePath.split(path14.sep).filter(Boolean);
|
|
13216
|
+
}
|
|
13217
|
+
function isWorkspaceHiddenPath(relativePath) {
|
|
13218
|
+
return workspacePathParts(relativePath).some((part) => part.startsWith("."));
|
|
13219
|
+
}
|
|
13220
|
+
function isWorkspaceNeverVisibleHiddenPath(relativePath) {
|
|
13221
|
+
return workspacePathParts(relativePath).some(isWorkspaceNeverVisibleHiddenEntry);
|
|
13222
|
+
}
|
|
13223
|
+
function isWorkspaceSecretFilePath(filePath) {
|
|
13224
|
+
return workspacePathParts(filePath).some(
|
|
13225
|
+
(part) => WORKSPACE_SECRET_FILE_PATTERNS.some((pattern) => pattern.test(part))
|
|
13226
|
+
);
|
|
13227
|
+
}
|
|
13011
13228
|
function readPositiveIntegerEnv(name, fallback) {
|
|
13012
13229
|
const raw = process.env[name];
|
|
13013
13230
|
if (!raw) return fallback;
|
|
@@ -13102,9 +13319,6 @@ function toLocalTime(iso) {
|
|
|
13102
13319
|
const pad = (n) => String(n).padStart(2, "0");
|
|
13103
13320
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
13104
13321
|
}
|
|
13105
|
-
function formatChannelLabel(message) {
|
|
13106
|
-
return message.channel_type === "dm" ? `DM:@${message.channel_name}` : `#${message.channel_name}`;
|
|
13107
|
-
}
|
|
13108
13322
|
function formatMessageTarget(message) {
|
|
13109
13323
|
return formatAgentMessageVisibleTarget(message);
|
|
13110
13324
|
}
|
|
@@ -13437,15 +13651,6 @@ function formatRuntimeProfileControlStartupInput(control, driver) {
|
|
|
13437
13651
|
control.message
|
|
13438
13652
|
].join("\n");
|
|
13439
13653
|
}
|
|
13440
|
-
function buildUnreadSummary(messages, excludeChannel) {
|
|
13441
|
-
const summary = /* @__PURE__ */ new Map();
|
|
13442
|
-
for (const message of messages) {
|
|
13443
|
-
const label = formatChannelLabel(message);
|
|
13444
|
-
if (excludeChannel && label === excludeChannel) continue;
|
|
13445
|
-
summary.set(label, (summary.get(label) || 0) + 1);
|
|
13446
|
-
}
|
|
13447
|
-
return summary.size > 0 ? Object.fromEntries(summary) : void 0;
|
|
13448
|
-
}
|
|
13449
13654
|
var MAX_TRAJECTORY_TEXT = 2e3;
|
|
13450
13655
|
var TRAJECTORY_COALESCE_MS = 350;
|
|
13451
13656
|
var ACTIVITY_HEARTBEAT_MS = 6e4;
|
|
@@ -13456,11 +13661,12 @@ var RUNTIME_ERROR_DELIVERY_BACKOFF_MAX_MS = 5 * 6e4;
|
|
|
13456
13661
|
var RUNTIME_ERROR_FINGERPRINT_FENCE_THRESHOLD = 3;
|
|
13457
13662
|
var SPAWN_FAIL_BACKOFF_BASE_MS = 1e3;
|
|
13458
13663
|
var SPAWN_FAIL_BACKOFF_MAX_MS = 3e4;
|
|
13459
|
-
var SPAWN_FAIL_BACKOFF_THRESHOLD =
|
|
13664
|
+
var SPAWN_FAIL_BACKOFF_THRESHOLD = 0;
|
|
13460
13665
|
var RUNNER_CREDENTIAL_MINT_BACKOFF_BASE_MS = 6e4;
|
|
13461
13666
|
var RUNNER_CREDENTIAL_MINT_BACKOFF_MAX_MS = 10 * 6e4;
|
|
13462
13667
|
var RUNNER_CREDENTIAL_MINT_BACKOFF_THRESHOLD = 0;
|
|
13463
13668
|
var COMPACTION_STALE_MS = 5 * 6e4;
|
|
13669
|
+
var REVIEW_STALE_MS = 10 * 6e4;
|
|
13464
13670
|
var RUNTIME_PROGRESS_STALE_MS = 15 * 6e4;
|
|
13465
13671
|
var DEFAULT_RUNTIME_START_TIMEOUT_MS = 2 * 6e4;
|
|
13466
13672
|
var DEFAULT_STALLED_RECOVERY_SIGTERM_TIMEOUT_MS = 1e4;
|
|
@@ -14096,6 +14302,39 @@ function runtimeRecoveryTraceAttrs(event) {
|
|
|
14096
14302
|
details_present: Boolean(event.details)
|
|
14097
14303
|
};
|
|
14098
14304
|
}
|
|
14305
|
+
function subagentProgressDetail(event) {
|
|
14306
|
+
const role = event.subagentType ? ` (${event.subagentType})` : "";
|
|
14307
|
+
switch (event.phase) {
|
|
14308
|
+
case "started":
|
|
14309
|
+
return `Subagent started${role}`;
|
|
14310
|
+
case "progress":
|
|
14311
|
+
return `Subagent working${role}`;
|
|
14312
|
+
case "notification":
|
|
14313
|
+
return `Subagent update${role}`;
|
|
14314
|
+
default:
|
|
14315
|
+
return `Subagent working${role}`;
|
|
14316
|
+
}
|
|
14317
|
+
}
|
|
14318
|
+
function subagentLineageFromEvent(event) {
|
|
14319
|
+
return {
|
|
14320
|
+
...event.parentToolUseId ? { parentToolUseId: event.parentToolUseId } : {},
|
|
14321
|
+
...event.subagentType ? { subagentType: event.subagentType } : {},
|
|
14322
|
+
...event.taskId ? { taskId: event.taskId } : {},
|
|
14323
|
+
phase: event.phase
|
|
14324
|
+
};
|
|
14325
|
+
}
|
|
14326
|
+
function subagentProgressTraceAttrs(event) {
|
|
14327
|
+
return {
|
|
14328
|
+
kind: event.kind,
|
|
14329
|
+
source: event.source,
|
|
14330
|
+
phase: event.phase,
|
|
14331
|
+
parent_tool_use_id_present: Boolean(event.parentToolUseId),
|
|
14332
|
+
subagent_type_present: Boolean(event.subagentType),
|
|
14333
|
+
task_id_present: Boolean(event.taskId),
|
|
14334
|
+
last_tool_name_present: Boolean(event.lastToolName),
|
|
14335
|
+
payloadBytes: event.payloadBytes
|
|
14336
|
+
};
|
|
14337
|
+
}
|
|
14099
14338
|
function currentErrorCandidates(ap) {
|
|
14100
14339
|
return ap.decisionErrorWindow.currentErrorCandidates();
|
|
14101
14340
|
}
|
|
@@ -14465,6 +14704,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14465
14704
|
this.cliTransportTraceDir = traceDir;
|
|
14466
14705
|
}
|
|
14467
14706
|
assertStartPendingDeliveryInvariants(context) {
|
|
14707
|
+
this.repairNonresidentRuntimeErrorFingerprintFences(context);
|
|
14468
14708
|
const residencySnapshot = this.noProcessResidencySnapshot();
|
|
14469
14709
|
AgentNoProcessResidency.assertInvariants(context, residencySnapshot);
|
|
14470
14710
|
this.lifecycleRecords.assertInvariants(context, this.agentLifecycleRecordSnapshot());
|
|
@@ -14515,10 +14755,10 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14515
14755
|
}
|
|
14516
14756
|
// ----- SPAWN-FAIL BACKOFF (per-agent) ----------------------------------
|
|
14517
14757
|
// Anchored at auto_restart_from_idle (apm:3596) + runtime_profile_auto_restart (apm:4137).
|
|
14518
|
-
//
|
|
14519
|
-
//
|
|
14520
|
-
// inner credential-mint loop exhausted
|
|
14521
|
-
//
|
|
14758
|
+
// One outer spawn failure enters cooldown immediately so repeated wakes cannot burn one
|
|
14759
|
+
// full spawn attempt per delivery. Runner credential mint failures keep a longer cooldown
|
|
14760
|
+
// because one outer failure already means the inner credential-mint loop exhausted
|
|
14761
|
+
// RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS.
|
|
14522
14762
|
// Successful spawn resets state. State lives outside AgentProcess because spawn fails BEFORE
|
|
14523
14763
|
// ap exists and the rate-window must persist across stop/respawn (else stop/start churn
|
|
14524
14764
|
// bypasses the cap — CC1 lifecycle pattern). Never advances any consume cursor or model-seen
|
|
@@ -14602,6 +14842,17 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14602
14842
|
reset_source: resetSource
|
|
14603
14843
|
});
|
|
14604
14844
|
}
|
|
14845
|
+
resetRuntimeErrorFingerprintFenceIfNonresident(agentId, resetSource, ap) {
|
|
14846
|
+
if (this.agents.has(agentId)) return;
|
|
14847
|
+
if (this.lifecycleRecords.getRestartSnapshot(agentId)) return;
|
|
14848
|
+
if (this.lifecycleRecords.getTerminalFailure(agentId)) return;
|
|
14849
|
+
this.resetRuntimeErrorFingerprintFence(agentId, resetSource, ap);
|
|
14850
|
+
}
|
|
14851
|
+
repairNonresidentRuntimeErrorFingerprintFences(context) {
|
|
14852
|
+
for (const agentId of [...this.lifecycleRecords.runtimeErrorFingerprintFenceAgentIds()]) {
|
|
14853
|
+
this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, `invariant_repair:${context}`);
|
|
14854
|
+
}
|
|
14855
|
+
}
|
|
14605
14856
|
formatRuntimeErrorFingerprintFenceDetail(state) {
|
|
14606
14857
|
return [
|
|
14607
14858
|
`Runtime stopped after ${state.attempts} repeated runtime errors with the same fingerprint (${state.fingerprint}).`,
|
|
@@ -14660,14 +14911,22 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14660
14911
|
this.sendStdinNotification(agentId);
|
|
14661
14912
|
}, delayMs);
|
|
14662
14913
|
}
|
|
14663
|
-
|
|
14914
|
+
scheduleIdleInboxDeliveryRetry(agentId, ap, notificationCount, source, traceName) {
|
|
14915
|
+
if (notificationCount <= 0 || !ap.driver.supportsStdinNotification || !ap.sessionId) return false;
|
|
14916
|
+
ap.notifications.add(notificationCount);
|
|
14917
|
+
ap.notifications.clearTimer();
|
|
14918
|
+
return ap.notifications.schedule(() => {
|
|
14919
|
+
this.flushIdleInboxDeliveryRetry(agentId, source, traceName);
|
|
14920
|
+
}, this.stdinNotificationRetryMs);
|
|
14921
|
+
}
|
|
14922
|
+
flushIdleInboxDeliveryRetry(agentId, source, traceName) {
|
|
14664
14923
|
const ap = this.agents.get(agentId);
|
|
14665
14924
|
if (!ap) return false;
|
|
14666
14925
|
const count = ap.notifications.takePendingAndClearTimer();
|
|
14667
14926
|
if (count === 0) return false;
|
|
14668
14927
|
if (!ap.driver.supportsStdinNotification || !ap.sessionId || ap.inbox.length === 0) {
|
|
14669
14928
|
ap.notifications.add(count);
|
|
14670
|
-
this.recordDaemonTrace(
|
|
14929
|
+
this.recordDaemonTrace(traceName, {
|
|
14671
14930
|
agentId,
|
|
14672
14931
|
runtime: ap.config.runtime,
|
|
14673
14932
|
model: ap.config.model,
|
|
@@ -14688,7 +14947,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14688
14947
|
ap.notifications.pruneContributedToPending(ap.inbox, ap.sessionId);
|
|
14689
14948
|
const messages = ap.notifications.filterUncontributedMessages(ap.inbox, ap.sessionId);
|
|
14690
14949
|
if (messages.length === 0) {
|
|
14691
|
-
this.recordDaemonTrace(
|
|
14950
|
+
this.recordDaemonTrace(traceName, {
|
|
14692
14951
|
agentId,
|
|
14693
14952
|
runtime: ap.config.runtime,
|
|
14694
14953
|
model: ap.config.model,
|
|
@@ -14702,16 +14961,16 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14702
14961
|
return false;
|
|
14703
14962
|
}
|
|
14704
14963
|
this.commitApmIdleState(agentId, ap, false);
|
|
14705
|
-
this.startRuntimeTrace(agentId, ap, "
|
|
14964
|
+
this.startRuntimeTrace(agentId, ap, source.replaceAll("_", "-"), messages);
|
|
14706
14965
|
this.broadcastMessageReceivedActivity(agentId);
|
|
14707
14966
|
const accepted = this.deliverInboxUpdateViaStdin(
|
|
14708
14967
|
agentId,
|
|
14709
14968
|
ap,
|
|
14710
14969
|
messages,
|
|
14711
14970
|
"idle",
|
|
14712
|
-
|
|
14971
|
+
source
|
|
14713
14972
|
);
|
|
14714
|
-
this.recordDaemonTrace(
|
|
14973
|
+
this.recordDaemonTrace(traceName, {
|
|
14715
14974
|
agentId,
|
|
14716
14975
|
runtime: ap.config.runtime,
|
|
14717
14976
|
model: ap.config.model,
|
|
@@ -14724,6 +14983,13 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14724
14983
|
});
|
|
14725
14984
|
return accepted;
|
|
14726
14985
|
}
|
|
14986
|
+
flushAsyncRejectedIdleDelivery(agentId) {
|
|
14987
|
+
return this.flushIdleInboxDeliveryRetry(
|
|
14988
|
+
agentId,
|
|
14989
|
+
"async_rejected_idle_delivery_retry",
|
|
14990
|
+
"daemon.agent.stdin_delivery.async_rejected.retry"
|
|
14991
|
+
);
|
|
14992
|
+
}
|
|
14727
14993
|
isApmIdle(ap) {
|
|
14728
14994
|
return ap.gatedSteering.isIdle;
|
|
14729
14995
|
}
|
|
@@ -14769,7 +15035,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14769
15035
|
this.broadcastActivity(agentId, "working", "Message received", [], void 0, "message_received");
|
|
14770
15036
|
}
|
|
14771
15037
|
toolActivityDetailKind(toolName) {
|
|
14772
|
-
switch (toolName) {
|
|
15038
|
+
switch (resolveToolSemantic(toolName) ?? toolName) {
|
|
14773
15039
|
case "bash":
|
|
14774
15040
|
return "running_command";
|
|
14775
15041
|
case "check_messages":
|
|
@@ -14787,6 +15053,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
14787
15053
|
if (options.includeCompactionWatchdog ?? true) {
|
|
14788
15054
|
this.clearCompactionWatchdog(ap);
|
|
14789
15055
|
}
|
|
15056
|
+
this.clearReviewWatchdog(ap);
|
|
14790
15057
|
this.clearStalledRecoverySigtermWatchdog(ap);
|
|
14791
15058
|
}
|
|
14792
15059
|
clearRuntimeErrorDeliveryBackoffWithTrace(agentId, ap, resetSource) {
|
|
@@ -15119,7 +15386,11 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15119
15386
|
path: input.pathname,
|
|
15120
15387
|
query_keys: input.queryKeys,
|
|
15121
15388
|
error_name: input.errorName,
|
|
15122
|
-
error_message: input.errorMessage
|
|
15389
|
+
error_message: input.errorMessage,
|
|
15390
|
+
response_status_code: input.responseStatusCode,
|
|
15391
|
+
response_code: input.responseCode,
|
|
15392
|
+
lifecycle_invalid_agent_id: input.lifecycleInvalidAgentId,
|
|
15393
|
+
lifecycle_invalid_context: input.lifecycleInvalidContext
|
|
15123
15394
|
}, "error");
|
|
15124
15395
|
}
|
|
15125
15396
|
recordAgentProxyTransportNormalizedError(agentId, input) {
|
|
@@ -15158,7 +15429,8 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15158
15429
|
detailKind: activity.statusEntry.detailKind ?? "daemon_activity",
|
|
15159
15430
|
entries: activity.entries,
|
|
15160
15431
|
launchId: ap?.launchId || void 0,
|
|
15161
|
-
clientSeq: ap ? this.nextActivityClientSeq(agentId) : void 0
|
|
15432
|
+
clientSeq: ap ? this.nextActivityClientSeq(agentId) : void 0,
|
|
15433
|
+
isHeartbeat: false
|
|
15162
15434
|
});
|
|
15163
15435
|
}
|
|
15164
15436
|
recordRuntimeDiagnosticActivity(agentId, ap, event) {
|
|
@@ -15171,7 +15443,8 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15171
15443
|
detailKind: ap.lastActivityDetailKind || "none",
|
|
15172
15444
|
entries: [runtimeDiagnosticTrajectoryEntry(event)],
|
|
15173
15445
|
launchId: ap.launchId || void 0,
|
|
15174
|
-
clientSeq: this.nextActivityClientSeq(agentId)
|
|
15446
|
+
clientSeq: this.nextActivityClientSeq(agentId),
|
|
15447
|
+
isHeartbeat: false
|
|
15175
15448
|
});
|
|
15176
15449
|
this.recordDaemonTrace("daemon.runtime.diagnostic", {
|
|
15177
15450
|
agentId,
|
|
@@ -15180,6 +15453,38 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15180
15453
|
...runtimeDiagnosticTraceAttrs(event)
|
|
15181
15454
|
});
|
|
15182
15455
|
}
|
|
15456
|
+
/**
|
|
15457
|
+
* APM 1.6 6a — surface a generic structured "working" signal from an
|
|
15458
|
+
* internal_progress liveness tick during a long turn. Only transitions INTO
|
|
15459
|
+
* the runtime-progress state once (idempotent while already in it) so the
|
|
15460
|
+
* high-frequency Claude partial-message stream does not spam a rendered status
|
|
15461
|
+
* line every tick; the activity heartbeat then keeps the signal live. Carries
|
|
15462
|
+
* no raw content — a bounded "Working" detail only. Never marks a subagent.
|
|
15463
|
+
*/
|
|
15464
|
+
maybeBroadcastRuntimeProgressActivity(agentId, ap) {
|
|
15465
|
+
const alreadyLive = ap.lastActivityKind === "working" || ap.lastActivityKind === "thinking";
|
|
15466
|
+
if (alreadyLive) return;
|
|
15467
|
+
this.broadcastActivity(agentId, "working", "Working", [], void 0, "runtime_progress");
|
|
15468
|
+
}
|
|
15469
|
+
recordSubagentProgressActivity(agentId, ap, event) {
|
|
15470
|
+
this.flushPendingTrajectory(agentId);
|
|
15471
|
+
this.broadcastActivity(
|
|
15472
|
+
agentId,
|
|
15473
|
+
"working",
|
|
15474
|
+
subagentProgressDetail(event),
|
|
15475
|
+
[],
|
|
15476
|
+
void 0,
|
|
15477
|
+
"subagent_activity",
|
|
15478
|
+
"working",
|
|
15479
|
+
subagentLineageFromEvent(event)
|
|
15480
|
+
);
|
|
15481
|
+
this.recordDaemonTrace("daemon.runtime.subagent.progress", {
|
|
15482
|
+
agentId,
|
|
15483
|
+
launchId: ap.launchId || void 0,
|
|
15484
|
+
runtime: ap.config.runtime,
|
|
15485
|
+
...subagentProgressTraceAttrs(event)
|
|
15486
|
+
});
|
|
15487
|
+
}
|
|
15183
15488
|
recordRuntimeRecoveryActivity(agentId, ap, event) {
|
|
15184
15489
|
this.sendToServer({
|
|
15185
15490
|
type: "agent:activity",
|
|
@@ -15190,7 +15495,8 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15190
15495
|
detailKind: ap.lastActivityDetailKind || "none",
|
|
15191
15496
|
entries: [runtimeRecoveryTrajectoryEntry(event)],
|
|
15192
15497
|
launchId: ap.launchId || void 0,
|
|
15193
|
-
clientSeq: this.nextActivityClientSeq(agentId)
|
|
15498
|
+
clientSeq: this.nextActivityClientSeq(agentId),
|
|
15499
|
+
isHeartbeat: false
|
|
15194
15500
|
});
|
|
15195
15501
|
this.recordDaemonTrace("daemon.runtime.recovery.visible", {
|
|
15196
15502
|
agentId,
|
|
@@ -15416,7 +15722,10 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15416
15722
|
rebindRunningStart(agentId, start, reason) {
|
|
15417
15723
|
const ap = this.agents.get(agentId);
|
|
15418
15724
|
if (!ap) {
|
|
15419
|
-
this.lifecycleRecords.setPendingStartRebind(agentId,
|
|
15725
|
+
this.lifecycleRecords.setPendingStartRebind(agentId, {
|
|
15726
|
+
...start,
|
|
15727
|
+
stopEpochAtRebind: this.lifecycleRecords.stopEpoch(agentId)
|
|
15728
|
+
});
|
|
15420
15729
|
return false;
|
|
15421
15730
|
}
|
|
15422
15731
|
const previousLaunchId = ap.launchId;
|
|
@@ -15466,7 +15775,16 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15466
15775
|
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages),
|
|
15467
15776
|
reason: "already_starting"
|
|
15468
15777
|
});
|
|
15469
|
-
this.lifecycleRecords.setPendingStartRebind(agentId, {
|
|
15778
|
+
this.lifecycleRecords.setPendingStartRebind(agentId, {
|
|
15779
|
+
config,
|
|
15780
|
+
wakeMessage,
|
|
15781
|
+
unreadSummary,
|
|
15782
|
+
resumePrompt,
|
|
15783
|
+
launchId,
|
|
15784
|
+
wakeMessageTransient,
|
|
15785
|
+
resumeMessages,
|
|
15786
|
+
stopEpochAtRebind: this.lifecycleRecords.stopEpoch(agentId)
|
|
15787
|
+
});
|
|
15470
15788
|
logger.info(`[Agent ${agentId}] Start rebind deferred (startup in progress)`);
|
|
15471
15789
|
return;
|
|
15472
15790
|
}
|
|
@@ -15544,7 +15862,10 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15544
15862
|
if (this.agents.has(item.agentId)) {
|
|
15545
15863
|
this.rebindRunningStart(item.agentId, item, "already_running_or_starting");
|
|
15546
15864
|
} else {
|
|
15547
|
-
this.lifecycleRecords.setPendingStartRebind(item.agentId,
|
|
15865
|
+
this.lifecycleRecords.setPendingStartRebind(item.agentId, {
|
|
15866
|
+
...item,
|
|
15867
|
+
stopEpochAtRebind: this.lifecycleRecords.stopEpoch(item.agentId)
|
|
15868
|
+
});
|
|
15548
15869
|
}
|
|
15549
15870
|
logger.info(`[Agent ${item.agentId}] Queued start skipped (already running or starting)`);
|
|
15550
15871
|
item.resolve();
|
|
@@ -15642,10 +15963,20 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15642
15963
|
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages),
|
|
15643
15964
|
reason: "already_starting"
|
|
15644
15965
|
});
|
|
15645
|
-
this.lifecycleRecords.setPendingStartRebind(agentId, {
|
|
15966
|
+
this.lifecycleRecords.setPendingStartRebind(agentId, {
|
|
15967
|
+
config,
|
|
15968
|
+
wakeMessage,
|
|
15969
|
+
unreadSummary,
|
|
15970
|
+
resumePrompt,
|
|
15971
|
+
launchId,
|
|
15972
|
+
wakeMessageTransient,
|
|
15973
|
+
resumeMessages,
|
|
15974
|
+
stopEpochAtRebind: this.lifecycleRecords.stopEpoch(agentId)
|
|
15975
|
+
});
|
|
15646
15976
|
logger.info(`[Agent ${agentId}] Start rebind deferred (startup in progress)`);
|
|
15647
15977
|
return;
|
|
15648
15978
|
}
|
|
15979
|
+
let startStopEpoch = this.lifecycleRecords.stopEpoch(agentId);
|
|
15649
15980
|
this.agentStarts.markStarting(agentId);
|
|
15650
15981
|
let agentProcess = null;
|
|
15651
15982
|
let pendingStartRebind;
|
|
@@ -15691,6 +16022,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
15691
16022
|
resumePrompt = pendingStartRebind.resumePrompt;
|
|
15692
16023
|
launchId = pendingStartRebind.launchId || launchId;
|
|
15693
16024
|
resumeMessages = pendingStartRebind.resumeMessages;
|
|
16025
|
+
startStopEpoch = pendingStartRebind.stopEpochAtRebind ?? startStopEpoch;
|
|
15694
16026
|
if (pendingStartRebind.wakeMessage) {
|
|
15695
16027
|
wakeMessage = pendingStartRebind.wakeMessage;
|
|
15696
16028
|
wakeMessageTransient = pendingStartRebind.wakeMessageTransient === true;
|
|
@@ -15834,6 +16166,11 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
15834
16166
|
this.agentStarts.clearStarting(agentId);
|
|
15835
16167
|
this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "defer_until_concrete_message" });
|
|
15836
16168
|
this.assertStartPendingDeliveryInvariants("defer-empty-start-drain");
|
|
16169
|
+
if (this.lifecycleRecords.stopEpochChanged(agentId, startStopEpoch)) {
|
|
16170
|
+
this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
|
|
16171
|
+
logger.info(`[Agent ${agentId}] Deferred ${driver.id} spawn suppressed by stop request`);
|
|
16172
|
+
return;
|
|
16173
|
+
}
|
|
15837
16174
|
this.lifecycleRecords.setRestartSnapshot(agentId, {
|
|
15838
16175
|
config: this.buildRestartSafeConfig(runtimeConfig, runtimeConfig.sessionId || null),
|
|
15839
16176
|
sessionId: runtimeConfig.sessionId || null,
|
|
@@ -15896,6 +16233,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
15896
16233
|
readinessTransition: null,
|
|
15897
16234
|
activation: { kind: "idle" },
|
|
15898
16235
|
compaction: { kind: "none" },
|
|
16236
|
+
review: { kind: "none" },
|
|
15899
16237
|
runtimeProgress: new RuntimeProgressState(Date.now()),
|
|
15900
16238
|
runtimeTraceSpan: null,
|
|
15901
16239
|
runtimeTraceCounters: createRuntimeTraceCounters(),
|
|
@@ -15919,6 +16257,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
15919
16257
|
};
|
|
15920
16258
|
this.startingInboxes.drainOnSpawn(agentId);
|
|
15921
16259
|
this.agents.set(agentId, agentProcess);
|
|
16260
|
+
if (this.lifecycleRecords.stopEpochChanged(agentId, startStopEpoch)) {
|
|
16261
|
+
await this.cleanupStoppedRuntimeStart(agentId, agentProcess);
|
|
16262
|
+
return;
|
|
16263
|
+
}
|
|
15922
16264
|
this.lifecycleRecords.setRestartSnapshot(agentId, {
|
|
15923
16265
|
config: this.buildRestartSafeConfig(runtimeConfig, restartSessionId),
|
|
15924
16266
|
sessionId: restartSessionId,
|
|
@@ -16108,16 +16450,16 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16108
16450
|
return;
|
|
16109
16451
|
}
|
|
16110
16452
|
if (processEndedCleanly) {
|
|
16453
|
+
const pendingRestartMessages = ap.inbox.splice(0).filter((message) => !this.isTransientDelivery(message));
|
|
16111
16454
|
let queuedWakeMessage;
|
|
16112
|
-
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16117
|
-
|
|
16455
|
+
const bufferedRestartMessages = [];
|
|
16456
|
+
for (const message of pendingRestartMessages) {
|
|
16457
|
+
if (!queuedWakeMessage && !this.shouldDeferWakeMessage(agentId, ap.driver, message)) {
|
|
16458
|
+
queuedWakeMessage = message;
|
|
16459
|
+
} else {
|
|
16460
|
+
bufferedRestartMessages.push(message);
|
|
16118
16461
|
}
|
|
16119
16462
|
}
|
|
16120
|
-
const unreadSummary2 = queuedWakeMessage ? buildUnreadSummary(ap.inbox, formatChannelLabel(queuedWakeMessage)) : void 0;
|
|
16121
16463
|
if (queuedWakeMessage) {
|
|
16122
16464
|
logger.info(`[Agent ${agentId}] Turn completed; restarting immediately for queued message`);
|
|
16123
16465
|
const nextConfig = this.buildRestartSafeConfig(ap.config, ap.sessionId);
|
|
@@ -16131,7 +16473,12 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16131
16473
|
if (expectedTerminationReason === "stalled_recovery") {
|
|
16132
16474
|
this.lifecycleRecords.setPendingSpawnCause(agentId, "restart_stall");
|
|
16133
16475
|
}
|
|
16134
|
-
this.startAgent(agentId, nextConfig, queuedWakeMessage,
|
|
16476
|
+
const startPromise = this.startAgent(agentId, nextConfig, queuedWakeMessage, void 0, void 0, ap.launchId || void 0);
|
|
16477
|
+
if (bufferedRestartMessages.length > 0) {
|
|
16478
|
+
this.startingInboxes.bufferMessagesDuringStart(agentId, bufferedRestartMessages);
|
|
16479
|
+
this.assertStartPendingDeliveryInvariants("clean-exit-pending-inbox-transfer");
|
|
16480
|
+
}
|
|
16481
|
+
startPromise.catch((err) => {
|
|
16135
16482
|
logger.error(`[Agent ${agentId}] Failed to continue with queued message`, err);
|
|
16136
16483
|
if (this.reportRunnerCredentialMintFailure(agentId, err, ap.launchId, "queued_continuation")) {
|
|
16137
16484
|
this.lifecycleRecords.setRestartSnapshot(agentId, {
|
|
@@ -16187,9 +16534,11 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16187
16534
|
logger.warn(`[Agent ${agentId}] Startup timeout cleanup completed (${reason})`);
|
|
16188
16535
|
} else if (startupRequestErrorTermination) {
|
|
16189
16536
|
this.lifecycleRecords.deleteRestartSnapshot(agentId);
|
|
16537
|
+
this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, "startup_request_error_cleanup", ap);
|
|
16190
16538
|
logger.warn(`[Agent ${agentId}] Startup request failure cleanup completed (${reason})`);
|
|
16191
16539
|
} else {
|
|
16192
16540
|
this.lifecycleRecords.deleteRestartSnapshot(agentId);
|
|
16541
|
+
this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, "nonrecoverable_process_close", ap);
|
|
16193
16542
|
logger.error(`[Agent ${agentId}] Process crashed (${reason}) \u2014 marking inactive`);
|
|
16194
16543
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
16195
16544
|
}
|
|
@@ -16278,6 +16627,47 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16278
16627
|
throw err;
|
|
16279
16628
|
}
|
|
16280
16629
|
}
|
|
16630
|
+
async cleanupStoppedRuntimeStart(agentId, ap) {
|
|
16631
|
+
if (this.agents.get(agentId) !== ap) return;
|
|
16632
|
+
this.agentStarts.clearStarting(agentId);
|
|
16633
|
+
this.lifecycleRecords.deletePendingStartRebind(agentId);
|
|
16634
|
+
this.lifecycleRecords.deletePendingSpawnCause(agentId);
|
|
16635
|
+
this.lifecycleRecords.deleteRestartSnapshot(agentId);
|
|
16636
|
+
this.startingInboxes.cancelStart(agentId);
|
|
16637
|
+
ap.notifications.clearTimer();
|
|
16638
|
+
this.disposeAgentProcessTimers(ap);
|
|
16639
|
+
this.closeRuntimeReadinessTransition(ap, "terminal");
|
|
16640
|
+
this.closeActivationTransition(ap, "terminal");
|
|
16641
|
+
cleanupAgentCredentialProxy(agentId, ap.launchId);
|
|
16642
|
+
this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
|
|
16643
|
+
this.agents.delete(agentId);
|
|
16644
|
+
this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
|
|
16645
|
+
this.assertStartPendingDeliveryInvariants("runtime-start-stop-epoch-fence");
|
|
16646
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
16647
|
+
stop_source: "explicit_request",
|
|
16648
|
+
stop_wait_requested: false,
|
|
16649
|
+
stop_silent: false,
|
|
16650
|
+
stop_epoch_fence: true
|
|
16651
|
+
});
|
|
16652
|
+
try {
|
|
16653
|
+
await ap.runtime.stop({ signal: "SIGTERM", reason: "explicit_request" });
|
|
16654
|
+
} catch (err) {
|
|
16655
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
16656
|
+
logger.warn(`[Agent ${agentId}] Failed to stop runtime suppressed by stop epoch: ${reason}`);
|
|
16657
|
+
}
|
|
16658
|
+
logger.info(`[Agent ${agentId}] Runtime start discarded after stop request`);
|
|
16659
|
+
}
|
|
16660
|
+
suppressFailedRestartAfterStop(agentId, stopEpochAtRestart, source) {
|
|
16661
|
+
if (!this.lifecycleRecords.stopEpochChanged(agentId, stopEpochAtRestart)) return false;
|
|
16662
|
+
this.lifecycleRecords.deleteRestartSnapshot(agentId);
|
|
16663
|
+
this.lifecycleRecords.deletePendingStartRebind(agentId);
|
|
16664
|
+
this.lifecycleRecords.deletePendingSpawnCause(agentId);
|
|
16665
|
+
this.startingInboxes.cancelStart(agentId);
|
|
16666
|
+
this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
|
|
16667
|
+
this.assertStartPendingDeliveryInvariants(`${source}-stop-epoch-fence`);
|
|
16668
|
+
logger.info(`[Agent ${agentId}] Failed ${source} restart suppressed after stop request`);
|
|
16669
|
+
return true;
|
|
16670
|
+
}
|
|
16281
16671
|
cleanupFailedRuntimeStart(agentId, ap, err) {
|
|
16282
16672
|
if (!ap) return;
|
|
16283
16673
|
if (this.agents.get(agentId) !== ap) return;
|
|
@@ -16298,6 +16688,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16298
16688
|
if (this.lifecycleRecords.deleteTerminalFailure(agentId)) {
|
|
16299
16689
|
this.closeNoProcessResidency(agentId, "terminal", { negativeEvidenceBucket: "runtime_start_failed" });
|
|
16300
16690
|
}
|
|
16691
|
+
this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, "runtime_start_failed_cleanup", ap);
|
|
16301
16692
|
}
|
|
16302
16693
|
cleanupTerminalRuntimeFailure(agentId, ap, detail) {
|
|
16303
16694
|
if (this.agents.get(agentId) !== ap) return;
|
|
@@ -16583,6 +16974,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16583
16974
|
return messages.some((message) => !runtimeProfileNotificationFromMessage(message));
|
|
16584
16975
|
}
|
|
16585
16976
|
async stopAgent(agentId, { wait = false, silent = false } = {}) {
|
|
16977
|
+
this.lifecycleRecords.recordStop(agentId);
|
|
16586
16978
|
this.cancelQueuedAgentStart(agentId, "stop requested");
|
|
16587
16979
|
this.lifecycleRecords.deletePendingStartRebind(agentId);
|
|
16588
16980
|
this.lifecycleRecords.deleteRestartSnapshot(agentId);
|
|
@@ -16759,6 +17151,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16759
17151
|
return true;
|
|
16760
17152
|
}
|
|
16761
17153
|
this.lifecycleRecords.deleteRestartSnapshot(agentId);
|
|
17154
|
+
const restartStopEpoch = this.lifecycleRecords.stopEpoch(agentId);
|
|
16762
17155
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
16763
17156
|
outcome: "auto_restart_from_idle",
|
|
16764
17157
|
accepted: true,
|
|
@@ -16774,6 +17167,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
16774
17167
|
return true;
|
|
16775
17168
|
}, (err) => {
|
|
16776
17169
|
logger.error(`[Agent ${agentId}] Failed to auto-restart`, err);
|
|
17170
|
+
if (this.suppressFailedRestartAfterStop(agentId, restartStopEpoch, "idle-auto-restart")) {
|
|
17171
|
+
return false;
|
|
17172
|
+
}
|
|
16777
17173
|
if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "idle_auto_restart")) {
|
|
16778
17174
|
this.lifecycleRecords.setRestartSnapshot(agentId, cached);
|
|
16779
17175
|
const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
|
|
@@ -17428,12 +17824,23 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
17428
17824
|
return true;
|
|
17429
17825
|
}
|
|
17430
17826
|
this.lifecycleRecords.deleteRestartSnapshot(agentId);
|
|
17827
|
+
const restartStopEpoch = this.lifecycleRecords.stopEpoch(agentId);
|
|
17431
17828
|
return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0).then(() => {
|
|
17432
17829
|
this.resetSpawnFailBackoff(agentId);
|
|
17433
17830
|
this.assertStartPendingDeliveryInvariants("runtime-profile-auto-restart-success");
|
|
17434
17831
|
return true;
|
|
17435
17832
|
}, (err) => {
|
|
17436
17833
|
logger.error(`[Agent ${agentId}] Failed to auto-restart for runtime profile notification`, err);
|
|
17834
|
+
if (this.suppressFailedRestartAfterStop(agentId, restartStopEpoch, "runtime-profile-auto-restart")) {
|
|
17835
|
+
span.end("ok", {
|
|
17836
|
+
attrs: {
|
|
17837
|
+
outcome: "suppressed_after_stop",
|
|
17838
|
+
runtime: cached.config.runtime,
|
|
17839
|
+
launchId: cached.launchId || void 0
|
|
17840
|
+
}
|
|
17841
|
+
});
|
|
17842
|
+
return false;
|
|
17843
|
+
}
|
|
17437
17844
|
if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "runtime_profile_auto_restart")) {
|
|
17438
17845
|
this.lifecycleRecords.setRestartSnapshot(agentId, cached);
|
|
17439
17846
|
const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
|
|
@@ -17574,7 +17981,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
17574
17981
|
return deleteWorkspaceDirectory(this.dataDir, directoryName);
|
|
17575
17982
|
}
|
|
17576
17983
|
// Workspace file browsing
|
|
17577
|
-
async getFileTree(agentId, dirPath) {
|
|
17984
|
+
async getFileTree(agentId, dirPath, includeHidden = false) {
|
|
17578
17985
|
const agentDir = path14.join(this.dataDir, agentId);
|
|
17579
17986
|
try {
|
|
17580
17987
|
await stat2(agentDir);
|
|
@@ -17587,9 +17994,16 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
17587
17994
|
if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
|
|
17588
17995
|
return [];
|
|
17589
17996
|
}
|
|
17997
|
+
const relativePath = path14.relative(agentDir, resolved);
|
|
17998
|
+
if (isWorkspaceNeverVisibleHiddenPath(relativePath)) {
|
|
17999
|
+
return [];
|
|
18000
|
+
}
|
|
18001
|
+
if (!includeHidden && isWorkspaceHiddenPath(relativePath)) {
|
|
18002
|
+
return [];
|
|
18003
|
+
}
|
|
17590
18004
|
targetDir = resolved;
|
|
17591
18005
|
}
|
|
17592
|
-
return this.listDirectoryChildren(targetDir, agentDir);
|
|
18006
|
+
return this.listDirectoryChildren(targetDir, agentDir, includeHidden);
|
|
17593
18007
|
}
|
|
17594
18008
|
async readFile(agentId, filePath) {
|
|
17595
18009
|
const agentDir = path14.join(this.dataDir, agentId);
|
|
@@ -17597,6 +18011,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
17597
18011
|
if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
|
|
17598
18012
|
throw new Error("Access denied");
|
|
17599
18013
|
}
|
|
18014
|
+
const relativePath = path14.relative(agentDir, resolved);
|
|
18015
|
+
if (isWorkspaceNeverVisibleHiddenPath(relativePath) || isWorkspaceSecretFilePath(relativePath)) {
|
|
18016
|
+
throw new Error("Preview is disabled for sensitive workspace files");
|
|
18017
|
+
}
|
|
17600
18018
|
const info = await stat2(resolved);
|
|
17601
18019
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
17602
18020
|
const ext = path14.extname(resolved).toLowerCase();
|
|
@@ -17909,12 +18327,19 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
17909
18327
|
* should carry explicit reason/correlation/window attrs so the server no
|
|
17910
18328
|
* longer infers lifecycle semantics from generic activity strings.
|
|
17911
18329
|
*/
|
|
17912
|
-
broadcastActivity(agentId, activityKind, detail, extraTrajectory = [], launchIdOverride, detailKind = "other", activityDisplay = activityKind) {
|
|
18330
|
+
broadcastActivity(agentId, activityKind, detail, extraTrajectory = [], launchIdOverride, detailKind = "other", activityDisplay = activityKind, subagentLineage) {
|
|
17913
18331
|
const ap = this.agents.get(agentId);
|
|
17914
18332
|
const entries = [...extraTrajectory];
|
|
17915
18333
|
const hasToolStart = entries.some((e) => e.kind === "tool_start");
|
|
17916
18334
|
if (!hasToolStart) {
|
|
17917
|
-
entries.push({
|
|
18335
|
+
entries.push({
|
|
18336
|
+
kind: "status",
|
|
18337
|
+
activity: activityKind,
|
|
18338
|
+
activityKind,
|
|
18339
|
+
detail,
|
|
18340
|
+
detailKind,
|
|
18341
|
+
...subagentLineage ? { subagent: subagentLineage } : {}
|
|
18342
|
+
});
|
|
17918
18343
|
}
|
|
17919
18344
|
const launchId = launchIdOverride || ap?.launchId || void 0;
|
|
17920
18345
|
const clientSeq = this.nextActivityClientSeq(agentId);
|
|
@@ -17929,7 +18354,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
17929
18354
|
entries,
|
|
17930
18355
|
launchId,
|
|
17931
18356
|
clientSeq,
|
|
17932
|
-
producerFactId
|
|
18357
|
+
producerFactId,
|
|
18358
|
+
isHeartbeat: false
|
|
17933
18359
|
});
|
|
17934
18360
|
this.recordActivityProducedTrace(agentId, activityKind, detail, detailKind, entries, ap, launchId, clientSeq, producerFactId);
|
|
17935
18361
|
if (ap) {
|
|
@@ -17957,7 +18383,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
17957
18383
|
detailKind: ap.lastActivityDetailKind,
|
|
17958
18384
|
launchId: heartbeatLaunchId,
|
|
17959
18385
|
clientSeq: heartbeatClientSeq,
|
|
17960
|
-
producerFactId: heartbeatProducerFactId
|
|
18386
|
+
producerFactId: heartbeatProducerFactId,
|
|
18387
|
+
// The one knowing site: this timer re-broadcasts stale
|
|
18388
|
+
// lastActivity, so it declares its replay provenance.
|
|
18389
|
+
isHeartbeat: true
|
|
17961
18390
|
});
|
|
17962
18391
|
this.recordActivityProducedTrace(agentId, ap.lastActivityKind, ap.lastActivityDetail, ap.lastActivityDetailKind, [], ap, heartbeatLaunchId, heartbeatClientSeq, heartbeatProducerFactId);
|
|
17963
18392
|
}, ACTIVITY_HEARTBEAT_MS);
|
|
@@ -18038,7 +18467,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18038
18467
|
launchId,
|
|
18039
18468
|
probeId,
|
|
18040
18469
|
clientSeq,
|
|
18041
|
-
producerFactId
|
|
18470
|
+
producerFactId,
|
|
18471
|
+
isHeartbeat: false
|
|
18042
18472
|
});
|
|
18043
18473
|
this.recordActivityProducedTrace(agentId, activityKind, detail, detailKind, [], ap, launchId, clientSeq, producerFactId);
|
|
18044
18474
|
}
|
|
@@ -18050,13 +18480,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18050
18480
|
ap.pendingTrajectory = null;
|
|
18051
18481
|
const text = pending.text.length > MAX_TRAJECTORY_TEXT ? pending.text.slice(0, MAX_TRAJECTORY_TEXT) + "\u2026" : pending.text;
|
|
18052
18482
|
if (!text) return;
|
|
18053
|
-
|
|
18054
|
-
|
|
18055
|
-
} else {
|
|
18056
|
-
this.broadcastActivity(agentId, "thinking", "", [{ kind: "text", text }], void 0, "none");
|
|
18057
|
-
}
|
|
18483
|
+
const entry = pending.kind === "thinking" ? { kind: "thinking", text, ...pending.subagent ? { subagent: pending.subagent } : {} } : { kind: "text", text, ...pending.subagent ? { subagent: pending.subagent } : {} };
|
|
18484
|
+
this.broadcastActivity(agentId, "thinking", "", [entry], void 0, "none");
|
|
18058
18485
|
}
|
|
18059
|
-
queueTrajectoryText(agentId, kind, text) {
|
|
18486
|
+
queueTrajectoryText(agentId, kind, text, subagent) {
|
|
18060
18487
|
const ap = this.agents.get(agentId);
|
|
18061
18488
|
if (!ap) {
|
|
18062
18489
|
this.recordDaemonTrace("daemon.agent.activity.skipped", {
|
|
@@ -18072,7 +18499,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18072
18499
|
return;
|
|
18073
18500
|
}
|
|
18074
18501
|
const pending = ap.pendingTrajectory;
|
|
18075
|
-
|
|
18502
|
+
const sameLineage = JSON.stringify(pending?.subagent ?? null) === JSON.stringify(subagent ?? null);
|
|
18503
|
+
if (pending && pending.kind === kind && sameLineage) {
|
|
18076
18504
|
pending.text += text;
|
|
18077
18505
|
clearTimeout(pending.timer);
|
|
18078
18506
|
pending.timer = setTimeout(() => this.flushPendingTrajectory(agentId), TRAJECTORY_COALESCE_MS);
|
|
@@ -18085,6 +18513,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18085
18513
|
ap.pendingTrajectory = {
|
|
18086
18514
|
kind,
|
|
18087
18515
|
text,
|
|
18516
|
+
...subagent ? { subagent } : {},
|
|
18088
18517
|
timer: setTimeout(() => this.flushPendingTrajectory(agentId), TRAJECTORY_COALESCE_MS)
|
|
18089
18518
|
};
|
|
18090
18519
|
}
|
|
@@ -18187,6 +18616,29 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18187
18616
|
ap.compaction = { ...ap.compaction, watchdog: null };
|
|
18188
18617
|
this.broadcastActivity(agentId, "working", "Context compaction still running; no finish event observed", [], void 0, "compaction_stale");
|
|
18189
18618
|
}
|
|
18619
|
+
startReviewWatchdog(agentId, ap) {
|
|
18620
|
+
this.clearReviewWatchdog(ap);
|
|
18621
|
+
const startedAt = Date.now();
|
|
18622
|
+
const watchdog = setTimeout(() => {
|
|
18623
|
+
this.markReviewStale(agentId, startedAt);
|
|
18624
|
+
}, REVIEW_STALE_MS);
|
|
18625
|
+
ap.review = { kind: "active", startedAt, watchdog };
|
|
18626
|
+
}
|
|
18627
|
+
clearReviewWatchdog(ap) {
|
|
18628
|
+
if (ap.review.kind === "active" && ap.review.watchdog) {
|
|
18629
|
+
clearTimeout(ap.review.watchdog);
|
|
18630
|
+
}
|
|
18631
|
+
ap.review = { kind: "none" };
|
|
18632
|
+
}
|
|
18633
|
+
markReviewStale(agentId, startedAt) {
|
|
18634
|
+
const ap = this.agents.get(agentId);
|
|
18635
|
+
if (!ap || ap.review.kind !== "active" || ap.review.startedAt !== startedAt) return;
|
|
18636
|
+
ap.review = { ...ap.review, watchdog: null };
|
|
18637
|
+
this.broadcastActivity(agentId, "working", "Review mode still active; no finish event observed", [], void 0, "review_stale");
|
|
18638
|
+
const reduction = reduceApmGatedReview(ap.gatedSteering, { kind: "review_finished" });
|
|
18639
|
+
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "review_finished", inferred: true });
|
|
18640
|
+
this.flushReviewBoundaryMessages(agentId, ap);
|
|
18641
|
+
}
|
|
18190
18642
|
completeCompactionIfActive(agentId, detail = "Context compaction finished", options = {}) {
|
|
18191
18643
|
const ap = this.agents.get(agentId);
|
|
18192
18644
|
if (!ap || ap.compaction.kind !== "active") return;
|
|
@@ -18795,6 +19247,23 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18795
19247
|
if (ap.runtimeProgress.isStale) return true;
|
|
18796
19248
|
const staleForMs = ap.runtimeProgress.ageMs();
|
|
18797
19249
|
if (staleForMs < RUNTIME_PROGRESS_STALE_MS) return false;
|
|
19250
|
+
const subprocessPidAlive = this.probeRuntimeProcessLiveness(ap);
|
|
19251
|
+
if (subprocessPidAlive === true) {
|
|
19252
|
+
this.recordDaemonTrace("daemon.runtime.stall.suppressed_alive", {
|
|
19253
|
+
...this.processLifecycleIdentityAttrs(agentId, ap),
|
|
19254
|
+
last_event_kind: ap.lastActivityKind || void 0,
|
|
19255
|
+
last_event_age_ms_bucket: bucketMs(staleForMs),
|
|
19256
|
+
subprocess_pid_alive: true,
|
|
19257
|
+
subprocess_socket_alive: !ap.runtime.closed,
|
|
19258
|
+
daemon_connected_to_server: this.serverConnected()
|
|
19259
|
+
});
|
|
19260
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.silent_alive", {
|
|
19261
|
+
staleForMs: bucketMs(staleForMs),
|
|
19262
|
+
lastActivity: ap.lastActivityKind || void 0,
|
|
19263
|
+
lastActivityDetailKind: ap.lastActivityDetailKind
|
|
19264
|
+
});
|
|
19265
|
+
return false;
|
|
19266
|
+
}
|
|
18798
19267
|
ap.runtimeProgress.markStale();
|
|
18799
19268
|
const staleForMinutes = Math.max(1, Math.floor(staleForMs / 6e4));
|
|
18800
19269
|
const diagnostic = buildRuntimeStallDiagnostic(ap, staleForMs, staleForMinutes);
|
|
@@ -18814,15 +19283,6 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18814
19283
|
...runtimeTraceCounterAttrs(ap),
|
|
18815
19284
|
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_stalled")
|
|
18816
19285
|
});
|
|
18817
|
-
let subprocessPidAlive;
|
|
18818
|
-
if (typeof ap.runtime.pid === "number") {
|
|
18819
|
-
try {
|
|
18820
|
-
process.kill(ap.runtime.pid, 0);
|
|
18821
|
-
subprocessPidAlive = true;
|
|
18822
|
-
} catch {
|
|
18823
|
-
subprocessPidAlive = false;
|
|
18824
|
-
}
|
|
18825
|
-
}
|
|
18826
19286
|
this.recordDaemonTrace("daemon.runtime.stall.detected", {
|
|
18827
19287
|
...this.processLifecycleIdentityAttrs(agentId, ap),
|
|
18828
19288
|
last_event_kind: ap.lastActivityKind || void 0,
|
|
@@ -18834,6 +19294,17 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18834
19294
|
this.broadcastActivity(agentId, "error", diagnostic.detail, [], void 0, "runtime_stalled");
|
|
18835
19295
|
return true;
|
|
18836
19296
|
}
|
|
19297
|
+
probeRuntimeProcessLiveness(ap) {
|
|
19298
|
+
const pid = ap.runtime.pid;
|
|
19299
|
+
if (typeof pid !== "number") return void 0;
|
|
19300
|
+
try {
|
|
19301
|
+
process.kill(pid, 0);
|
|
19302
|
+
return true;
|
|
19303
|
+
} catch (err) {
|
|
19304
|
+
const code = typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
|
|
19305
|
+
return code === "EPERM" ? true : false;
|
|
19306
|
+
}
|
|
19307
|
+
}
|
|
18837
19308
|
recoverStaleProcessForQueuedMessageIfNeeded(agentId, ap) {
|
|
18838
19309
|
const staleForMs = ap.runtimeProgress.ageMs();
|
|
18839
19310
|
const reduction = reduceApmStalledRecoveryTermination(ap.gatedSteering, {
|
|
@@ -18944,6 +19415,15 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18944
19415
|
source: event.source,
|
|
18945
19416
|
itemType: event.itemType,
|
|
18946
19417
|
payloadBytes: event.payloadBytes
|
|
19418
|
+
} : event.kind === "subagent_progress" ? {
|
|
19419
|
+
kind: event.kind,
|
|
19420
|
+
source: event.source,
|
|
19421
|
+
phase: event.phase,
|
|
19422
|
+
parent_tool_use_id_present: Boolean(event.parentToolUseId),
|
|
19423
|
+
subagent_type_present: Boolean(event.subagentType),
|
|
19424
|
+
task_id_present: Boolean(event.taskId),
|
|
19425
|
+
last_tool_name_present: Boolean(event.lastToolName),
|
|
19426
|
+
payloadBytes: event.payloadBytes
|
|
18947
19427
|
} : event.kind === "runtime_diagnostic" ? runtimeDiagnosticTraceAttrs(event) : event.kind === "runtime_recovery" ? runtimeRecoveryTraceAttrs(event) : { kind: event.kind };
|
|
18948
19428
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.event.received", eventAttrs);
|
|
18949
19429
|
const recordProgressObservedAfterStall = () => {
|
|
@@ -18965,6 +19445,15 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
18965
19445
|
itemType: event.itemType,
|
|
18966
19446
|
payloadBytes: event.payloadBytes
|
|
18967
19447
|
});
|
|
19448
|
+
this.maybeBroadcastRuntimeProgressActivity(agentId, ap);
|
|
19449
|
+
return;
|
|
19450
|
+
}
|
|
19451
|
+
if (event.kind === "subagent_progress") {
|
|
19452
|
+
this.noteRuntimeProgress(ap, event.kind);
|
|
19453
|
+
recordProgressObservedAfterStall();
|
|
19454
|
+
this.invalidateRecoveryErrorView(ap);
|
|
19455
|
+
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
19456
|
+
this.recordSubagentProgressActivity(agentId, ap, event);
|
|
18968
19457
|
return;
|
|
18969
19458
|
}
|
|
18970
19459
|
if (event.kind === "runtime_diagnostic") {
|
|
@@ -19001,7 +19490,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
19001
19490
|
break;
|
|
19002
19491
|
case "thinking": {
|
|
19003
19492
|
this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
|
|
19004
|
-
this.queueTrajectoryText(agentId, "thinking", event.text);
|
|
19493
|
+
this.queueTrajectoryText(agentId, "thinking", event.text, event.subagent);
|
|
19005
19494
|
if (ap) {
|
|
19006
19495
|
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
19007
19496
|
const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
|
|
@@ -19012,7 +19501,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
19012
19501
|
}
|
|
19013
19502
|
case "text": {
|
|
19014
19503
|
this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
|
|
19015
|
-
this.queueTrajectoryText(agentId, "text", event.text);
|
|
19504
|
+
this.queueTrajectoryText(agentId, "text", event.text, event.subagent);
|
|
19016
19505
|
if (ap) {
|
|
19017
19506
|
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
19018
19507
|
const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
|
|
@@ -19039,8 +19528,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
19039
19528
|
this.broadcastActivity(agentId, "working", detail, [{
|
|
19040
19529
|
kind: "tool_start",
|
|
19041
19530
|
toolName: invocation.toolName,
|
|
19042
|
-
toolInput: inputSummary
|
|
19043
|
-
|
|
19531
|
+
toolInput: inputSummary,
|
|
19532
|
+
...event.subagent ? { subagent: event.subagent } : {}
|
|
19533
|
+
}], void 0, event.subagent ? "subagent_activity" : this.toolActivityDetailKind(invocation.toolName));
|
|
19044
19534
|
break;
|
|
19045
19535
|
}
|
|
19046
19536
|
case "tool_output": {
|
|
@@ -19088,11 +19578,15 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
|
|
|
19088
19578
|
if (ap) {
|
|
19089
19579
|
const reduction = reduceApmGatedReview(ap.gatedSteering, { kind: "review_started" });
|
|
19090
19580
|
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "review_started" });
|
|
19581
|
+
this.startReviewWatchdog(agentId, ap);
|
|
19091
19582
|
}
|
|
19092
19583
|
break;
|
|
19093
19584
|
case "review_finished":
|
|
19094
19585
|
this.flushPendingTrajectory(agentId);
|
|
19095
|
-
if (ap)
|
|
19586
|
+
if (ap) {
|
|
19587
|
+
this.clearReviewWatchdog(ap);
|
|
19588
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime.review_mode.finished");
|
|
19589
|
+
}
|
|
19096
19590
|
this.broadcastActivity(agentId, "working", "Review finished", [], void 0, "review_finished");
|
|
19097
19591
|
if (ap) {
|
|
19098
19592
|
const reduction = reduceApmGatedReview(ap.gatedSteering, { kind: "review_finished" });
|
|
@@ -19613,6 +20107,15 @@ ${RESPONSE_TARGET_HINT}`;
|
|
|
19613
20107
|
`${mode} inbox update`
|
|
19614
20108
|
);
|
|
19615
20109
|
if (!sendResult.ok) {
|
|
20110
|
+
const retryNotificationCount = mode === "idle" && ap.driver.supportsStdinNotification && ap.sessionId ? messages.length : 0;
|
|
20111
|
+
const retrySource = source.endsWith("_retry") ? source : `${source}_retry`;
|
|
20112
|
+
const retryScheduled = mode === "idle" ? this.scheduleIdleInboxDeliveryRetry(
|
|
20113
|
+
agentId,
|
|
20114
|
+
ap,
|
|
20115
|
+
retryNotificationCount,
|
|
20116
|
+
retrySource,
|
|
20117
|
+
"daemon.agent.stdin_delivery.idle_retry"
|
|
20118
|
+
) : false;
|
|
19616
20119
|
if (mode === "idle") {
|
|
19617
20120
|
this.commitApmIdleState(agentId, ap, true);
|
|
19618
20121
|
}
|
|
@@ -19637,7 +20140,9 @@ ${RESPONSE_TARGET_HINT}`;
|
|
|
19637
20140
|
outcome: runtimeSendFailureOutcome(sendResult),
|
|
19638
20141
|
failure_reason: sendResult.reason,
|
|
19639
20142
|
failure_error: sendResult.error,
|
|
19640
|
-
requeued_messages_count:
|
|
20143
|
+
requeued_messages_count: retryNotificationCount,
|
|
20144
|
+
retry_scheduled: retryScheduled,
|
|
20145
|
+
notification_timer_present: ap.notifications.hasTimer,
|
|
19641
20146
|
cursors_advanced: "none"
|
|
19642
20147
|
}, "error");
|
|
19643
20148
|
return false;
|
|
@@ -19779,7 +20284,7 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
19779
20284
|
return true;
|
|
19780
20285
|
}
|
|
19781
20286
|
/** List ONE level of a directory — directories returned without children (lazy-loaded on demand) */
|
|
19782
|
-
async listDirectoryChildren(dir, rootDir) {
|
|
20287
|
+
async listDirectoryChildren(dir, rootDir, includeHidden = false) {
|
|
19783
20288
|
let entries;
|
|
19784
20289
|
try {
|
|
19785
20290
|
entries = await readdir2(dir, { withFileTypes: true });
|
|
@@ -19793,7 +20298,9 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
19793
20298
|
});
|
|
19794
20299
|
const nodes = [];
|
|
19795
20300
|
for (const entry of entries) {
|
|
19796
|
-
|
|
20301
|
+
const isHidden = entry.name.startsWith(".");
|
|
20302
|
+
if (entry.name === "node_modules") continue;
|
|
20303
|
+
if (isHidden && (!includeHidden || isWorkspaceNeverVisibleHiddenEntry(entry.name))) continue;
|
|
19797
20304
|
const fullPath = path14.join(dir, entry.name);
|
|
19798
20305
|
const relativePath = path14.relative(rootDir, fullPath);
|
|
19799
20306
|
let info;
|
|
@@ -19803,9 +20310,9 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
19803
20310
|
continue;
|
|
19804
20311
|
}
|
|
19805
20312
|
if (entry.isDirectory()) {
|
|
19806
|
-
nodes.push({ name: entry.name, path: relativePath, isDirectory: true, size: 0, modifiedAt: info.mtime.toISOString() });
|
|
20313
|
+
nodes.push({ name: entry.name, path: relativePath, isDirectory: true, size: 0, modifiedAt: info.mtime.toISOString(), isHidden });
|
|
19807
20314
|
} else {
|
|
19808
|
-
nodes.push({ name: entry.name, path: relativePath, isDirectory: false, size: info.size, modifiedAt: info.mtime.toISOString() });
|
|
20315
|
+
nodes.push({ name: entry.name, path: relativePath, isDirectory: false, size: info.size, modifiedAt: info.mtime.toISOString(), isHidden });
|
|
19809
20316
|
}
|
|
19810
20317
|
}
|
|
19811
20318
|
return nodes;
|
|
@@ -19820,6 +20327,14 @@ var systemClock = {
|
|
|
19820
20327
|
clearTimeout: (timer) => clearTimeout(timer)
|
|
19821
20328
|
};
|
|
19822
20329
|
var INBOUND_WATCHDOG_MS = 7e4;
|
|
20330
|
+
function normalizeHandshakeReason(value) {
|
|
20331
|
+
const raw = Array.isArray(value) ? value[0] : value;
|
|
20332
|
+
if (typeof raw !== "string") return null;
|
|
20333
|
+
const trimmed = raw.trim();
|
|
20334
|
+
if (!trimmed) return null;
|
|
20335
|
+
if (!/^[a-z0-9_:-]{1,80}$/i.test(trimmed)) return "invalid_header";
|
|
20336
|
+
return trimmed;
|
|
20337
|
+
}
|
|
19823
20338
|
function durationMsBucket(ms) {
|
|
19824
20339
|
if (ms == null || !Number.isFinite(ms) || ms < 0) return "unknown";
|
|
19825
20340
|
if (ms === 0) return "0";
|
|
@@ -19843,6 +20358,7 @@ var DaemonConnection = class {
|
|
|
19843
20358
|
lastDroppedSendLogAt = 0;
|
|
19844
20359
|
lastInboundAt = null;
|
|
19845
20360
|
lastInboundMessageKind = null;
|
|
20361
|
+
inboundProbeInFlight = false;
|
|
19846
20362
|
pendingActivityByAgent = /* @__PURE__ */ new Map();
|
|
19847
20363
|
latestObservedLaunchIdByAgent = /* @__PURE__ */ new Map();
|
|
19848
20364
|
constructor(options) {
|
|
@@ -19911,6 +20427,7 @@ var DaemonConnection = class {
|
|
|
19911
20427
|
});
|
|
19912
20428
|
const ws = this.options.wsFactory ? this.options.wsFactory(wsUrl, wsOptions) : new WebSocket(wsUrl, wsOptions);
|
|
19913
20429
|
this.ws = ws;
|
|
20430
|
+
let handshakeRejected = false;
|
|
19914
20431
|
ws.on("open", () => {
|
|
19915
20432
|
if (this.ws !== ws) return;
|
|
19916
20433
|
if (!this.shouldConnect) return;
|
|
@@ -19971,8 +20488,27 @@ var DaemonConnection = class {
|
|
|
19971
20488
|
this.options.onDisconnect();
|
|
19972
20489
|
this.scheduleReconnect();
|
|
19973
20490
|
});
|
|
20491
|
+
ws.on("unexpected-response", (_request, response) => {
|
|
20492
|
+
if (this.ws !== ws) return;
|
|
20493
|
+
handshakeRejected = true;
|
|
20494
|
+
const reason = normalizeHandshakeReason(response.headers["slock-reason"]);
|
|
20495
|
+
const statusCode = response.statusCode ?? 0;
|
|
20496
|
+
const reasonText = reason ? `, slock_reason=${reason}` : "";
|
|
20497
|
+
logger.error(`[Daemon] WebSocket handshake rejected (status=${statusCode}${reasonText})`);
|
|
20498
|
+
this.trace("daemon.connection.handshake_rejected", {
|
|
20499
|
+
status_code: statusCode,
|
|
20500
|
+
slock_reason_present: Boolean(reason),
|
|
20501
|
+
slock_reason: reason
|
|
20502
|
+
}, "error");
|
|
20503
|
+
response.resume();
|
|
20504
|
+
try {
|
|
20505
|
+
ws.terminate();
|
|
20506
|
+
} catch {
|
|
20507
|
+
}
|
|
20508
|
+
});
|
|
19974
20509
|
ws.on("error", (err) => {
|
|
19975
20510
|
if (this.ws !== ws) return;
|
|
20511
|
+
if (handshakeRejected) return;
|
|
19976
20512
|
logger.error(`[Daemon] WebSocket error: ${err.message}`);
|
|
19977
20513
|
this.trace("daemon.connection.error", {
|
|
19978
20514
|
error_class: err.name || "Error"
|
|
@@ -19996,11 +20532,44 @@ var DaemonConnection = class {
|
|
|
19996
20532
|
}
|
|
19997
20533
|
resetWatchdog() {
|
|
19998
20534
|
this.clearWatchdog();
|
|
20535
|
+
this.inboundProbeInFlight = false;
|
|
20536
|
+
this.scheduleWatchdogDeadline();
|
|
20537
|
+
}
|
|
20538
|
+
scheduleWatchdogDeadline() {
|
|
19999
20539
|
const ms = this.options.inboundWatchdogMs ?? INBOUND_WATCHDOG_MS;
|
|
20000
20540
|
this.watchdogTimer = this.clock.setTimeout(() => {
|
|
20001
|
-
|
|
20541
|
+
if (!this.inboundProbeInFlight && this.ws?.readyState === WebSocket.OPEN) {
|
|
20542
|
+
this.inboundProbeInFlight = true;
|
|
20543
|
+
logger.info(`[Daemon] No inbound traffic for ${ms / 1e3}s \u2014 sending liveness probe`);
|
|
20544
|
+
this.trace("daemon.connection.inbound_probe_sent", {
|
|
20545
|
+
inbound_watchdog_ms: ms,
|
|
20546
|
+
last_inbound_message_kind: this.lastInboundMessageKind,
|
|
20547
|
+
last_inbound_age_ms_bucket: this.lastInboundAgeBucket(),
|
|
20548
|
+
ws_ready_state: this.ws.readyState,
|
|
20549
|
+
reconnecting: this.shouldConnect
|
|
20550
|
+
});
|
|
20551
|
+
try {
|
|
20552
|
+
this.ws.send(JSON.stringify({ type: "ping" }));
|
|
20553
|
+
} catch (err) {
|
|
20554
|
+
this.trace("daemon.connection.inbound_probe_send_failed", {
|
|
20555
|
+
inbound_watchdog_ms: ms,
|
|
20556
|
+
error_class: err instanceof Error ? err.name : typeof err,
|
|
20557
|
+
ws_ready_state: this.ws?.readyState ?? null,
|
|
20558
|
+
reconnecting: this.shouldConnect
|
|
20559
|
+
}, "error");
|
|
20560
|
+
try {
|
|
20561
|
+
this.ws?.terminate();
|
|
20562
|
+
} catch {
|
|
20563
|
+
}
|
|
20564
|
+
return;
|
|
20565
|
+
}
|
|
20566
|
+
this.scheduleWatchdogDeadline();
|
|
20567
|
+
return;
|
|
20568
|
+
}
|
|
20569
|
+
logger.warn(`[Daemon] No inbound traffic after liveness probe \u2014 forcing reconnect`);
|
|
20002
20570
|
this.trace("daemon.connection.watchdog_timeout", {
|
|
20003
20571
|
inbound_watchdog_ms: ms,
|
|
20572
|
+
probe_in_flight: this.inboundProbeInFlight,
|
|
20004
20573
|
last_inbound_message_kind: this.lastInboundMessageKind,
|
|
20005
20574
|
last_inbound_age_ms_bucket: this.lastInboundAgeBucket(),
|
|
20006
20575
|
ws_ready_state: this.ws?.readyState ?? null,
|
|
@@ -20957,7 +21526,7 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
|
|
|
20957
21526
|
spanAttrs: ["agentId", "event_kind", "runtime"]
|
|
20958
21527
|
}
|
|
20959
21528
|
};
|
|
20960
|
-
var DAEMON_CLI_USAGE =
|
|
21529
|
+
var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
|
|
20961
21530
|
var RunnerCredentialMintError2 = class extends Error {
|
|
20962
21531
|
code;
|
|
20963
21532
|
retryable;
|
|
@@ -20993,9 +21562,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
20993
21562
|
async function waitForRunnerCredentialRetry2() {
|
|
20994
21563
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
20995
21564
|
}
|
|
20996
|
-
function parseDaemonCliArgs(args) {
|
|
21565
|
+
function parseDaemonCliArgs(args, env = {}) {
|
|
20997
21566
|
let serverUrl = "";
|
|
20998
|
-
let apiKey = "";
|
|
21567
|
+
let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
|
|
20999
21568
|
for (let i = 0; i < args.length; i++) {
|
|
21000
21569
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
21001
21570
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -21032,7 +21601,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
|
|
|
21032
21601
|
}
|
|
21033
21602
|
async function runBundledSlockCli(argv) {
|
|
21034
21603
|
process.argv = [process.execPath, "slock", ...argv];
|
|
21035
|
-
await import("./dist-
|
|
21604
|
+
await import("./dist-IHHGSWH2.js");
|
|
21036
21605
|
}
|
|
21037
21606
|
function detectRuntimes(tracer = noopTracer) {
|
|
21038
21607
|
const ids = [];
|
|
@@ -21144,7 +21713,7 @@ function summarizeIncomingMessage(msg) {
|
|
|
21144
21713
|
case "agent:runtime_profile:daemon_release_notice":
|
|
21145
21714
|
return `(agent=${msg.agentId}, notice=${msg.noticeKey})`;
|
|
21146
21715
|
case "agent:workspace:list":
|
|
21147
|
-
return `(agent=${msg.agentId}, dir=${msg.dirPath || "."})`;
|
|
21716
|
+
return `(agent=${msg.agentId}, dir=${msg.dirPath || "."}, hidden=${msg.includeHidden ? "yes" : "no"})`;
|
|
21148
21717
|
case "agent:workspace:read":
|
|
21149
21718
|
return `(agent=${msg.agentId}, path=${msg.path})`;
|
|
21150
21719
|
case "agent:skills:list":
|
|
@@ -21669,8 +22238,8 @@ var DaemonCore = class {
|
|
|
21669
22238
|
break;
|
|
21670
22239
|
}
|
|
21671
22240
|
case "agent:workspace:list":
|
|
21672
|
-
this.agentManager.getFileTree(msg.agentId, msg.dirPath).then((files) => {
|
|
21673
|
-
this.connection.send({ type: "agent:workspace:file_tree", agentId: msg.agentId, files, dirPath: msg.dirPath });
|
|
22241
|
+
this.agentManager.getFileTree(msg.agentId, msg.dirPath, Boolean(msg.includeHidden)).then((files) => {
|
|
22242
|
+
this.connection.send({ type: "agent:workspace:file_tree", agentId: msg.agentId, files, dirPath: msg.dirPath, includeHidden: Boolean(msg.includeHidden) });
|
|
21674
22243
|
});
|
|
21675
22244
|
break;
|
|
21676
22245
|
case "agent:workspace:read":
|
|
@@ -21974,6 +22543,8 @@ var DaemonCore = class {
|
|
|
21974
22543
|
|
|
21975
22544
|
export {
|
|
21976
22545
|
subscribeDaemonLogs,
|
|
22546
|
+
DAEMON_API_KEY_ENV,
|
|
22547
|
+
scrubDaemonAuthEnv,
|
|
21977
22548
|
resolveWorkspaceDirectoryPath,
|
|
21978
22549
|
scanWorkspaceDirectories,
|
|
21979
22550
|
deleteWorkspaceDirectory,
|