@drisp/cli 0.5.1 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{WorkflowInstallWizard-X754ND4V.js → WorkflowInstallWizard-7Y5PWAKW.js} +2 -2
- package/dist/athena-gateway.js +4113 -4
- package/dist/{chunk-A54HGVML.js → chunk-7E54JMXH.js} +126 -114
- package/dist/{chunk-PEBITVZQ.js → chunk-QVXHUJPH.js} +1944 -1117
- package/dist/cli.js +21 -380
- package/dist/dashboard-daemon.js +103 -8
- package/package.json +1 -1
- package/dist/chunk-2OJ3GGIP.js +0 -104
- package/dist/chunk-OB4HZXR5.js +0 -4124
- package/dist/chunk-ZVOGOZNT.js +0 -395
- package/dist/supervisor.js +0 -692
|
@@ -13,10 +13,6 @@ import {
|
|
|
13
13
|
isValidHookEventEnvelope,
|
|
14
14
|
resolveHookSocketPath
|
|
15
15
|
} from "./chunk-BTKQ67RE.js";
|
|
16
|
-
import {
|
|
17
|
-
createInstanceSocketClient,
|
|
18
|
-
writeAttachmentMirror
|
|
19
|
-
} from "./chunk-ZVOGOZNT.js";
|
|
20
16
|
import {
|
|
21
17
|
TransportUnreachableError,
|
|
22
18
|
createUdsClientTransport,
|
|
@@ -38,7 +34,7 @@ import {
|
|
|
38
34
|
resolveWorkflow,
|
|
39
35
|
resolveWorkflowInstall,
|
|
40
36
|
resolveWorkflowPlugins
|
|
41
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-7E54JMXH.js";
|
|
42
38
|
|
|
43
39
|
// src/infra/daemon/stateDir.ts
|
|
44
40
|
import fs from "fs";
|
|
@@ -6568,12 +6564,16 @@ function resolveCodexMcpConfig(pluginMcpConfig, workflowPlan) {
|
|
|
6568
6564
|
return Object.keys(merged).length === 0 ? void 0 : { mcp_servers: merged };
|
|
6569
6565
|
}
|
|
6570
6566
|
function resolveCodexWorkflowPlugins(workflowPlan) {
|
|
6571
|
-
|
|
6567
|
+
const resolvedTargets = workflowPlan?.resolvedPlugins.map((plugin) => ({
|
|
6572
6568
|
ref: plugin.ref,
|
|
6573
6569
|
pluginName: plugin.pluginName,
|
|
6574
6570
|
marketplacePath: plugin.codexMarketplacePath,
|
|
6575
6571
|
...plugin.version !== void 0 && { version: plugin.version }
|
|
6576
|
-
})) ??
|
|
6572
|
+
})) ?? [];
|
|
6573
|
+
const directTargets = workflowPlan?.codexPlugins ?? [];
|
|
6574
|
+
return [...resolvedTargets, ...directTargets].filter(
|
|
6575
|
+
(plugin, index, array) => array.findIndex((candidate) => candidate.ref === plugin.ref) === index
|
|
6576
|
+
);
|
|
6577
6577
|
}
|
|
6578
6578
|
|
|
6579
6579
|
// src/harnesses/codex/session/promptOptions.ts
|
|
@@ -7349,11 +7349,6 @@ var EXEC_EXIT_CODE = {
|
|
|
7349
7349
|
import crypto2 from "crypto";
|
|
7350
7350
|
import path18 from "path";
|
|
7351
7351
|
|
|
7352
|
-
// src/core/feed/todo.ts
|
|
7353
|
-
function isSubagentTool(toolName) {
|
|
7354
|
-
return toolName === "Task" || toolName === "Agent";
|
|
7355
|
-
}
|
|
7356
|
-
|
|
7357
7352
|
// src/core/feed/entities.ts
|
|
7358
7353
|
var ActorRegistry = class {
|
|
7359
7354
|
actors = /* @__PURE__ */ new Map();
|
|
@@ -8149,625 +8144,639 @@ function createSubagentTracker() {
|
|
|
8149
8144
|
};
|
|
8150
8145
|
}
|
|
8151
8146
|
|
|
8152
|
-
// src/core/feed/
|
|
8153
|
-
function
|
|
8154
|
-
const
|
|
8155
|
-
|
|
8147
|
+
// src/core/feed/internals/projection.ts
|
|
8148
|
+
function readString(...values) {
|
|
8149
|
+
for (const value of values) {
|
|
8150
|
+
if (typeof value === "string") return value;
|
|
8151
|
+
}
|
|
8152
|
+
return void 0;
|
|
8156
8153
|
}
|
|
8157
|
-
function
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
return "in_progress";
|
|
8161
|
-
case "completed":
|
|
8162
|
-
return "completed";
|
|
8163
|
-
case void 0:
|
|
8164
|
-
default:
|
|
8165
|
-
return "pending";
|
|
8154
|
+
function readBoolean(...values) {
|
|
8155
|
+
for (const value of values) {
|
|
8156
|
+
if (typeof value === "boolean") return value;
|
|
8166
8157
|
}
|
|
8158
|
+
return void 0;
|
|
8167
8159
|
}
|
|
8168
|
-
function
|
|
8169
|
-
const
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
const transcriptReader = createTranscriptReader();
|
|
8173
|
-
const actors = new ActorRegistry();
|
|
8174
|
-
const rootPlan = createRootPlanTracker();
|
|
8175
|
-
const subagents = createSubagentTracker();
|
|
8176
|
-
function makeEvent(kind, level, actorId, data, runtimeEvent, cause) {
|
|
8177
|
-
const s = runLifecycle.allocateSeq();
|
|
8178
|
-
const runId = runLifecycle.getRunId();
|
|
8179
|
-
const eventId = `${runId}:E${s}`;
|
|
8180
|
-
const baseCause = {
|
|
8181
|
-
hook_request_id: runtimeEvent.id,
|
|
8182
|
-
transcript_path: runtimeEvent.context.transcriptPath,
|
|
8183
|
-
...cause
|
|
8184
|
-
};
|
|
8185
|
-
const fe = {
|
|
8186
|
-
event_id: eventId,
|
|
8187
|
-
seq: s,
|
|
8188
|
-
ts: runtimeEvent.timestamp,
|
|
8189
|
-
session_id: runtimeEvent.sessionId,
|
|
8190
|
-
run_id: runId,
|
|
8191
|
-
kind,
|
|
8192
|
-
level,
|
|
8193
|
-
actor_id: actorId,
|
|
8194
|
-
cause: baseCause,
|
|
8195
|
-
title: "",
|
|
8196
|
-
display: runtimeEvent.display,
|
|
8197
|
-
raw: runtimeEvent.payload,
|
|
8198
|
-
data
|
|
8199
|
-
};
|
|
8200
|
-
fe.title = composeTitle(fe, runtimeEvent);
|
|
8201
|
-
if (runtimeEvent.interaction.expectsDecision || kind === "permission.request" || kind === "stop.request") {
|
|
8202
|
-
decisionCorrelation.recordRequest(runtimeEvent.id, eventId, kind);
|
|
8160
|
+
function readObject(...values) {
|
|
8161
|
+
for (const value of values) {
|
|
8162
|
+
if (typeof value === "object" && value !== null) {
|
|
8163
|
+
return value;
|
|
8203
8164
|
}
|
|
8204
|
-
return fe;
|
|
8205
8165
|
}
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
)
|
|
8210
|
-
|
|
8211
|
-
runLifecycle.restoreFrom(bootstrap);
|
|
8212
|
-
for (const e of bootstrap.feedEvents) {
|
|
8213
|
-
if (e.kind === "tool.pre" && e.actor_id === "agent:root" && e.data.tool_name === "TodoWrite") {
|
|
8214
|
-
rootPlan.set(
|
|
8215
|
-
extractTodoItems(e.data.tool_input)
|
|
8216
|
-
);
|
|
8217
|
-
}
|
|
8218
|
-
}
|
|
8166
|
+
return {};
|
|
8167
|
+
}
|
|
8168
|
+
function readSuggestionArray(...values) {
|
|
8169
|
+
for (const value of values) {
|
|
8170
|
+
if (Array.isArray(value)) return value;
|
|
8219
8171
|
}
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8172
|
+
return void 0;
|
|
8173
|
+
}
|
|
8174
|
+
|
|
8175
|
+
// src/core/feed/todo.ts
|
|
8176
|
+
function isSubagentTool(toolName) {
|
|
8177
|
+
return toolName === "Task" || toolName === "Agent";
|
|
8178
|
+
}
|
|
8179
|
+
|
|
8180
|
+
// src/core/feed/internals/toolProjection.ts
|
|
8181
|
+
function extractTodoItems(toolInput) {
|
|
8182
|
+
const input = toolInput;
|
|
8183
|
+
return Array.isArray(input?.todos) ? input.todos : [];
|
|
8184
|
+
}
|
|
8185
|
+
function resolveToolUseId(event, record) {
|
|
8186
|
+
return event.toolUseId ?? record["tool_use_id"];
|
|
8187
|
+
}
|
|
8188
|
+
function toolUseCause(toolUseId, parentId) {
|
|
8189
|
+
return {
|
|
8190
|
+
...toolUseId ? { tool_use_id: toolUseId } : {},
|
|
8191
|
+
...parentId ? { parent_event_id: parentId } : {}
|
|
8192
|
+
};
|
|
8193
|
+
}
|
|
8194
|
+
function createToolProjection(args) {
|
|
8195
|
+
const {
|
|
8196
|
+
ensureRunArray,
|
|
8197
|
+
makeEvent,
|
|
8198
|
+
runLifecycle,
|
|
8199
|
+
toolCorrelation,
|
|
8200
|
+
rootPlan,
|
|
8201
|
+
subagents,
|
|
8202
|
+
resolveToolActor
|
|
8203
|
+
} = args;
|
|
8204
|
+
function webSearchStarted(event, data, toolUseId, parentEventId) {
|
|
8205
|
+
const toolInput = readObject(data["tool_input"]);
|
|
8206
|
+
const query = readString(toolInput["query"]);
|
|
8223
8207
|
return makeEvent(
|
|
8224
|
-
"
|
|
8208
|
+
"web.search",
|
|
8225
8209
|
"info",
|
|
8226
8210
|
"system",
|
|
8227
|
-
{
|
|
8228
|
-
|
|
8211
|
+
{
|
|
8212
|
+
message: query ? `Searching web for "${query}".` : "Searching the web.",
|
|
8213
|
+
phase: "started",
|
|
8214
|
+
query,
|
|
8215
|
+
item_id: toolUseId
|
|
8216
|
+
},
|
|
8217
|
+
event,
|
|
8218
|
+
toolUseId ? { parent_event_id: parentEventId, tool_use_id: toolUseId } : { parent_event_id: parentEventId }
|
|
8229
8219
|
);
|
|
8230
8220
|
}
|
|
8231
|
-
function
|
|
8232
|
-
|
|
8233
|
-
const
|
|
8234
|
-
const
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8221
|
+
function webSearchCompleted(event, data, toolUseId, parentEventId) {
|
|
8222
|
+
const response = readObject(data["tool_response"]);
|
|
8223
|
+
const actionType = readString(response["type"]);
|
|
8224
|
+
const query = readString(readObject(data["tool_input"])["query"]);
|
|
8225
|
+
const url = readString(response["url"]);
|
|
8226
|
+
const pattern = readString(response["pattern"]);
|
|
8227
|
+
const queries = Array.isArray(response["queries"]) ? response["queries"] : void 0;
|
|
8228
|
+
const message = actionType === "openPage" ? url ? `Opened search result ${url}.` : "Opened search result." : actionType === "findInPage" ? pattern ? `Found "${pattern}" in ${url ?? "the page"}.` : `Searched within ${url ?? "the page"}.` : actionType === "search" ? queries && queries.length > 1 ? `Ran ${queries.length} search queries.` : query ? `Searched web for "${query}".` : "Finished web search." : query ? `Finished web search for "${query}".` : "Finished web search.";
|
|
8229
|
+
return makeEvent(
|
|
8230
|
+
"web.search",
|
|
8231
|
+
"info",
|
|
8232
|
+
"system",
|
|
8233
|
+
{
|
|
8234
|
+
message,
|
|
8235
|
+
phase: "completed",
|
|
8236
|
+
query,
|
|
8237
|
+
action_type: actionType,
|
|
8238
|
+
url,
|
|
8239
|
+
pattern,
|
|
8240
|
+
queries,
|
|
8241
|
+
item_id: toolUseId
|
|
8242
|
+
},
|
|
8243
|
+
event,
|
|
8244
|
+
toolUseId ? { parent_event_id: parentEventId, tool_use_id: toolUseId } : { parent_event_id: parentEventId }
|
|
8254
8245
|
);
|
|
8255
|
-
return results;
|
|
8256
|
-
}
|
|
8257
|
-
function resolveToolActor() {
|
|
8258
|
-
return subagents.peek() ?? "agent:root";
|
|
8259
|
-
}
|
|
8260
|
-
function resolveToolUseId(event, record) {
|
|
8261
|
-
return event.toolUseId ?? record["tool_use_id"];
|
|
8262
|
-
}
|
|
8263
|
-
function toolUseCause(toolUseId, parentId) {
|
|
8264
|
-
return {
|
|
8265
|
-
...toolUseId ? { tool_use_id: toolUseId } : {},
|
|
8266
|
-
...parentId ? { parent_event_id: parentId } : {}
|
|
8267
|
-
};
|
|
8268
8246
|
}
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8247
|
+
return {
|
|
8248
|
+
mapToolEvent(event, data) {
|
|
8249
|
+
const results = ensureRunArray(event);
|
|
8250
|
+
const toolUseId = resolveToolUseId(event, data);
|
|
8251
|
+
const toolName = event.toolName ?? readString(data["tool_name"]) ?? "Unknown";
|
|
8252
|
+
const toolInput = readObject(data["tool_input"]);
|
|
8253
|
+
if (event.kind === "tool.delta") {
|
|
8254
|
+
const parentId = toolCorrelation.lookupParent(toolUseId);
|
|
8255
|
+
const cumulative = toolCorrelation.appendDelta(
|
|
8256
|
+
toolUseId,
|
|
8257
|
+
readString(data["delta"]) ?? ""
|
|
8258
|
+
);
|
|
8259
|
+
results.push(
|
|
8260
|
+
makeEvent(
|
|
8261
|
+
"tool.delta",
|
|
8262
|
+
"info",
|
|
8263
|
+
resolveToolActor(),
|
|
8264
|
+
{
|
|
8265
|
+
tool_name: toolName,
|
|
8266
|
+
tool_input: toolInput,
|
|
8267
|
+
tool_use_id: toolUseId,
|
|
8268
|
+
delta: cumulative
|
|
8269
|
+
},
|
|
8270
|
+
event,
|
|
8271
|
+
toolUseCause(toolUseId, parentId)
|
|
8272
|
+
)
|
|
8273
|
+
);
|
|
8274
|
+
return results;
|
|
8280
8275
|
}
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8276
|
+
if (event.kind === "tool.pre") {
|
|
8277
|
+
runLifecycle.incrementCounter("tool_uses");
|
|
8278
|
+
const preEvent = makeEvent(
|
|
8279
|
+
"tool.pre",
|
|
8280
|
+
"info",
|
|
8281
|
+
resolveToolActor(),
|
|
8282
|
+
{
|
|
8283
|
+
tool_name: toolName,
|
|
8284
|
+
tool_input: toolInput,
|
|
8285
|
+
tool_use_id: toolUseId
|
|
8286
|
+
},
|
|
8287
|
+
event,
|
|
8288
|
+
toolUseId ? { tool_use_id: toolUseId } : void 0
|
|
8289
|
+
);
|
|
8290
|
+
if (toolUseId) toolCorrelation.recordPre(toolUseId, preEvent.event_id);
|
|
8291
|
+
results.push(preEvent);
|
|
8292
|
+
if (toolName === "WebSearch") {
|
|
8293
|
+
results.push(
|
|
8294
|
+
webSearchStarted(event, data, toolUseId, preEvent.event_id)
|
|
8295
|
+
);
|
|
8287
8296
|
}
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8297
|
+
if (toolName === "TodoWrite" && preEvent.actor_id === "agent:root") {
|
|
8298
|
+
rootPlan.set(extractTodoItems(toolInput));
|
|
8299
|
+
}
|
|
8300
|
+
if (isSubagentTool(toolName)) {
|
|
8301
|
+
if (typeof toolInput["description"] === "string") {
|
|
8302
|
+
subagents.recordPendingDescription(toolInput["description"]);
|
|
8303
|
+
} else {
|
|
8304
|
+
subagents.clearPendingDescription();
|
|
8305
|
+
}
|
|
8295
8306
|
}
|
|
8307
|
+
return results;
|
|
8296
8308
|
}
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
if (results.some((r) => r.kind === "agent.message")) return;
|
|
8304
|
-
const msg = readString(d["last_assistant_message"]);
|
|
8305
|
-
if (!msg) return;
|
|
8306
|
-
const parentEvt = results.find((r) => r.kind === parentKind);
|
|
8307
|
-
const ev = agentMessageStream.emit({
|
|
8308
|
-
runtimeEvent: event,
|
|
8309
|
-
actorId,
|
|
8310
|
-
scope,
|
|
8311
|
-
message: msg,
|
|
8312
|
-
source: "hook",
|
|
8313
|
-
cause: parentEvt ? { parent_event_id: parentEvt.event_id } : void 0
|
|
8314
|
-
});
|
|
8315
|
-
if (ev) results.push(ev);
|
|
8316
|
-
}
|
|
8317
|
-
const transcriptPath = event.context.transcriptPath;
|
|
8318
|
-
const isStopEvent = eventKind2 === "stop.request" || eventKind2 === "subagent.stop";
|
|
8319
|
-
if (transcriptPath && !isStopEvent) {
|
|
8320
|
-
results.push(
|
|
8321
|
-
...agentMessageStream.emitTranscriptMessages(
|
|
8322
|
-
transcriptPath,
|
|
8323
|
-
event,
|
|
8309
|
+
if (event.kind === "tool.post") {
|
|
8310
|
+
if (toolUseId) toolCorrelation.forgetTool(toolUseId);
|
|
8311
|
+
const parentId = toolCorrelation.lookupParent(toolUseId);
|
|
8312
|
+
const postEvent = makeEvent(
|
|
8313
|
+
"tool.post",
|
|
8314
|
+
"info",
|
|
8324
8315
|
resolveToolActor(),
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
source,
|
|
8337
|
-
agent_type: readString(d["agent_type"])
|
|
8338
|
-
});
|
|
8339
|
-
if (source === "resume" || source === "clear" || source === "compact") {
|
|
8316
|
+
{
|
|
8317
|
+
tool_name: toolName,
|
|
8318
|
+
tool_input: toolInput,
|
|
8319
|
+
tool_use_id: toolUseId,
|
|
8320
|
+
tool_response: data.tool_response
|
|
8321
|
+
},
|
|
8322
|
+
event,
|
|
8323
|
+
toolUseCause(toolUseId, parentId)
|
|
8324
|
+
);
|
|
8325
|
+
results.push(postEvent);
|
|
8326
|
+
if (toolName === "WebSearch") {
|
|
8340
8327
|
results.push(
|
|
8341
|
-
|
|
8328
|
+
webSearchCompleted(event, data, toolUseId, postEvent.event_id)
|
|
8342
8329
|
);
|
|
8343
8330
|
}
|
|
8331
|
+
return results;
|
|
8332
|
+
}
|
|
8333
|
+
if (event.kind === "tool.failure") {
|
|
8334
|
+
runLifecycle.incrementCounter("tool_failures");
|
|
8335
|
+
if (toolUseId) toolCorrelation.forgetTool(toolUseId);
|
|
8336
|
+
const parentId = toolCorrelation.lookupParent(toolUseId);
|
|
8344
8337
|
results.push(
|
|
8345
8338
|
makeEvent(
|
|
8346
|
-
"
|
|
8347
|
-
"
|
|
8348
|
-
|
|
8339
|
+
"tool.failure",
|
|
8340
|
+
"error",
|
|
8341
|
+
resolveToolActor(),
|
|
8349
8342
|
{
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8343
|
+
tool_name: toolName,
|
|
8344
|
+
tool_input: toolInput,
|
|
8345
|
+
tool_use_id: toolUseId,
|
|
8346
|
+
error: readString(data["error"]) ?? "Unknown error",
|
|
8347
|
+
is_interrupt: readBoolean(data["is_interrupt"])
|
|
8353
8348
|
},
|
|
8354
|
-
event
|
|
8349
|
+
event,
|
|
8350
|
+
toolUseCause(toolUseId, parentId)
|
|
8355
8351
|
)
|
|
8356
8352
|
);
|
|
8357
|
-
break;
|
|
8358
8353
|
}
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
)
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8354
|
+
return results;
|
|
8355
|
+
}
|
|
8356
|
+
};
|
|
8357
|
+
}
|
|
8358
|
+
|
|
8359
|
+
// src/core/feed/internals/notificationProjection.ts
|
|
8360
|
+
function createNotificationProjection(args) {
|
|
8361
|
+
const { ensureRunArray, makeEvent, decisionCorrelation } = args;
|
|
8362
|
+
const reviewRoute = (data, runtimeEvent, ctx) => {
|
|
8363
|
+
const item = readObject(data["item"]);
|
|
8364
|
+
return [
|
|
8365
|
+
makeEvent(
|
|
8366
|
+
"review.status",
|
|
8367
|
+
"info",
|
|
8368
|
+
"system",
|
|
8369
|
+
{
|
|
8370
|
+
message: ctx.message,
|
|
8371
|
+
phase: ctx.notificationType.endsWith(".completed") ? "completed" : "started",
|
|
8372
|
+
review: readString(item["review"]),
|
|
8373
|
+
item_id: readString(data["item_id"])
|
|
8374
|
+
},
|
|
8375
|
+
runtimeEvent
|
|
8376
|
+
)
|
|
8377
|
+
];
|
|
8378
|
+
};
|
|
8379
|
+
const imageViewRoute = (data, runtimeEvent, ctx) => {
|
|
8380
|
+
const item = readObject(data["item"]);
|
|
8381
|
+
return [
|
|
8382
|
+
makeEvent(
|
|
8383
|
+
"image.view",
|
|
8384
|
+
"info",
|
|
8385
|
+
"system",
|
|
8386
|
+
{
|
|
8387
|
+
message: ctx.message,
|
|
8388
|
+
path: readString(item["path"]),
|
|
8389
|
+
item_id: readString(data["item_id"])
|
|
8390
|
+
},
|
|
8391
|
+
runtimeEvent
|
|
8392
|
+
)
|
|
8393
|
+
];
|
|
8394
|
+
};
|
|
8395
|
+
const contextCompactionRoute = (data, runtimeEvent, ctx) => [
|
|
8396
|
+
makeEvent(
|
|
8397
|
+
"context.compaction",
|
|
8398
|
+
"info",
|
|
8399
|
+
"system",
|
|
8400
|
+
{
|
|
8401
|
+
message: ctx.message,
|
|
8402
|
+
phase: ctx.notificationType.endsWith(".completed") ? "completed" : "started",
|
|
8403
|
+
item_id: readString(data["item_id"])
|
|
8404
|
+
},
|
|
8405
|
+
runtimeEvent
|
|
8406
|
+
)
|
|
8407
|
+
];
|
|
8408
|
+
const routes = {
|
|
8409
|
+
"codex.error": (data, runtimeEvent, ctx) => [
|
|
8410
|
+
makeEvent(
|
|
8411
|
+
"runtime.error",
|
|
8412
|
+
"error",
|
|
8413
|
+
"system",
|
|
8414
|
+
{
|
|
8415
|
+
message: ctx.message,
|
|
8416
|
+
title: ctx.title,
|
|
8417
|
+
thread_id: readString(data["thread_id"]),
|
|
8418
|
+
turn_id: readString(data["turn_id"]),
|
|
8419
|
+
error_code: readString(data["error_code"]),
|
|
8420
|
+
will_retry: readBoolean(data["will_retry"])
|
|
8421
|
+
},
|
|
8422
|
+
runtimeEvent
|
|
8423
|
+
)
|
|
8424
|
+
],
|
|
8425
|
+
"thread.status_changed": (data, runtimeEvent, ctx) => [
|
|
8426
|
+
makeEvent(
|
|
8427
|
+
"thread.status",
|
|
8428
|
+
"info",
|
|
8429
|
+
"system",
|
|
8430
|
+
{
|
|
8431
|
+
message: ctx.message,
|
|
8432
|
+
thread_id: readString(data["thread_id"]),
|
|
8433
|
+
status_type: readString(data["status_type"]),
|
|
8434
|
+
active_flags: Array.isArray(data["active_flags"]) ? data["active_flags"] : void 0
|
|
8435
|
+
},
|
|
8436
|
+
runtimeEvent
|
|
8437
|
+
)
|
|
8438
|
+
],
|
|
8439
|
+
"turn.diff_updated": (data, runtimeEvent, ctx) => [
|
|
8440
|
+
makeEvent(
|
|
8441
|
+
"turn.diff",
|
|
8442
|
+
"info",
|
|
8443
|
+
"system",
|
|
8444
|
+
{
|
|
8445
|
+
message: ctx.message,
|
|
8446
|
+
thread_id: readString(data["thread_id"]),
|
|
8447
|
+
turn_id: readString(data["turn_id"]),
|
|
8448
|
+
diff: readString(data["diff"]) ?? ""
|
|
8449
|
+
},
|
|
8450
|
+
runtimeEvent
|
|
8451
|
+
)
|
|
8452
|
+
],
|
|
8453
|
+
"server_request.resolved": (data, runtimeEvent, ctx) => {
|
|
8454
|
+
const requestId = data["request_id"] !== void 0 ? String(data["request_id"]) : void 0;
|
|
8455
|
+
const resolved = requestId ? decisionCorrelation.lookupResolved(requestId) : null;
|
|
8456
|
+
return [
|
|
8457
|
+
makeEvent(
|
|
8458
|
+
"server.request.resolved",
|
|
8459
|
+
"info",
|
|
8460
|
+
"system",
|
|
8461
|
+
{
|
|
8462
|
+
message: ctx.message,
|
|
8463
|
+
request_id: requestId,
|
|
8464
|
+
resolved_kind: resolved?.kind
|
|
8465
|
+
},
|
|
8466
|
+
runtimeEvent,
|
|
8467
|
+
resolved ? { parent_event_id: resolved.event_id } : void 0
|
|
8468
|
+
)
|
|
8469
|
+
];
|
|
8470
|
+
},
|
|
8471
|
+
"item.enteredReviewMode.started": reviewRoute,
|
|
8472
|
+
"item.enteredReviewMode.completed": reviewRoute,
|
|
8473
|
+
"item.exitedReviewMode.started": reviewRoute,
|
|
8474
|
+
"item.exitedReviewMode.completed": reviewRoute,
|
|
8475
|
+
"item.imageView.started": imageViewRoute,
|
|
8476
|
+
"item.imageView.completed": imageViewRoute,
|
|
8477
|
+
"item.contextCompaction.started": contextCompactionRoute,
|
|
8478
|
+
"item.contextCompaction.completed": contextCompactionRoute,
|
|
8479
|
+
"mcp_tool_call.progress": (_data, runtimeEvent, ctx) => [
|
|
8480
|
+
makeEvent(
|
|
8481
|
+
"mcp.progress",
|
|
8482
|
+
"info",
|
|
8483
|
+
"system",
|
|
8484
|
+
{
|
|
8485
|
+
message: ctx.message,
|
|
8486
|
+
title: ctx.title
|
|
8487
|
+
},
|
|
8488
|
+
runtimeEvent
|
|
8489
|
+
)
|
|
8490
|
+
],
|
|
8491
|
+
"command_execution.terminal_interaction": (_data, runtimeEvent, ctx) => [
|
|
8492
|
+
makeEvent(
|
|
8493
|
+
"terminal.input",
|
|
8494
|
+
"info",
|
|
8495
|
+
"system",
|
|
8496
|
+
{
|
|
8497
|
+
message: ctx.message,
|
|
8498
|
+
input_preview: ctx.message
|
|
8499
|
+
},
|
|
8500
|
+
runtimeEvent
|
|
8501
|
+
)
|
|
8502
|
+
],
|
|
8503
|
+
"skills.changed": (_data, runtimeEvent, ctx) => [
|
|
8504
|
+
makeEvent(
|
|
8505
|
+
"skills.changed",
|
|
8506
|
+
"info",
|
|
8507
|
+
"system",
|
|
8508
|
+
{
|
|
8509
|
+
message: ctx.message
|
|
8510
|
+
},
|
|
8511
|
+
runtimeEvent
|
|
8512
|
+
)
|
|
8513
|
+
],
|
|
8514
|
+
"skills.loaded": (_data, runtimeEvent, ctx) => {
|
|
8515
|
+
const payload = typeof runtimeEvent.payload === "object" && runtimeEvent.payload !== null ? runtimeEvent.payload : null;
|
|
8516
|
+
return [
|
|
8517
|
+
makeEvent(
|
|
8518
|
+
"skills.loaded",
|
|
8519
|
+
"info",
|
|
8520
|
+
"system",
|
|
8521
|
+
{
|
|
8522
|
+
message: ctx.message,
|
|
8523
|
+
count: typeof payload?.["count"] === "number" ? payload["count"] : void 0,
|
|
8524
|
+
error_count: typeof payload?.["error_count"] === "number" ? payload["error_count"] : void 0
|
|
8525
|
+
},
|
|
8526
|
+
runtimeEvent
|
|
8527
|
+
)
|
|
8528
|
+
];
|
|
8529
|
+
}
|
|
8530
|
+
};
|
|
8531
|
+
return {
|
|
8532
|
+
mapNotification(event, data) {
|
|
8533
|
+
const results = ensureRunArray(event);
|
|
8534
|
+
const notificationType = readString(data["notification_type"]);
|
|
8535
|
+
const message = readString(data["message"]) ?? "";
|
|
8536
|
+
const title = readString(data["title"]);
|
|
8537
|
+
const route = notificationType ? routes[notificationType] : void 0;
|
|
8538
|
+
if (route && notificationType) {
|
|
8400
8539
|
results.push(
|
|
8401
|
-
...
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
)
|
|
8406
|
-
);
|
|
8407
|
-
if (prompt) {
|
|
8408
|
-
results.push(
|
|
8409
|
-
makeEvent(
|
|
8410
|
-
"user.prompt",
|
|
8411
|
-
"info",
|
|
8412
|
-
"user",
|
|
8413
|
-
{
|
|
8414
|
-
prompt,
|
|
8415
|
-
cwd: event.context.cwd,
|
|
8416
|
-
permission_mode: event.context.permissionMode
|
|
8417
|
-
},
|
|
8418
|
-
event
|
|
8419
|
-
)
|
|
8420
|
-
);
|
|
8421
|
-
}
|
|
8422
|
-
break;
|
|
8423
|
-
}
|
|
8424
|
-
case "message.delta": {
|
|
8425
|
-
agentMessageStream.appendPendingDelta(
|
|
8426
|
-
readString(d["item_id"]),
|
|
8427
|
-
readString(d["delta"]) ?? "",
|
|
8428
|
-
resolveToolActor(),
|
|
8429
|
-
currentScope()
|
|
8540
|
+
...route(data, event, {
|
|
8541
|
+
notificationType,
|
|
8542
|
+
message,
|
|
8543
|
+
title
|
|
8544
|
+
})
|
|
8430
8545
|
);
|
|
8431
|
-
|
|
8432
|
-
}
|
|
8433
|
-
case "message.complete": {
|
|
8434
|
-
results.push(...ensureRunArray(event));
|
|
8435
|
-
const ev = agentMessageStream.emitCompleted({
|
|
8436
|
-
itemId: readString(d["item_id"]),
|
|
8437
|
-
messageText: readString(d["message"]),
|
|
8438
|
-
fallbackActorId: resolveToolActor(),
|
|
8439
|
-
fallbackScope: currentScope(),
|
|
8440
|
-
runtimeEvent: event
|
|
8441
|
-
});
|
|
8442
|
-
if (ev) results.push(ev);
|
|
8443
|
-
break;
|
|
8546
|
+
return results;
|
|
8444
8547
|
}
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
break;
|
|
8449
|
-
}
|
|
8450
|
-
const stopEvt = makeEvent(
|
|
8451
|
-
"stop.request",
|
|
8548
|
+
results.push(
|
|
8549
|
+
makeEvent(
|
|
8550
|
+
"notification",
|
|
8452
8551
|
"info",
|
|
8453
|
-
"
|
|
8552
|
+
"system",
|
|
8454
8553
|
{
|
|
8455
|
-
|
|
8554
|
+
message,
|
|
8555
|
+
title,
|
|
8556
|
+
notification_type: notificationType
|
|
8456
8557
|
},
|
|
8457
8558
|
event
|
|
8458
|
-
)
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
results.push(
|
|
8498
|
-
makeEvent(
|
|
8499
|
-
"plan.update",
|
|
8500
|
-
"info",
|
|
8501
|
-
"system",
|
|
8502
|
-
{
|
|
8503
|
-
explanation: readString(d["explanation"]) ?? null,
|
|
8504
|
-
delta: readString(d["delta"]),
|
|
8505
|
-
item_id: readString(d["item_id"]),
|
|
8506
|
-
thread_id: readString(d["thread_id"]),
|
|
8507
|
-
turn_id: readString(d["turn_id"]),
|
|
8508
|
-
plan: Array.isArray(planSteps) ? planSteps : void 0
|
|
8509
|
-
},
|
|
8510
|
-
event
|
|
8511
|
-
)
|
|
8512
|
-
);
|
|
8513
|
-
break;
|
|
8514
|
-
}
|
|
8515
|
-
case "reasoning.delta":
|
|
8516
|
-
if (readString(d["phase"]) === "summary" && readString(d["delta"])) {
|
|
8517
|
-
const summaryIndex = (() => {
|
|
8518
|
-
const value = d["summary_index"] ?? d["content_index"];
|
|
8519
|
-
return typeof value === "number" ? value : void 0;
|
|
8520
|
-
})();
|
|
8521
|
-
results.push(
|
|
8522
|
-
makeEvent(
|
|
8523
|
-
"reasoning.summary",
|
|
8524
|
-
"info",
|
|
8525
|
-
"agent:root",
|
|
8526
|
-
{
|
|
8527
|
-
message: agentMessageStream.appendReasoningSummary(
|
|
8528
|
-
readString(d["item_id"]),
|
|
8529
|
-
summaryIndex,
|
|
8530
|
-
readString(d["delta"]) ?? ""
|
|
8531
|
-
),
|
|
8532
|
-
item_id: readString(d["item_id"]),
|
|
8533
|
-
content_index: typeof d["content_index"] === "number" ? d["content_index"] : void 0,
|
|
8534
|
-
summary_index: typeof d["summary_index"] === "number" ? d["summary_index"] : summaryIndex,
|
|
8535
|
-
thread_id: readString(d["thread_id"]),
|
|
8536
|
-
turn_id: readString(d["turn_id"])
|
|
8537
|
-
},
|
|
8538
|
-
event
|
|
8539
|
-
)
|
|
8540
|
-
);
|
|
8541
|
-
}
|
|
8542
|
-
break;
|
|
8543
|
-
case "usage.update": {
|
|
8559
|
+
)
|
|
8560
|
+
);
|
|
8561
|
+
return results;
|
|
8562
|
+
}
|
|
8563
|
+
};
|
|
8564
|
+
}
|
|
8565
|
+
|
|
8566
|
+
// src/core/feed/internals/decisionProjection.ts
|
|
8567
|
+
function createDecisionProjection(args) {
|
|
8568
|
+
const { ensureRunArray, makeEvent, runLifecycle, decisionCorrelation } = args;
|
|
8569
|
+
function makeDecisionEvent(requestId, parentEventId, decision, kind, data) {
|
|
8570
|
+
const s = runLifecycle.allocateSeq();
|
|
8571
|
+
const runId = runLifecycle.getRunId();
|
|
8572
|
+
const session = runLifecycle.getSession();
|
|
8573
|
+
const fe = {
|
|
8574
|
+
event_id: `${runId}:E${s}`,
|
|
8575
|
+
seq: s,
|
|
8576
|
+
ts: Date.now(),
|
|
8577
|
+
session_id: session?.session_id ?? "unknown",
|
|
8578
|
+
run_id: runId,
|
|
8579
|
+
kind,
|
|
8580
|
+
level: "info",
|
|
8581
|
+
actor_id: decision.source === "user" ? "user" : "system",
|
|
8582
|
+
cause: {
|
|
8583
|
+
parent_event_id: parentEventId,
|
|
8584
|
+
hook_request_id: requestId
|
|
8585
|
+
},
|
|
8586
|
+
title: "",
|
|
8587
|
+
data
|
|
8588
|
+
};
|
|
8589
|
+
fe.title = generateTitle(fe);
|
|
8590
|
+
return fe;
|
|
8591
|
+
}
|
|
8592
|
+
return {
|
|
8593
|
+
mapRequestEvent(event, data) {
|
|
8594
|
+
const results = ensureRunArray(event);
|
|
8595
|
+
if (event.kind === "permission.request") {
|
|
8596
|
+
runLifecycle.incrementCounter("permission_requests");
|
|
8597
|
+
const networkContext = readObject(data["network_context"]);
|
|
8544
8598
|
results.push(
|
|
8545
8599
|
makeEvent(
|
|
8546
|
-
"
|
|
8600
|
+
"permission.request",
|
|
8547
8601
|
"info",
|
|
8548
8602
|
"system",
|
|
8549
8603
|
{
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
const chunk = readString(d["delta"]) ?? "";
|
|
8566
|
-
const cumulative = toolCorrelation.appendDelta(toolUseId, chunk);
|
|
8567
|
-
results.push(
|
|
8568
|
-
makeEvent(
|
|
8569
|
-
"tool.delta",
|
|
8570
|
-
"info",
|
|
8571
|
-
resolveToolActor(),
|
|
8572
|
-
{
|
|
8573
|
-
tool_name: toolName,
|
|
8574
|
-
tool_input: readObject(d["tool_input"]),
|
|
8575
|
-
tool_use_id: toolUseId,
|
|
8576
|
-
delta: cumulative
|
|
8577
|
-
},
|
|
8578
|
-
event,
|
|
8579
|
-
toolUseCause(toolUseId, parentId)
|
|
8580
|
-
)
|
|
8581
|
-
);
|
|
8582
|
-
break;
|
|
8583
|
-
}
|
|
8584
|
-
case "tool.pre": {
|
|
8585
|
-
results.push(...ensureRunArray(event));
|
|
8586
|
-
runLifecycle.incrementCounter("tool_uses");
|
|
8587
|
-
const toolUseId = resolveToolUseId(event, d);
|
|
8588
|
-
const toolName = event.toolName ?? readString(d["tool_name"]) ?? "Unknown";
|
|
8589
|
-
const fe = makeEvent(
|
|
8590
|
-
"tool.pre",
|
|
8591
|
-
"info",
|
|
8592
|
-
resolveToolActor(),
|
|
8593
|
-
{
|
|
8594
|
-
tool_name: toolName,
|
|
8595
|
-
tool_input: readObject(d["tool_input"]),
|
|
8596
|
-
tool_use_id: toolUseId
|
|
8597
|
-
},
|
|
8598
|
-
event,
|
|
8599
|
-
toolUseId ? { tool_use_id: toolUseId } : void 0
|
|
8600
|
-
);
|
|
8601
|
-
if (toolUseId) {
|
|
8602
|
-
toolCorrelation.recordPre(toolUseId, fe.event_id);
|
|
8603
|
-
}
|
|
8604
|
-
results.push(fe);
|
|
8605
|
-
if (toolName === "WebSearch") {
|
|
8606
|
-
results.push(
|
|
8607
|
-
makeEvent(
|
|
8608
|
-
"web.search",
|
|
8609
|
-
"info",
|
|
8610
|
-
"system",
|
|
8611
|
-
{
|
|
8612
|
-
message: (() => {
|
|
8613
|
-
const query = readString(
|
|
8614
|
-
readObject(d["tool_input"])["query"]
|
|
8615
|
-
);
|
|
8616
|
-
return query ? `Searching web for "${query}".` : "Searching the web.";
|
|
8617
|
-
})(),
|
|
8618
|
-
phase: "started",
|
|
8619
|
-
query: readString(readObject(d["tool_input"])["query"]),
|
|
8620
|
-
item_id: toolUseId
|
|
8621
|
-
},
|
|
8622
|
-
event,
|
|
8623
|
-
toolUseId ? { parent_event_id: fe.event_id, tool_use_id: toolUseId } : { parent_event_id: fe.event_id }
|
|
8624
|
-
)
|
|
8625
|
-
);
|
|
8626
|
-
}
|
|
8627
|
-
if (toolName === "TodoWrite" && fe.actor_id === "agent:root") {
|
|
8628
|
-
rootPlan.set(extractTodoItems(readObject(d["tool_input"])));
|
|
8629
|
-
}
|
|
8630
|
-
if (isSubagentTool(toolName)) {
|
|
8631
|
-
const input = readObject(d["tool_input"]);
|
|
8632
|
-
if (typeof input["description"] === "string") {
|
|
8633
|
-
subagents.recordPendingDescription(input["description"]);
|
|
8634
|
-
} else {
|
|
8635
|
-
subagents.clearPendingDescription();
|
|
8636
|
-
}
|
|
8637
|
-
}
|
|
8638
|
-
break;
|
|
8604
|
+
tool_name: event.toolName ?? readString(data["tool_name"]) ?? "Unknown",
|
|
8605
|
+
tool_input: readObject(data["tool_input"]),
|
|
8606
|
+
tool_use_id: resolveToolUseId(event, data),
|
|
8607
|
+
permission_suggestions: readSuggestionArray(
|
|
8608
|
+
data["permission_suggestions"]
|
|
8609
|
+
),
|
|
8610
|
+
network_context: Object.keys(networkContext).length > 0 ? {
|
|
8611
|
+
host: readString(networkContext["host"]),
|
|
8612
|
+
protocol: readString(networkContext["protocol"])
|
|
8613
|
+
} : void 0
|
|
8614
|
+
},
|
|
8615
|
+
event
|
|
8616
|
+
)
|
|
8617
|
+
);
|
|
8618
|
+
return results;
|
|
8639
8619
|
}
|
|
8640
|
-
|
|
8641
|
-
results.push(
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
tool_response: d.tool_response
|
|
8655
|
-
},
|
|
8656
|
-
event,
|
|
8657
|
-
toolUseCause(toolUseId, parentId)
|
|
8620
|
+
if (event.kind === "stop.request") {
|
|
8621
|
+
results.push(
|
|
8622
|
+
makeEvent(
|
|
8623
|
+
"stop.request",
|
|
8624
|
+
"info",
|
|
8625
|
+
"agent:root",
|
|
8626
|
+
{
|
|
8627
|
+
stop_hook_active: readBoolean(data["stop_hook_active"]) ?? false,
|
|
8628
|
+
last_assistant_message: readString(
|
|
8629
|
+
data["last_assistant_message"]
|
|
8630
|
+
)
|
|
8631
|
+
},
|
|
8632
|
+
event
|
|
8633
|
+
)
|
|
8658
8634
|
);
|
|
8659
|
-
results
|
|
8660
|
-
if (toolName === "WebSearch") {
|
|
8661
|
-
const response = readObject(d["tool_response"]);
|
|
8662
|
-
const actionType = readString(response["type"]);
|
|
8663
|
-
const query = readString(readObject(d["tool_input"])["query"]);
|
|
8664
|
-
const url = readString(response["url"]);
|
|
8665
|
-
const pattern = readString(response["pattern"]);
|
|
8666
|
-
const queries = Array.isArray(response["queries"]) ? response["queries"] : void 0;
|
|
8667
|
-
const message = actionType === "openPage" ? url ? `Opened search result ${url}.` : "Opened search result." : actionType === "findInPage" ? pattern ? `Found "${pattern}" in ${url ?? "the page"}.` : `Searched within ${url ?? "the page"}.` : actionType === "search" ? queries && queries.length > 1 ? `Ran ${queries.length} search queries.` : query ? `Searched web for "${query}".` : "Finished web search." : query ? `Finished web search for "${query}".` : "Finished web search.";
|
|
8668
|
-
results.push(
|
|
8669
|
-
makeEvent(
|
|
8670
|
-
"web.search",
|
|
8671
|
-
"info",
|
|
8672
|
-
"system",
|
|
8673
|
-
{
|
|
8674
|
-
message,
|
|
8675
|
-
phase: "completed",
|
|
8676
|
-
query,
|
|
8677
|
-
action_type: actionType,
|
|
8678
|
-
url,
|
|
8679
|
-
pattern,
|
|
8680
|
-
queries,
|
|
8681
|
-
item_id: toolUseId
|
|
8682
|
-
},
|
|
8683
|
-
event,
|
|
8684
|
-
toolUseId ? { parent_event_id: postEvent.event_id, tool_use_id: toolUseId } : { parent_event_id: postEvent.event_id }
|
|
8685
|
-
)
|
|
8686
|
-
);
|
|
8687
|
-
}
|
|
8688
|
-
break;
|
|
8635
|
+
return results;
|
|
8689
8636
|
}
|
|
8690
|
-
|
|
8691
|
-
results.push(...ensureRunArray(event));
|
|
8692
|
-
runLifecycle.incrementCounter("tool_failures");
|
|
8693
|
-
const toolUseId = resolveToolUseId(event, d);
|
|
8694
|
-
if (toolUseId) toolCorrelation.forgetTool(toolUseId);
|
|
8695
|
-
const parentId = toolCorrelation.lookupParent(toolUseId);
|
|
8696
|
-
const toolName = event.toolName ?? readString(d["tool_name"]) ?? "Unknown";
|
|
8637
|
+
if (event.kind === "stop.failure") {
|
|
8697
8638
|
results.push(
|
|
8698
8639
|
makeEvent(
|
|
8699
|
-
"
|
|
8640
|
+
"stop.failure",
|
|
8700
8641
|
"error",
|
|
8701
|
-
|
|
8642
|
+
"system",
|
|
8702
8643
|
{
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
tool_use_id: toolUseId,
|
|
8706
|
-
error: readString(d["error"]) ?? "Unknown error",
|
|
8707
|
-
is_interrupt: readBoolean(d["is_interrupt"])
|
|
8644
|
+
error_type: readString(data["error_type"]) ?? "unknown",
|
|
8645
|
+
error_message: readString(data["error_message"])
|
|
8708
8646
|
},
|
|
8709
|
-
event
|
|
8710
|
-
toolUseCause(toolUseId, parentId)
|
|
8647
|
+
event
|
|
8711
8648
|
)
|
|
8712
8649
|
);
|
|
8713
|
-
|
|
8650
|
+
return results;
|
|
8714
8651
|
}
|
|
8715
|
-
|
|
8716
|
-
results.push(...ensureRunArray(event));
|
|
8717
|
-
runLifecycle.incrementCounter("permission_requests");
|
|
8718
|
-
const toolName = event.toolName ?? readString(d["tool_name"]) ?? "Unknown";
|
|
8652
|
+
if (event.kind === "permission.denied") {
|
|
8719
8653
|
results.push(
|
|
8720
8654
|
makeEvent(
|
|
8721
|
-
"permission.
|
|
8722
|
-
"
|
|
8655
|
+
"permission.denied",
|
|
8656
|
+
"warn",
|
|
8723
8657
|
"system",
|
|
8724
8658
|
{
|
|
8725
|
-
tool_name: toolName,
|
|
8726
|
-
tool_input: readObject(
|
|
8727
|
-
tool_use_id:
|
|
8728
|
-
|
|
8729
|
-
d["permission_suggestions"]
|
|
8730
|
-
),
|
|
8731
|
-
network_context: typeof d["network_context"] === "object" && d["network_context"] !== null ? {
|
|
8732
|
-
host: readString(
|
|
8733
|
-
d["network_context"]["host"]
|
|
8734
|
-
),
|
|
8735
|
-
protocol: readString(
|
|
8736
|
-
d["network_context"]["protocol"]
|
|
8737
|
-
)
|
|
8738
|
-
} : void 0
|
|
8659
|
+
tool_name: event.toolName ?? readString(data["tool_name"]) ?? "Unknown",
|
|
8660
|
+
tool_input: readObject(data["tool_input"]),
|
|
8661
|
+
tool_use_id: readString(data["tool_use_id"]),
|
|
8662
|
+
reason: readString(data["reason"])
|
|
8739
8663
|
},
|
|
8740
8664
|
event
|
|
8741
8665
|
)
|
|
8742
8666
|
);
|
|
8743
|
-
|
|
8667
|
+
return results;
|
|
8744
8668
|
}
|
|
8745
|
-
|
|
8746
|
-
results.push(
|
|
8747
|
-
|
|
8748
|
-
|
|
8669
|
+
if (event.kind === "elicitation.request") {
|
|
8670
|
+
results.push(
|
|
8671
|
+
makeEvent(
|
|
8672
|
+
"elicitation.request",
|
|
8673
|
+
"warn",
|
|
8674
|
+
"system",
|
|
8675
|
+
{
|
|
8676
|
+
mcp_server: readString(data["mcp_server"]) ?? "unknown",
|
|
8677
|
+
form: data["form"]
|
|
8678
|
+
},
|
|
8679
|
+
event
|
|
8680
|
+
)
|
|
8681
|
+
);
|
|
8682
|
+
return results;
|
|
8683
|
+
}
|
|
8684
|
+
if (event.kind === "elicitation.result") {
|
|
8685
|
+
const action = readString(data["action"]);
|
|
8686
|
+
const evt = makeEvent(
|
|
8687
|
+
"elicitation.result",
|
|
8749
8688
|
"info",
|
|
8750
|
-
"
|
|
8689
|
+
"system",
|
|
8751
8690
|
{
|
|
8752
|
-
|
|
8753
|
-
|
|
8691
|
+
mcp_server: readString(data["mcp_server"]) ?? "unknown",
|
|
8692
|
+
...action ? { action } : {},
|
|
8693
|
+
content: readObject(data["content"])
|
|
8754
8694
|
},
|
|
8755
8695
|
event
|
|
8756
8696
|
);
|
|
8757
|
-
|
|
8758
|
-
|
|
8697
|
+
evt.ui = { collapsed_default: true };
|
|
8698
|
+
results.push(evt);
|
|
8759
8699
|
}
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8700
|
+
return results;
|
|
8701
|
+
},
|
|
8702
|
+
mapDecision(requestId, decision) {
|
|
8703
|
+
const consumed = decisionCorrelation.consumeForDecision(requestId);
|
|
8704
|
+
if (!consumed) return null;
|
|
8705
|
+
const { parentEventId, originalKind } = consumed;
|
|
8706
|
+
if (originalKind === "permission.request") {
|
|
8707
|
+
let data;
|
|
8708
|
+
if (decision.source === "timeout") {
|
|
8709
|
+
data = { decision_type: "no_opinion", reason: "timeout" };
|
|
8710
|
+
} else if (decision.type === "passthrough") {
|
|
8711
|
+
data = { decision_type: "no_opinion", reason: decision.source };
|
|
8712
|
+
} else if (decision.intent?.kind === "permission_allow") {
|
|
8713
|
+
data = { decision_type: "allow" };
|
|
8714
|
+
} else if (decision.intent?.kind === "permission_deny") {
|
|
8715
|
+
data = {
|
|
8716
|
+
decision_type: "deny",
|
|
8717
|
+
message: decision.intent.reason
|
|
8718
|
+
};
|
|
8719
|
+
} else {
|
|
8720
|
+
data = { decision_type: "no_opinion", reason: "unknown" };
|
|
8721
|
+
}
|
|
8722
|
+
return makeDecisionEvent(
|
|
8723
|
+
requestId,
|
|
8724
|
+
parentEventId,
|
|
8725
|
+
decision,
|
|
8726
|
+
"permission.decision",
|
|
8727
|
+
data
|
|
8728
|
+
);
|
|
8729
|
+
}
|
|
8730
|
+
if (originalKind === "stop.request") {
|
|
8731
|
+
let data;
|
|
8732
|
+
const d = decision.data;
|
|
8733
|
+
const decisionReason = typeof d?.reason === "string" ? d.reason : void 0;
|
|
8734
|
+
if (decision.source === "timeout") {
|
|
8735
|
+
data = { decision_type: "no_opinion", reason: "timeout" };
|
|
8736
|
+
} else if (decision.type === "passthrough") {
|
|
8737
|
+
data = { decision_type: "no_opinion", reason: decision.source };
|
|
8738
|
+
} else if (d?.decision === "block") {
|
|
8739
|
+
data = {
|
|
8740
|
+
decision_type: "block",
|
|
8741
|
+
reason: decisionReason ?? decision.reason ?? "Blocked"
|
|
8742
|
+
};
|
|
8743
|
+
} else if (d?.ok === false) {
|
|
8744
|
+
data = {
|
|
8745
|
+
decision_type: "block",
|
|
8746
|
+
reason: decisionReason ?? "Blocked by hook"
|
|
8747
|
+
};
|
|
8748
|
+
} else {
|
|
8749
|
+
data = { decision_type: "allow" };
|
|
8750
|
+
}
|
|
8751
|
+
return makeDecisionEvent(
|
|
8752
|
+
requestId,
|
|
8753
|
+
parentEventId,
|
|
8754
|
+
decision,
|
|
8755
|
+
"stop.decision",
|
|
8756
|
+
data
|
|
8757
|
+
);
|
|
8758
|
+
}
|
|
8759
|
+
return null;
|
|
8760
|
+
}
|
|
8761
|
+
};
|
|
8762
|
+
}
|
|
8763
|
+
|
|
8764
|
+
// src/core/feed/internals/subagentProjection.ts
|
|
8765
|
+
function createSubagentProjection(args) {
|
|
8766
|
+
const { ensureRunArray, makeEvent, runLifecycle, actors, subagents } = args;
|
|
8767
|
+
return {
|
|
8768
|
+
mapSubagentEvent(event, data) {
|
|
8769
|
+
const results = ensureRunArray(event);
|
|
8770
|
+
const agentId = event.agentId ?? readString(data["agent_id"]);
|
|
8771
|
+
const agentType = event.agentType ?? readString(data["agent_type"]);
|
|
8772
|
+
if (event.kind === "subagent.start") {
|
|
8764
8773
|
if (agentId) {
|
|
8765
8774
|
actors.ensureSubagent(agentId, agentType ?? "unknown");
|
|
8766
8775
|
const currentRun = runLifecycle.getCurrentRun();
|
|
8767
8776
|
if (currentRun) currentRun.actors.subagent_ids.push(agentId);
|
|
8768
8777
|
subagents.pushActor(`subagent:${agentId}`);
|
|
8769
8778
|
}
|
|
8770
|
-
const description = subagents.consumePendingDescription() ?? readString(
|
|
8779
|
+
const description = subagents.consumePendingDescription() ?? readString(data["prompt"]);
|
|
8771
8780
|
results.push(
|
|
8772
8781
|
makeEvent(
|
|
8773
8782
|
"subagent.start",
|
|
@@ -8777,485 +8786,726 @@ function createFeedMapper(bootstrap) {
|
|
|
8777
8786
|
agent_id: agentId ?? "",
|
|
8778
8787
|
agent_type: agentType ?? "",
|
|
8779
8788
|
description: description ?? void 0,
|
|
8780
|
-
tool: readString(
|
|
8781
|
-
sender_thread_id: readString(
|
|
8782
|
-
receiver_thread_id: readString(
|
|
8783
|
-
new_thread_id: readString(
|
|
8784
|
-
agent_status: readString(
|
|
8789
|
+
tool: readString(data["tool"]),
|
|
8790
|
+
sender_thread_id: readString(data["sender_thread_id"]),
|
|
8791
|
+
receiver_thread_id: readString(data["receiver_thread_id"]),
|
|
8792
|
+
new_thread_id: readString(data["new_thread_id"]),
|
|
8793
|
+
agent_status: readString(data["agent_status"])
|
|
8785
8794
|
},
|
|
8786
8795
|
event
|
|
8787
8796
|
)
|
|
8788
8797
|
);
|
|
8789
|
-
if (agentId && description)
|
|
8798
|
+
if (agentId && description)
|
|
8790
8799
|
subagents.setDescription(agentId, description);
|
|
8791
|
-
|
|
8792
|
-
break;
|
|
8800
|
+
return results;
|
|
8793
8801
|
}
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
if (agentId) {
|
|
8798
|
-
subagents.popActor(`subagent:${agentId}`);
|
|
8799
|
-
}
|
|
8800
|
-
const subStopActorId = `subagent:${agentId ?? "unknown"}`;
|
|
8801
|
-
const subStopEvt = makeEvent(
|
|
8802
|
+
if (agentId) subagents.popActor(`subagent:${agentId}`);
|
|
8803
|
+
results.push(
|
|
8804
|
+
makeEvent(
|
|
8802
8805
|
"subagent.stop",
|
|
8803
8806
|
"info",
|
|
8804
|
-
|
|
8807
|
+
`subagent:${agentId ?? "unknown"}`,
|
|
8805
8808
|
{
|
|
8806
8809
|
agent_id: agentId ?? "",
|
|
8807
|
-
agent_type:
|
|
8808
|
-
stop_hook_active: readBoolean(
|
|
8809
|
-
agent_transcript_path: readString(
|
|
8810
|
-
last_assistant_message: readString(
|
|
8810
|
+
agent_type: agentType ?? "",
|
|
8811
|
+
stop_hook_active: readBoolean(data["stop_hook_active"]) ?? false,
|
|
8812
|
+
agent_transcript_path: readString(data["agent_transcript_path"]),
|
|
8813
|
+
last_assistant_message: readString(data["last_assistant_message"]),
|
|
8811
8814
|
description: subagents.description(agentId ?? ""),
|
|
8812
|
-
tool: readString(
|
|
8813
|
-
status: readString(
|
|
8814
|
-
sender_thread_id: readString(
|
|
8815
|
-
receiver_thread_id: readString(
|
|
8816
|
-
new_thread_id: readString(
|
|
8817
|
-
agent_status: readString(
|
|
8815
|
+
tool: readString(data["tool"]),
|
|
8816
|
+
status: readString(data["status"]),
|
|
8817
|
+
sender_thread_id: readString(data["sender_thread_id"]),
|
|
8818
|
+
receiver_thread_id: readString(data["receiver_thread_id"]),
|
|
8819
|
+
new_thread_id: readString(data["new_thread_id"]),
|
|
8820
|
+
agent_status: readString(data["agent_status"])
|
|
8818
8821
|
},
|
|
8819
8822
|
event
|
|
8820
|
-
)
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8823
|
+
)
|
|
8824
|
+
);
|
|
8825
|
+
return results;
|
|
8826
|
+
}
|
|
8827
|
+
};
|
|
8828
|
+
}
|
|
8829
|
+
|
|
8830
|
+
// src/core/feed/internals/fileConfigProjection.ts
|
|
8831
|
+
function createFileConfigProjection(args) {
|
|
8832
|
+
const { ensureRunArray, makeEvent } = args;
|
|
8833
|
+
function collapsed(event) {
|
|
8834
|
+
event.ui = { collapsed_default: true };
|
|
8835
|
+
return event;
|
|
8836
|
+
}
|
|
8837
|
+
return {
|
|
8838
|
+
mapFileConfigEvent(event, data) {
|
|
8839
|
+
const results = ensureRunArray(event);
|
|
8840
|
+
if (event.kind === "compact.pre") {
|
|
8841
|
+
results.push(
|
|
8842
|
+
collapsed(
|
|
8832
8843
|
makeEvent(
|
|
8833
|
-
"
|
|
8844
|
+
"compact.pre",
|
|
8834
8845
|
"info",
|
|
8835
8846
|
"system",
|
|
8836
8847
|
{
|
|
8837
|
-
|
|
8838
|
-
|
|
8839
|
-
review: readString(item["review"]),
|
|
8840
|
-
item_id: readString(data["item_id"])
|
|
8848
|
+
trigger: readString(data["trigger"]) ?? "auto",
|
|
8849
|
+
custom_instructions: readString(data["custom_instructions"])
|
|
8841
8850
|
},
|
|
8842
|
-
|
|
8851
|
+
event
|
|
8843
8852
|
)
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8853
|
+
)
|
|
8854
|
+
);
|
|
8855
|
+
return results;
|
|
8856
|
+
}
|
|
8857
|
+
if (event.kind === "setup") {
|
|
8858
|
+
results.push(
|
|
8859
|
+
collapsed(
|
|
8849
8860
|
makeEvent(
|
|
8850
|
-
"
|
|
8861
|
+
"setup",
|
|
8851
8862
|
"info",
|
|
8852
8863
|
"system",
|
|
8853
8864
|
{
|
|
8854
|
-
|
|
8855
|
-
path: readString(item["path"]),
|
|
8856
|
-
item_id: readString(data["item_id"])
|
|
8865
|
+
trigger: readString(data["trigger"]) ?? "init"
|
|
8857
8866
|
},
|
|
8858
|
-
|
|
8867
|
+
event
|
|
8859
8868
|
)
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8869
|
+
)
|
|
8870
|
+
);
|
|
8871
|
+
return results;
|
|
8872
|
+
}
|
|
8873
|
+
if (event.kind === "config.change") {
|
|
8874
|
+
results.push(
|
|
8863
8875
|
makeEvent(
|
|
8864
|
-
"
|
|
8876
|
+
"config.change",
|
|
8865
8877
|
"info",
|
|
8866
8878
|
"system",
|
|
8867
8879
|
{
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
item_id: readString(data["item_id"])
|
|
8880
|
+
source: readString(data["source"]) ?? "unknown",
|
|
8881
|
+
file_path: readString(data["file_path"])
|
|
8871
8882
|
},
|
|
8872
|
-
|
|
8883
|
+
event
|
|
8873
8884
|
)
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
"system",
|
|
8881
|
-
{
|
|
8882
|
-
message: ctx.message,
|
|
8883
|
-
title: ctx.title,
|
|
8884
|
-
thread_id: readString(data["thread_id"]),
|
|
8885
|
-
turn_id: readString(data["turn_id"]),
|
|
8886
|
-
error_code: readString(data["error_code"]),
|
|
8887
|
-
will_retry: readBoolean(data["will_retry"])
|
|
8888
|
-
},
|
|
8889
|
-
runtimeEvent
|
|
8890
|
-
)
|
|
8891
|
-
],
|
|
8892
|
-
"thread.status_changed": (data, runtimeEvent, ctx) => [
|
|
8893
|
-
makeEvent(
|
|
8894
|
-
"thread.status",
|
|
8895
|
-
"info",
|
|
8896
|
-
"system",
|
|
8897
|
-
{
|
|
8898
|
-
message: ctx.message,
|
|
8899
|
-
thread_id: readString(data["thread_id"]),
|
|
8900
|
-
status_type: readString(data["status_type"]),
|
|
8901
|
-
active_flags: Array.isArray(data["active_flags"]) ? data["active_flags"] : void 0
|
|
8902
|
-
},
|
|
8903
|
-
runtimeEvent
|
|
8904
|
-
)
|
|
8905
|
-
],
|
|
8906
|
-
"turn.diff_updated": (data, runtimeEvent, ctx) => [
|
|
8907
|
-
makeEvent(
|
|
8908
|
-
"turn.diff",
|
|
8909
|
-
"info",
|
|
8910
|
-
"system",
|
|
8911
|
-
{
|
|
8912
|
-
message: ctx.message,
|
|
8913
|
-
thread_id: readString(data["thread_id"]),
|
|
8914
|
-
turn_id: readString(data["turn_id"]),
|
|
8915
|
-
diff: readString(data["diff"]) ?? ""
|
|
8916
|
-
},
|
|
8917
|
-
runtimeEvent
|
|
8918
|
-
)
|
|
8919
|
-
],
|
|
8920
|
-
"server_request.resolved": (data, runtimeEvent, ctx) => {
|
|
8921
|
-
const requestId = data["request_id"] !== void 0 ? String(data["request_id"]) : void 0;
|
|
8922
|
-
const resolved = requestId ? decisionCorrelation.lookupResolved(requestId) : null;
|
|
8923
|
-
return [
|
|
8924
|
-
makeEvent(
|
|
8925
|
-
"server.request.resolved",
|
|
8926
|
-
"info",
|
|
8927
|
-
"system",
|
|
8928
|
-
{
|
|
8929
|
-
message: ctx.message,
|
|
8930
|
-
request_id: requestId,
|
|
8931
|
-
resolved_kind: resolved?.kind
|
|
8932
|
-
},
|
|
8933
|
-
runtimeEvent,
|
|
8934
|
-
resolved ? { parent_event_id: resolved.event_id } : void 0
|
|
8935
|
-
)
|
|
8936
|
-
];
|
|
8937
|
-
},
|
|
8938
|
-
"item.enteredReviewMode.started": reviewRoute,
|
|
8939
|
-
"item.enteredReviewMode.completed": reviewRoute,
|
|
8940
|
-
"item.exitedReviewMode.started": reviewRoute,
|
|
8941
|
-
"item.exitedReviewMode.completed": reviewRoute,
|
|
8942
|
-
"item.imageView.started": imageViewRoute,
|
|
8943
|
-
"item.imageView.completed": imageViewRoute,
|
|
8944
|
-
"item.contextCompaction.started": contextCompactionRoute,
|
|
8945
|
-
"item.contextCompaction.completed": contextCompactionRoute,
|
|
8946
|
-
"mcp_tool_call.progress": (_data, runtimeEvent, ctx) => [
|
|
8885
|
+
);
|
|
8886
|
+
return results;
|
|
8887
|
+
}
|
|
8888
|
+
if (event.kind === "compact.post") {
|
|
8889
|
+
results.push(
|
|
8890
|
+
collapsed(
|
|
8947
8891
|
makeEvent(
|
|
8948
|
-
"
|
|
8892
|
+
"compact.post",
|
|
8949
8893
|
"info",
|
|
8950
8894
|
"system",
|
|
8951
8895
|
{
|
|
8952
|
-
|
|
8953
|
-
title: ctx.title
|
|
8896
|
+
trigger: readString(data["trigger"]) ?? "auto"
|
|
8954
8897
|
},
|
|
8955
|
-
|
|
8898
|
+
event
|
|
8956
8899
|
)
|
|
8957
|
-
|
|
8958
|
-
|
|
8900
|
+
)
|
|
8901
|
+
);
|
|
8902
|
+
return results;
|
|
8903
|
+
}
|
|
8904
|
+
if (event.kind === "cwd.changed") {
|
|
8905
|
+
results.push(
|
|
8906
|
+
collapsed(
|
|
8959
8907
|
makeEvent(
|
|
8960
|
-
"
|
|
8908
|
+
"cwd.changed",
|
|
8961
8909
|
"info",
|
|
8962
8910
|
"system",
|
|
8963
8911
|
{
|
|
8964
|
-
|
|
8965
|
-
input_preview: ctx.message
|
|
8912
|
+
cwd: readString(data["cwd"]) ?? ""
|
|
8966
8913
|
},
|
|
8967
|
-
|
|
8914
|
+
event
|
|
8968
8915
|
)
|
|
8969
|
-
|
|
8970
|
-
|
|
8916
|
+
)
|
|
8917
|
+
);
|
|
8918
|
+
return results;
|
|
8919
|
+
}
|
|
8920
|
+
if (event.kind === "file.changed") {
|
|
8921
|
+
results.push(
|
|
8922
|
+
collapsed(
|
|
8971
8923
|
makeEvent(
|
|
8972
|
-
"
|
|
8924
|
+
"file.changed",
|
|
8973
8925
|
"info",
|
|
8974
8926
|
"system",
|
|
8975
8927
|
{
|
|
8976
|
-
|
|
8928
|
+
file_path: readString(data["file_path"]) ?? ""
|
|
8977
8929
|
},
|
|
8978
|
-
|
|
8930
|
+
event
|
|
8979
8931
|
)
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
8932
|
+
)
|
|
8933
|
+
);
|
|
8934
|
+
return results;
|
|
8935
|
+
}
|
|
8936
|
+
return results;
|
|
8937
|
+
}
|
|
8938
|
+
};
|
|
8939
|
+
}
|
|
8940
|
+
|
|
8941
|
+
// src/core/feed/internals/runSessionProjection.ts
|
|
8942
|
+
function mapPlanStepStatus(status) {
|
|
8943
|
+
switch (status) {
|
|
8944
|
+
case "inProgress":
|
|
8945
|
+
return "in_progress";
|
|
8946
|
+
case "completed":
|
|
8947
|
+
return "completed";
|
|
8948
|
+
case void 0:
|
|
8949
|
+
default:
|
|
8950
|
+
return "pending";
|
|
8951
|
+
}
|
|
8952
|
+
}
|
|
8953
|
+
function createRunSessionProjection(args) {
|
|
8954
|
+
const {
|
|
8955
|
+
ensureRunArray,
|
|
8956
|
+
makeEvent,
|
|
8957
|
+
closeRunIntoEvent,
|
|
8958
|
+
runLifecycle,
|
|
8959
|
+
agentMessageStream,
|
|
8960
|
+
rootPlan,
|
|
8961
|
+
resolveToolActor,
|
|
8962
|
+
currentScope
|
|
8963
|
+
} = args;
|
|
8964
|
+
return {
|
|
8965
|
+
mapRunSessionEvent(event, data) {
|
|
8966
|
+
const results = [];
|
|
8967
|
+
if (event.kind === "session.start") {
|
|
8968
|
+
agentMessageStream.clearPending();
|
|
8969
|
+
const source = readString(data["source"]) ?? "startup";
|
|
8970
|
+
runLifecycle.setSession({
|
|
8971
|
+
session_id: event.sessionId,
|
|
8972
|
+
started_at: event.timestamp,
|
|
8973
|
+
source,
|
|
8974
|
+
agent_type: readString(data["agent_type"])
|
|
8975
|
+
});
|
|
8976
|
+
if (source === "resume" || source === "clear" || source === "compact") {
|
|
9000
8977
|
results.push(
|
|
9001
|
-
...
|
|
9002
|
-
notificationType,
|
|
9003
|
-
message,
|
|
9004
|
-
title
|
|
9005
|
-
})
|
|
8978
|
+
...ensureRunArray(event, source)
|
|
9006
8979
|
);
|
|
9007
|
-
break;
|
|
9008
8980
|
}
|
|
9009
8981
|
results.push(
|
|
9010
8982
|
makeEvent(
|
|
9011
|
-
"
|
|
8983
|
+
"session.start",
|
|
9012
8984
|
"info",
|
|
9013
8985
|
"system",
|
|
9014
8986
|
{
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
8987
|
+
source,
|
|
8988
|
+
agent_type: readString(data["agent_type"]),
|
|
8989
|
+
model: readString(data["model"])
|
|
9018
8990
|
},
|
|
9019
8991
|
event
|
|
9020
8992
|
)
|
|
9021
8993
|
);
|
|
9022
|
-
|
|
9023
|
-
}
|
|
9024
|
-
case "compact.pre": {
|
|
9025
|
-
results.push(...ensureRunArray(event));
|
|
9026
|
-
const compactEvt = makeEvent(
|
|
9027
|
-
"compact.pre",
|
|
9028
|
-
"info",
|
|
9029
|
-
"system",
|
|
9030
|
-
{
|
|
9031
|
-
trigger: readString(d["trigger"]) ?? "auto",
|
|
9032
|
-
custom_instructions: readString(d["custom_instructions"])
|
|
9033
|
-
},
|
|
9034
|
-
event
|
|
9035
|
-
);
|
|
9036
|
-
compactEvt.ui = { collapsed_default: true };
|
|
9037
|
-
results.push(compactEvt);
|
|
9038
|
-
break;
|
|
9039
|
-
}
|
|
9040
|
-
case "setup": {
|
|
9041
|
-
results.push(...ensureRunArray(event));
|
|
9042
|
-
const setupEvt = makeEvent(
|
|
9043
|
-
"setup",
|
|
9044
|
-
"info",
|
|
9045
|
-
"system",
|
|
9046
|
-
{
|
|
9047
|
-
trigger: readString(d["trigger"]) ?? "init"
|
|
9048
|
-
},
|
|
9049
|
-
event
|
|
9050
|
-
);
|
|
9051
|
-
setupEvt.ui = { collapsed_default: true };
|
|
9052
|
-
results.push(setupEvt);
|
|
9053
|
-
break;
|
|
9054
|
-
}
|
|
9055
|
-
case "teammate.idle": {
|
|
9056
|
-
results.push(...ensureRunArray(event));
|
|
9057
|
-
const idleEvt = makeEvent(
|
|
9058
|
-
"teammate.idle",
|
|
9059
|
-
"info",
|
|
9060
|
-
"system",
|
|
9061
|
-
{
|
|
9062
|
-
teammate_name: readString(d["teammate_name"]) ?? "",
|
|
9063
|
-
team_name: readString(d["team_name"]) ?? ""
|
|
9064
|
-
},
|
|
9065
|
-
event
|
|
9066
|
-
);
|
|
9067
|
-
idleEvt.ui = { collapsed_default: true };
|
|
9068
|
-
results.push(idleEvt);
|
|
9069
|
-
break;
|
|
8994
|
+
return results;
|
|
9070
8995
|
}
|
|
9071
|
-
|
|
9072
|
-
|
|
8996
|
+
if (event.kind === "session.end") {
|
|
8997
|
+
agentMessageStream.clearPending();
|
|
8998
|
+
const closeEvt = closeRunIntoEvent(event, "completed");
|
|
8999
|
+
if (closeEvt) results.push(closeEvt);
|
|
9073
9000
|
results.push(
|
|
9074
9001
|
makeEvent(
|
|
9075
|
-
"
|
|
9002
|
+
"session.end",
|
|
9076
9003
|
"info",
|
|
9077
9004
|
"system",
|
|
9078
9005
|
{
|
|
9079
|
-
|
|
9080
|
-
task_subject: readString(d["task_subject"]) ?? "",
|
|
9081
|
-
task_description: readString(d["task_description"]),
|
|
9082
|
-
teammate_name: readString(d["teammate_name"]),
|
|
9083
|
-
team_name: readString(d["team_name"])
|
|
9006
|
+
reason: readString(data["reason"]) ?? "unknown"
|
|
9084
9007
|
},
|
|
9085
9008
|
event
|
|
9086
9009
|
)
|
|
9087
9010
|
);
|
|
9088
|
-
|
|
9011
|
+
runLifecycle.endSession(event.timestamp);
|
|
9012
|
+
return results;
|
|
9089
9013
|
}
|
|
9090
|
-
|
|
9091
|
-
|
|
9014
|
+
if (event.kind === "user.prompt") {
|
|
9015
|
+
const prompt = readString(data["prompt"]) ?? "";
|
|
9016
|
+
results.push(
|
|
9017
|
+
...ensureRunArray(event, "user_prompt_submit", prompt.slice(0, 80))
|
|
9018
|
+
);
|
|
9092
9019
|
results.push(
|
|
9093
9020
|
makeEvent(
|
|
9094
|
-
"
|
|
9021
|
+
"user.prompt",
|
|
9095
9022
|
"info",
|
|
9096
|
-
"
|
|
9023
|
+
"user",
|
|
9097
9024
|
{
|
|
9098
|
-
|
|
9099
|
-
|
|
9025
|
+
prompt,
|
|
9026
|
+
cwd: event.context.cwd,
|
|
9027
|
+
permission_mode: event.context.permissionMode ?? readString(data["permission_mode"])
|
|
9100
9028
|
},
|
|
9101
9029
|
event
|
|
9102
9030
|
)
|
|
9103
9031
|
);
|
|
9104
|
-
|
|
9032
|
+
return results;
|
|
9033
|
+
}
|
|
9034
|
+
if (event.kind === "turn.start") {
|
|
9035
|
+
agentMessageStream.clearPending();
|
|
9036
|
+
const prompt = readString(data["prompt"]);
|
|
9037
|
+
results.push(
|
|
9038
|
+
...ensureRunArray(
|
|
9039
|
+
event,
|
|
9040
|
+
prompt ? "user_prompt_submit" : "other",
|
|
9041
|
+
prompt?.slice(0, 80)
|
|
9042
|
+
)
|
|
9043
|
+
);
|
|
9044
|
+
if (prompt) {
|
|
9045
|
+
results.push(
|
|
9046
|
+
makeEvent(
|
|
9047
|
+
"user.prompt",
|
|
9048
|
+
"info",
|
|
9049
|
+
"user",
|
|
9050
|
+
{
|
|
9051
|
+
prompt,
|
|
9052
|
+
cwd: event.context.cwd,
|
|
9053
|
+
permission_mode: event.context.permissionMode
|
|
9054
|
+
},
|
|
9055
|
+
event
|
|
9056
|
+
)
|
|
9057
|
+
);
|
|
9058
|
+
}
|
|
9059
|
+
return results;
|
|
9060
|
+
}
|
|
9061
|
+
if (event.kind === "message.delta") {
|
|
9062
|
+
agentMessageStream.appendPendingDelta(
|
|
9063
|
+
readString(data["item_id"]),
|
|
9064
|
+
readString(data["delta"]) ?? "",
|
|
9065
|
+
resolveToolActor(),
|
|
9066
|
+
currentScope()
|
|
9067
|
+
);
|
|
9068
|
+
return results;
|
|
9105
9069
|
}
|
|
9106
|
-
|
|
9070
|
+
if (event.kind === "message.complete") {
|
|
9107
9071
|
results.push(...ensureRunArray(event));
|
|
9108
|
-
const
|
|
9109
|
-
"
|
|
9072
|
+
const ev = agentMessageStream.emitCompleted({
|
|
9073
|
+
itemId: readString(data["item_id"]),
|
|
9074
|
+
messageText: readString(data["message"]),
|
|
9075
|
+
fallbackActorId: resolveToolActor(),
|
|
9076
|
+
fallbackScope: currentScope(),
|
|
9077
|
+
runtimeEvent: event
|
|
9078
|
+
});
|
|
9079
|
+
if (ev) results.push(ev);
|
|
9080
|
+
return results;
|
|
9081
|
+
}
|
|
9082
|
+
if (event.kind === "turn.complete") {
|
|
9083
|
+
if (!runLifecycle.getCurrentRun()) {
|
|
9084
|
+
agentMessageStream.clearPending();
|
|
9085
|
+
return results;
|
|
9086
|
+
}
|
|
9087
|
+
const stopEvt = makeEvent(
|
|
9088
|
+
"stop.request",
|
|
9110
9089
|
"info",
|
|
9111
|
-
"
|
|
9090
|
+
"agent:root",
|
|
9112
9091
|
{
|
|
9113
|
-
|
|
9092
|
+
stop_hook_active: false
|
|
9114
9093
|
},
|
|
9115
9094
|
event
|
|
9116
9095
|
);
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9096
|
+
results.push(stopEvt);
|
|
9097
|
+
const flushed = agentMessageStream.flushPending(event);
|
|
9098
|
+
for (const f of flushed) {
|
|
9099
|
+
f.cause = {
|
|
9100
|
+
...f.cause ?? {},
|
|
9101
|
+
parent_event_id: stopEvt.event_id
|
|
9102
|
+
};
|
|
9103
|
+
results.push(f);
|
|
9104
|
+
}
|
|
9105
|
+
const closeEvt = closeRunIntoEvent(event, "completed");
|
|
9106
|
+
if (closeEvt) results.push(closeEvt);
|
|
9107
|
+
return results;
|
|
9120
9108
|
}
|
|
9121
|
-
|
|
9122
|
-
|
|
9109
|
+
if (event.kind === "plan.delta") {
|
|
9110
|
+
const planSteps = data["plan"];
|
|
9111
|
+
if (Array.isArray(planSteps) && planSteps.length > 0) {
|
|
9112
|
+
const next = planSteps.map(
|
|
9113
|
+
(step) => ({
|
|
9114
|
+
content: typeof step.step === "string" ? step.step : "",
|
|
9115
|
+
status: mapPlanStepStatus(step.status)
|
|
9116
|
+
})
|
|
9117
|
+
);
|
|
9118
|
+
if (rootPlan.differs(next)) {
|
|
9119
|
+
rootPlan.set(next);
|
|
9120
|
+
results.push(
|
|
9121
|
+
makeEvent(
|
|
9122
|
+
"todo.update",
|
|
9123
|
+
"info",
|
|
9124
|
+
"system",
|
|
9125
|
+
{
|
|
9126
|
+
todo_id: "plan",
|
|
9127
|
+
patch: { status: "doing" }
|
|
9128
|
+
},
|
|
9129
|
+
event
|
|
9130
|
+
)
|
|
9131
|
+
);
|
|
9132
|
+
}
|
|
9133
|
+
}
|
|
9123
9134
|
results.push(
|
|
9124
9135
|
makeEvent(
|
|
9125
|
-
"
|
|
9136
|
+
"plan.update",
|
|
9126
9137
|
"info",
|
|
9127
9138
|
"system",
|
|
9128
9139
|
{
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9140
|
+
explanation: readString(data["explanation"]) ?? null,
|
|
9141
|
+
delta: readString(data["delta"]),
|
|
9142
|
+
item_id: readString(data["item_id"]),
|
|
9143
|
+
thread_id: readString(data["thread_id"]),
|
|
9144
|
+
turn_id: readString(data["turn_id"]),
|
|
9145
|
+
plan: Array.isArray(planSteps) ? planSteps : void 0
|
|
9134
9146
|
},
|
|
9135
9147
|
event
|
|
9136
9148
|
)
|
|
9137
9149
|
);
|
|
9138
|
-
|
|
9139
|
-
}
|
|
9140
|
-
case "cwd.changed": {
|
|
9141
|
-
results.push(...ensureRunArray(event));
|
|
9142
|
-
const evt = makeEvent(
|
|
9143
|
-
"cwd.changed",
|
|
9144
|
-
"info",
|
|
9145
|
-
"system",
|
|
9146
|
-
{
|
|
9147
|
-
cwd: readString(d["cwd"]) ?? ""
|
|
9148
|
-
},
|
|
9149
|
-
event
|
|
9150
|
-
);
|
|
9151
|
-
evt.ui = { collapsed_default: true };
|
|
9152
|
-
results.push(evt);
|
|
9153
|
-
break;
|
|
9150
|
+
return results;
|
|
9154
9151
|
}
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9152
|
+
if (event.kind === "reasoning.delta") {
|
|
9153
|
+
if (readString(data["phase"]) === "summary" && readString(data["delta"])) {
|
|
9154
|
+
const summaryIndex = (() => {
|
|
9155
|
+
const value = data["summary_index"] ?? data["content_index"];
|
|
9156
|
+
return typeof value === "number" ? value : void 0;
|
|
9157
|
+
})();
|
|
9158
|
+
results.push(
|
|
9159
|
+
makeEvent(
|
|
9160
|
+
"reasoning.summary",
|
|
9161
|
+
"info",
|
|
9162
|
+
"agent:root",
|
|
9163
|
+
{
|
|
9164
|
+
message: agentMessageStream.appendReasoningSummary(
|
|
9165
|
+
readString(data["item_id"]),
|
|
9166
|
+
summaryIndex,
|
|
9167
|
+
readString(data["delta"]) ?? ""
|
|
9168
|
+
),
|
|
9169
|
+
item_id: readString(data["item_id"]),
|
|
9170
|
+
content_index: typeof data["content_index"] === "number" ? data["content_index"] : void 0,
|
|
9171
|
+
summary_index: typeof data["summary_index"] === "number" ? data["summary_index"] : summaryIndex,
|
|
9172
|
+
thread_id: readString(data["thread_id"]),
|
|
9173
|
+
turn_id: readString(data["turn_id"])
|
|
9174
|
+
},
|
|
9175
|
+
event
|
|
9176
|
+
)
|
|
9177
|
+
);
|
|
9178
|
+
}
|
|
9179
|
+
return results;
|
|
9169
9180
|
}
|
|
9170
|
-
|
|
9171
|
-
results.push(...ensureRunArray(event));
|
|
9181
|
+
if (event.kind === "usage.update") {
|
|
9172
9182
|
results.push(
|
|
9173
9183
|
makeEvent(
|
|
9174
|
-
"
|
|
9175
|
-
"
|
|
9184
|
+
"usage.update",
|
|
9185
|
+
"info",
|
|
9176
9186
|
"system",
|
|
9177
9187
|
{
|
|
9178
|
-
|
|
9179
|
-
|
|
9188
|
+
thread_id: readString(data["thread_id"]),
|
|
9189
|
+
turn_id: readString(data["turn_id"]),
|
|
9190
|
+
usage: typeof data["usage"] === "object" && data["usage"] !== null ? data["usage"] : void 0,
|
|
9191
|
+
delta: typeof data["delta"] === "object" && data["delta"] !== null ? data["delta"] : void 0
|
|
9180
9192
|
},
|
|
9181
9193
|
event
|
|
9182
9194
|
)
|
|
9183
9195
|
);
|
|
9184
|
-
break;
|
|
9185
9196
|
}
|
|
9186
|
-
|
|
9187
|
-
|
|
9197
|
+
return results;
|
|
9198
|
+
}
|
|
9199
|
+
};
|
|
9200
|
+
}
|
|
9201
|
+
|
|
9202
|
+
// src/core/feed/internals/statusProjection.ts
|
|
9203
|
+
function createStatusProjection(args) {
|
|
9204
|
+
const { ensureRunArray, makeEvent } = args;
|
|
9205
|
+
return {
|
|
9206
|
+
mapStatusEvent(event, data) {
|
|
9207
|
+
const results = ensureRunArray(event);
|
|
9208
|
+
if (event.kind === "teammate.idle") {
|
|
9209
|
+
const idleEvt = makeEvent(
|
|
9210
|
+
"teammate.idle",
|
|
9211
|
+
"info",
|
|
9212
|
+
"system",
|
|
9213
|
+
{
|
|
9214
|
+
teammate_name: readString(data["teammate_name"]) ?? "",
|
|
9215
|
+
team_name: readString(data["team_name"]) ?? ""
|
|
9216
|
+
},
|
|
9217
|
+
event
|
|
9218
|
+
);
|
|
9219
|
+
idleEvt.ui = { collapsed_default: true };
|
|
9220
|
+
results.push(idleEvt);
|
|
9221
|
+
return results;
|
|
9222
|
+
}
|
|
9223
|
+
if (event.kind === "task.created") {
|
|
9188
9224
|
results.push(
|
|
9189
9225
|
makeEvent(
|
|
9190
|
-
"
|
|
9191
|
-
"
|
|
9226
|
+
"task.created",
|
|
9227
|
+
"info",
|
|
9192
9228
|
"system",
|
|
9193
9229
|
{
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9230
|
+
task_id: readString(data["task_id"]) ?? "",
|
|
9231
|
+
task_subject: readString(data["task_subject"]) ?? "",
|
|
9232
|
+
task_description: readString(data["task_description"]),
|
|
9233
|
+
teammate_name: readString(data["teammate_name"]),
|
|
9234
|
+
team_name: readString(data["team_name"])
|
|
9198
9235
|
},
|
|
9199
9236
|
event
|
|
9200
9237
|
)
|
|
9201
9238
|
);
|
|
9202
|
-
|
|
9239
|
+
return results;
|
|
9203
9240
|
}
|
|
9204
|
-
|
|
9205
|
-
results.push(...ensureRunArray(event));
|
|
9241
|
+
if (event.kind === "task.completed") {
|
|
9206
9242
|
results.push(
|
|
9207
9243
|
makeEvent(
|
|
9208
|
-
"
|
|
9209
|
-
"
|
|
9244
|
+
"task.completed",
|
|
9245
|
+
"info",
|
|
9210
9246
|
"system",
|
|
9211
9247
|
{
|
|
9212
|
-
|
|
9213
|
-
|
|
9248
|
+
task_id: readString(data["task_id"]) ?? "",
|
|
9249
|
+
task_subject: readString(data["task_subject"]) ?? "",
|
|
9250
|
+
task_description: readString(data["task_description"]),
|
|
9251
|
+
teammate_name: readString(data["teammate_name"]),
|
|
9252
|
+
team_name: readString(data["team_name"])
|
|
9214
9253
|
},
|
|
9215
9254
|
event
|
|
9216
9255
|
)
|
|
9217
9256
|
);
|
|
9218
|
-
break;
|
|
9219
|
-
}
|
|
9220
|
-
case "elicitation.result": {
|
|
9221
|
-
results.push(...ensureRunArray(event));
|
|
9222
|
-
const action = readString(d["action"]);
|
|
9223
|
-
const evt = makeEvent(
|
|
9224
|
-
"elicitation.result",
|
|
9225
|
-
"info",
|
|
9226
|
-
"system",
|
|
9227
|
-
{
|
|
9228
|
-
mcp_server: readString(d["mcp_server"]) ?? "unknown",
|
|
9229
|
-
...action ? { action } : {},
|
|
9230
|
-
content: readObject(d["content"])
|
|
9231
|
-
},
|
|
9232
|
-
event
|
|
9233
|
-
);
|
|
9234
|
-
evt.ui = { collapsed_default: true };
|
|
9235
|
-
results.push(evt);
|
|
9236
|
-
break;
|
|
9237
9257
|
}
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9258
|
+
return results;
|
|
9259
|
+
}
|
|
9260
|
+
};
|
|
9261
|
+
}
|
|
9262
|
+
|
|
9263
|
+
// src/core/feed/mapper.ts
|
|
9264
|
+
var RUN_SESSION_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
9265
|
+
"session.start",
|
|
9266
|
+
"session.end",
|
|
9267
|
+
"user.prompt",
|
|
9268
|
+
"turn.start",
|
|
9269
|
+
"message.delta",
|
|
9270
|
+
"message.complete",
|
|
9271
|
+
"turn.complete",
|
|
9272
|
+
"plan.delta",
|
|
9273
|
+
"reasoning.delta",
|
|
9274
|
+
"usage.update"
|
|
9275
|
+
]);
|
|
9276
|
+
var TOOL_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
9277
|
+
"tool.delta",
|
|
9278
|
+
"tool.pre",
|
|
9279
|
+
"tool.post",
|
|
9280
|
+
"tool.failure"
|
|
9281
|
+
]);
|
|
9282
|
+
var DECISION_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
9283
|
+
"permission.request",
|
|
9284
|
+
"stop.request",
|
|
9285
|
+
"stop.failure",
|
|
9286
|
+
"permission.denied",
|
|
9287
|
+
"elicitation.request",
|
|
9288
|
+
"elicitation.result"
|
|
9289
|
+
]);
|
|
9290
|
+
var SUBAGENT_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
9291
|
+
"subagent.start",
|
|
9292
|
+
"subagent.stop"
|
|
9293
|
+
]);
|
|
9294
|
+
var FILE_CONFIG_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
9295
|
+
"compact.pre",
|
|
9296
|
+
"setup",
|
|
9297
|
+
"config.change",
|
|
9298
|
+
"compact.post",
|
|
9299
|
+
"cwd.changed",
|
|
9300
|
+
"file.changed"
|
|
9301
|
+
]);
|
|
9302
|
+
var STATUS_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
9303
|
+
"teammate.idle",
|
|
9304
|
+
"task.completed",
|
|
9305
|
+
"task.created"
|
|
9306
|
+
]);
|
|
9307
|
+
function createFeedMapper(bootstrap) {
|
|
9308
|
+
const runLifecycle = createRunLifecycle();
|
|
9309
|
+
const decisionCorrelation = createDecisionCorrelation();
|
|
9310
|
+
const toolCorrelation = createToolCorrelation();
|
|
9311
|
+
const transcriptReader = createTranscriptReader();
|
|
9312
|
+
const actors = new ActorRegistry();
|
|
9313
|
+
const rootPlan = createRootPlanTracker();
|
|
9314
|
+
const subagents = createSubagentTracker();
|
|
9315
|
+
function makeEvent(kind, level, actorId, data, runtimeEvent, cause) {
|
|
9316
|
+
const s = runLifecycle.allocateSeq();
|
|
9317
|
+
const runId = runLifecycle.getRunId();
|
|
9318
|
+
const eventId = `${runId}:E${s}`;
|
|
9319
|
+
const baseCause = {
|
|
9320
|
+
hook_request_id: runtimeEvent.id,
|
|
9321
|
+
transcript_path: runtimeEvent.context.transcriptPath,
|
|
9322
|
+
...cause
|
|
9323
|
+
};
|
|
9324
|
+
const fe = {
|
|
9325
|
+
event_id: eventId,
|
|
9326
|
+
seq: s,
|
|
9327
|
+
ts: runtimeEvent.timestamp,
|
|
9328
|
+
session_id: runtimeEvent.sessionId,
|
|
9329
|
+
run_id: runId,
|
|
9330
|
+
kind,
|
|
9331
|
+
level,
|
|
9332
|
+
actor_id: actorId,
|
|
9333
|
+
cause: baseCause,
|
|
9334
|
+
title: "",
|
|
9335
|
+
display: runtimeEvent.display,
|
|
9336
|
+
raw: runtimeEvent.payload,
|
|
9337
|
+
data
|
|
9338
|
+
};
|
|
9339
|
+
fe.title = composeTitle(fe, runtimeEvent);
|
|
9340
|
+
if (runtimeEvent.interaction.expectsDecision || kind === "permission.request" || kind === "stop.request") {
|
|
9341
|
+
decisionCorrelation.recordRequest(runtimeEvent.id, eventId, kind);
|
|
9342
|
+
}
|
|
9343
|
+
return fe;
|
|
9344
|
+
}
|
|
9345
|
+
const agentMessageStream = createAgentMessageStream(
|
|
9346
|
+
makeEvent,
|
|
9347
|
+
transcriptReader
|
|
9348
|
+
);
|
|
9349
|
+
if (bootstrap) {
|
|
9350
|
+
runLifecycle.restoreFrom(bootstrap);
|
|
9351
|
+
for (const e of bootstrap.feedEvents) {
|
|
9352
|
+
if (e.kind === "tool.pre" && e.actor_id === "agent:root" && e.data.tool_name === "TodoWrite") {
|
|
9353
|
+
rootPlan.set(
|
|
9354
|
+
extractTodoItems(e.data.tool_input)
|
|
9253
9355
|
);
|
|
9254
|
-
unknownEvt.ui = { collapsed_default: true };
|
|
9255
|
-
results.push(unknownEvt);
|
|
9256
|
-
break;
|
|
9257
9356
|
}
|
|
9258
9357
|
}
|
|
9358
|
+
}
|
|
9359
|
+
function closeRunIntoEvent(runtimeEvent, status) {
|
|
9360
|
+
const closed = runLifecycle.closeRun(runtimeEvent.timestamp, status);
|
|
9361
|
+
if (!closed) return null;
|
|
9362
|
+
return makeEvent(
|
|
9363
|
+
"run.end",
|
|
9364
|
+
"info",
|
|
9365
|
+
"system",
|
|
9366
|
+
{ status, counters: { ...closed.counters } },
|
|
9367
|
+
runtimeEvent
|
|
9368
|
+
);
|
|
9369
|
+
}
|
|
9370
|
+
function ensureRunArray(runtimeEvent, triggerType = "other", promptPreview) {
|
|
9371
|
+
if (runLifecycle.getCurrentRun() && triggerType === "other") return [];
|
|
9372
|
+
const results = [];
|
|
9373
|
+
const closeEvt = closeRunIntoEvent(runtimeEvent, "completed");
|
|
9374
|
+
if (closeEvt) results.push(closeEvt);
|
|
9375
|
+
toolCorrelation.resetForNewRun();
|
|
9376
|
+
decisionCorrelation.resetForNewRun();
|
|
9377
|
+
agentMessageStream.resetForNewRun();
|
|
9378
|
+
subagents.clear();
|
|
9379
|
+
runLifecycle.openNewRun(
|
|
9380
|
+
runtimeEvent.timestamp,
|
|
9381
|
+
runtimeEvent.sessionId,
|
|
9382
|
+
triggerType,
|
|
9383
|
+
promptPreview
|
|
9384
|
+
);
|
|
9385
|
+
results.push(
|
|
9386
|
+
makeEvent(
|
|
9387
|
+
"run.start",
|
|
9388
|
+
"info",
|
|
9389
|
+
"system",
|
|
9390
|
+
{ trigger: { type: triggerType, prompt_preview: promptPreview } },
|
|
9391
|
+
runtimeEvent
|
|
9392
|
+
)
|
|
9393
|
+
);
|
|
9394
|
+
return results;
|
|
9395
|
+
}
|
|
9396
|
+
function resolveToolActor() {
|
|
9397
|
+
return subagents.peek() ?? "agent:root";
|
|
9398
|
+
}
|
|
9399
|
+
const toolProjection = createToolProjection({
|
|
9400
|
+
ensureRunArray,
|
|
9401
|
+
makeEvent,
|
|
9402
|
+
runLifecycle,
|
|
9403
|
+
toolCorrelation,
|
|
9404
|
+
rootPlan,
|
|
9405
|
+
subagents,
|
|
9406
|
+
resolveToolActor
|
|
9407
|
+
});
|
|
9408
|
+
const notificationProjection = createNotificationProjection({
|
|
9409
|
+
ensureRunArray,
|
|
9410
|
+
makeEvent,
|
|
9411
|
+
decisionCorrelation
|
|
9412
|
+
});
|
|
9413
|
+
const decisionProjection = createDecisionProjection({
|
|
9414
|
+
ensureRunArray,
|
|
9415
|
+
makeEvent,
|
|
9416
|
+
runLifecycle,
|
|
9417
|
+
decisionCorrelation
|
|
9418
|
+
});
|
|
9419
|
+
const subagentProjection = createSubagentProjection({
|
|
9420
|
+
ensureRunArray,
|
|
9421
|
+
makeEvent,
|
|
9422
|
+
runLifecycle,
|
|
9423
|
+
actors,
|
|
9424
|
+
subagents
|
|
9425
|
+
});
|
|
9426
|
+
const fileConfigProjection = createFileConfigProjection({
|
|
9427
|
+
ensureRunArray,
|
|
9428
|
+
makeEvent
|
|
9429
|
+
});
|
|
9430
|
+
const statusProjection = createStatusProjection({
|
|
9431
|
+
ensureRunArray,
|
|
9432
|
+
makeEvent
|
|
9433
|
+
});
|
|
9434
|
+
const currentScope = () => subagents.currentScope();
|
|
9435
|
+
const runSessionProjection = createRunSessionProjection({
|
|
9436
|
+
ensureRunArray,
|
|
9437
|
+
makeEvent,
|
|
9438
|
+
closeRunIntoEvent,
|
|
9439
|
+
runLifecycle,
|
|
9440
|
+
agentMessageStream,
|
|
9441
|
+
rootPlan,
|
|
9442
|
+
resolveToolActor,
|
|
9443
|
+
currentScope
|
|
9444
|
+
});
|
|
9445
|
+
function mapEvent(event) {
|
|
9446
|
+
const d = event.data;
|
|
9447
|
+
const eventKind2 = event.kind;
|
|
9448
|
+
const results = [];
|
|
9449
|
+
function emitFallbackMessage(parentKind, actorId, scope) {
|
|
9450
|
+
if (results.some((r) => r.kind === "agent.message")) return;
|
|
9451
|
+
const msg = readString(d["last_assistant_message"]);
|
|
9452
|
+
if (!msg) return;
|
|
9453
|
+
const parentEvt = results.find((r) => r.kind === parentKind);
|
|
9454
|
+
const ev = agentMessageStream.emit({
|
|
9455
|
+
runtimeEvent: event,
|
|
9456
|
+
actorId,
|
|
9457
|
+
scope,
|
|
9458
|
+
message: msg,
|
|
9459
|
+
source: "hook",
|
|
9460
|
+
cause: parentEvt ? { parent_event_id: parentEvt.event_id } : void 0
|
|
9461
|
+
});
|
|
9462
|
+
if (ev) results.push(ev);
|
|
9463
|
+
}
|
|
9464
|
+
const transcriptPath = event.context.transcriptPath;
|
|
9465
|
+
const isStopEvent = eventKind2 === "stop.request" || eventKind2 === "subagent.stop";
|
|
9466
|
+
if (transcriptPath && !isStopEvent) {
|
|
9467
|
+
results.push(
|
|
9468
|
+
...agentMessageStream.emitTranscriptMessages(
|
|
9469
|
+
transcriptPath,
|
|
9470
|
+
event,
|
|
9471
|
+
resolveToolActor(),
|
|
9472
|
+
currentScope()
|
|
9473
|
+
)
|
|
9474
|
+
);
|
|
9475
|
+
}
|
|
9476
|
+
if (RUN_SESSION_EVENT_KINDS.has(eventKind2)) {
|
|
9477
|
+
results.push(...runSessionProjection.mapRunSessionEvent(event, d));
|
|
9478
|
+
} else if (TOOL_EVENT_KINDS.has(eventKind2)) {
|
|
9479
|
+
results.push(...toolProjection.mapToolEvent(event, d));
|
|
9480
|
+
} else if (DECISION_EVENT_KINDS.has(eventKind2)) {
|
|
9481
|
+
results.push(...decisionProjection.mapRequestEvent(event, d));
|
|
9482
|
+
} else if (SUBAGENT_EVENT_KINDS.has(eventKind2)) {
|
|
9483
|
+
results.push(...subagentProjection.mapSubagentEvent(event, d));
|
|
9484
|
+
} else if (eventKind2 === "notification") {
|
|
9485
|
+
results.push(...notificationProjection.mapNotification(event, d));
|
|
9486
|
+
} else if (FILE_CONFIG_EVENT_KINDS.has(eventKind2)) {
|
|
9487
|
+
results.push(...fileConfigProjection.mapFileConfigEvent(event, d));
|
|
9488
|
+
} else if (STATUS_EVENT_KINDS.has(eventKind2)) {
|
|
9489
|
+
results.push(...statusProjection.mapStatusEvent(event, d));
|
|
9490
|
+
} else if (eventKind2 === "unknown") {
|
|
9491
|
+
results.push(...ensureRunArray(event));
|
|
9492
|
+
const unknownEvt = makeEvent(
|
|
9493
|
+
"unknown.hook",
|
|
9494
|
+
"debug",
|
|
9495
|
+
"system",
|
|
9496
|
+
{
|
|
9497
|
+
hook_event_name: readString(
|
|
9498
|
+
d["source_event_name"],
|
|
9499
|
+
d["hook_event_name"],
|
|
9500
|
+
event.hookName
|
|
9501
|
+
) ?? "unknown",
|
|
9502
|
+
payload: d.payload ?? null
|
|
9503
|
+
},
|
|
9504
|
+
event
|
|
9505
|
+
);
|
|
9506
|
+
unknownEvt.ui = { collapsed_default: true };
|
|
9507
|
+
results.push(unknownEvt);
|
|
9508
|
+
}
|
|
9259
9509
|
if (eventKind2 === "stop.request") {
|
|
9260
9510
|
if (transcriptPath) agentMessageStream.drainTranscript(transcriptPath);
|
|
9261
9511
|
emitFallbackMessage("stop.request", "agent:root", "root");
|
|
@@ -9268,74 +9518,7 @@ function createFeedMapper(bootstrap) {
|
|
|
9268
9518
|
return results;
|
|
9269
9519
|
}
|
|
9270
9520
|
function mapDecision(requestId, decision) {
|
|
9271
|
-
|
|
9272
|
-
if (!consumed) return null;
|
|
9273
|
-
const { parentEventId, originalKind } = consumed;
|
|
9274
|
-
function makeDecisionEvent(kind, data) {
|
|
9275
|
-
const s = runLifecycle.allocateSeq();
|
|
9276
|
-
const runId = runLifecycle.getRunId();
|
|
9277
|
-
const session = runLifecycle.getSession();
|
|
9278
|
-
const fe = {
|
|
9279
|
-
event_id: `${runId}:E${s}`,
|
|
9280
|
-
seq: s,
|
|
9281
|
-
ts: Date.now(),
|
|
9282
|
-
session_id: session?.session_id ?? "unknown",
|
|
9283
|
-
run_id: runId,
|
|
9284
|
-
kind,
|
|
9285
|
-
level: "info",
|
|
9286
|
-
actor_id: decision.source === "user" ? "user" : "system",
|
|
9287
|
-
cause: {
|
|
9288
|
-
parent_event_id: parentEventId,
|
|
9289
|
-
hook_request_id: requestId
|
|
9290
|
-
},
|
|
9291
|
-
title: "",
|
|
9292
|
-
data
|
|
9293
|
-
};
|
|
9294
|
-
fe.title = generateTitle(fe);
|
|
9295
|
-
return fe;
|
|
9296
|
-
}
|
|
9297
|
-
if (originalKind === "permission.request") {
|
|
9298
|
-
let data;
|
|
9299
|
-
if (decision.source === "timeout") {
|
|
9300
|
-
data = { decision_type: "no_opinion", reason: "timeout" };
|
|
9301
|
-
} else if (decision.type === "passthrough") {
|
|
9302
|
-
data = { decision_type: "no_opinion", reason: decision.source };
|
|
9303
|
-
} else if (decision.intent?.kind === "permission_allow") {
|
|
9304
|
-
data = { decision_type: "allow" };
|
|
9305
|
-
} else if (decision.intent?.kind === "permission_deny") {
|
|
9306
|
-
data = {
|
|
9307
|
-
decision_type: "deny",
|
|
9308
|
-
message: decision.intent.reason
|
|
9309
|
-
};
|
|
9310
|
-
} else {
|
|
9311
|
-
data = { decision_type: "no_opinion", reason: "unknown" };
|
|
9312
|
-
}
|
|
9313
|
-
return makeDecisionEvent("permission.decision", data);
|
|
9314
|
-
}
|
|
9315
|
-
if (originalKind === "stop.request") {
|
|
9316
|
-
let data;
|
|
9317
|
-
const d = decision.data;
|
|
9318
|
-
const decisionReason = typeof d?.reason === "string" ? d.reason : void 0;
|
|
9319
|
-
if (decision.source === "timeout") {
|
|
9320
|
-
data = { decision_type: "no_opinion", reason: "timeout" };
|
|
9321
|
-
} else if (decision.type === "passthrough") {
|
|
9322
|
-
data = { decision_type: "no_opinion", reason: decision.source };
|
|
9323
|
-
} else if (d?.decision === "block") {
|
|
9324
|
-
data = {
|
|
9325
|
-
decision_type: "block",
|
|
9326
|
-
reason: decisionReason ?? decision.reason ?? "Blocked"
|
|
9327
|
-
};
|
|
9328
|
-
} else if (d?.ok === false) {
|
|
9329
|
-
data = {
|
|
9330
|
-
decision_type: "block",
|
|
9331
|
-
reason: decisionReason ?? "Blocked by hook"
|
|
9332
|
-
};
|
|
9333
|
-
} else {
|
|
9334
|
-
data = { decision_type: "allow" };
|
|
9335
|
-
}
|
|
9336
|
-
return makeDecisionEvent("stop.decision", data);
|
|
9337
|
-
}
|
|
9338
|
-
return null;
|
|
9521
|
+
return decisionProjection.mapDecision(requestId, decision);
|
|
9339
9522
|
}
|
|
9340
9523
|
return {
|
|
9341
9524
|
mapEvent,
|
|
@@ -11231,17 +11414,52 @@ function createDashboardFeedOutbox(options = {}) {
|
|
|
11231
11414
|
}
|
|
11232
11415
|
};
|
|
11233
11416
|
}
|
|
11234
|
-
|
|
11417
|
+
|
|
11418
|
+
// src/app/dashboard/pairedFeedPublisher.ts
|
|
11419
|
+
var DEFAULT_DRAIN_INTERVAL_MS = 1e3;
|
|
11420
|
+
function createPairedFeedPublisher(options = {}) {
|
|
11235
11421
|
const readConfig2 = options.readConfig ?? (() => readDashboardClientConfig());
|
|
11236
11422
|
const now = options.now ?? (() => Date.now());
|
|
11237
11423
|
const onError = options.onError ?? (() => {
|
|
11238
11424
|
});
|
|
11425
|
+
const drainIntervalMs = options.drainIntervalMs ?? DEFAULT_DRAIN_INTERVAL_MS;
|
|
11239
11426
|
let ownedOutbox = null;
|
|
11427
|
+
let transport = null;
|
|
11428
|
+
let drainTimer = null;
|
|
11240
11429
|
function getOutbox() {
|
|
11241
11430
|
if (options.outbox) return options.outbox;
|
|
11242
11431
|
ownedOutbox ??= createDashboardFeedOutbox();
|
|
11243
11432
|
return ownedOutbox;
|
|
11244
11433
|
}
|
|
11434
|
+
function clearDrainTimer() {
|
|
11435
|
+
if (!drainTimer) return;
|
|
11436
|
+
clearInterval(drainTimer);
|
|
11437
|
+
drainTimer = null;
|
|
11438
|
+
}
|
|
11439
|
+
function drain(force = false) {
|
|
11440
|
+
if (!transport) return;
|
|
11441
|
+
const rows = getOutbox().pendingBatch({
|
|
11442
|
+
limit: 100,
|
|
11443
|
+
now: force ? Number.POSITIVE_INFINITY : now()
|
|
11444
|
+
});
|
|
11445
|
+
for (const row of rows) {
|
|
11446
|
+
transport.sendFeedEvent({
|
|
11447
|
+
deliverySeq: row.deliverySeq,
|
|
11448
|
+
envelope: row.envelope
|
|
11449
|
+
});
|
|
11450
|
+
getOutbox().markAttempted({
|
|
11451
|
+
deliverySeq: row.deliverySeq,
|
|
11452
|
+
nextAttemptAt: now() + Math.min(3e4, (row.attempt + 1) * 1e3)
|
|
11453
|
+
});
|
|
11454
|
+
}
|
|
11455
|
+
}
|
|
11456
|
+
function startDrainTimer() {
|
|
11457
|
+
clearDrainTimer();
|
|
11458
|
+
const timer = setInterval(drain, drainIntervalMs);
|
|
11459
|
+
timer.unref();
|
|
11460
|
+
drainTimer = timer;
|
|
11461
|
+
drain(true);
|
|
11462
|
+
}
|
|
11245
11463
|
return {
|
|
11246
11464
|
publish(input) {
|
|
11247
11465
|
if (input.feedEvents.length === 0) return;
|
|
@@ -11255,11 +11473,30 @@ function createDashboardFeedPublisher(options = {}) {
|
|
|
11255
11473
|
feedEvents: input.feedEvents,
|
|
11256
11474
|
emittedAt: now()
|
|
11257
11475
|
});
|
|
11476
|
+
drain();
|
|
11258
11477
|
} catch (err) {
|
|
11259
11478
|
onError(
|
|
11260
|
-
`
|
|
11479
|
+
`paired feed publish failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11261
11480
|
);
|
|
11262
11481
|
}
|
|
11482
|
+
},
|
|
11483
|
+
attachTransport(nextTransport) {
|
|
11484
|
+
transport = nextTransport;
|
|
11485
|
+
startDrainTimer();
|
|
11486
|
+
},
|
|
11487
|
+
detachTransport() {
|
|
11488
|
+
transport = null;
|
|
11489
|
+
clearDrainTimer();
|
|
11490
|
+
},
|
|
11491
|
+
handleAck(frame) {
|
|
11492
|
+
getOutbox().markAcked({
|
|
11493
|
+
...typeof frame.deliverySeq === "number" ? { deliverySeq: frame.deliverySeq } : {},
|
|
11494
|
+
...typeof frame.eventId === "string" ? { eventId: frame.eventId } : {}
|
|
11495
|
+
});
|
|
11496
|
+
},
|
|
11497
|
+
close() {
|
|
11498
|
+
this.detachTransport();
|
|
11499
|
+
ownedOutbox?.close();
|
|
11263
11500
|
}
|
|
11264
11501
|
};
|
|
11265
11502
|
}
|
|
@@ -11412,7 +11649,7 @@ async function runExec(options) {
|
|
|
11412
11649
|
const runtimeFactory = options.runtimeFactory ?? createRuntime;
|
|
11413
11650
|
const sessionStoreFactory = options.sessionStoreFactory ?? createSessionStore;
|
|
11414
11651
|
const athenaSessionId = options.athenaSessionId ?? crypto2.randomUUID();
|
|
11415
|
-
const dashboardFeedPublisher = options.dashboardFeedPublisher ??
|
|
11652
|
+
const dashboardFeedPublisher = options.dashboardFeedPublisher ?? createPairedFeedPublisher();
|
|
11416
11653
|
const dashboardOrigin = options.dashboardOrigin ?? "local";
|
|
11417
11654
|
const output = createExecOutputWriter({
|
|
11418
11655
|
json,
|
|
@@ -11781,6 +12018,207 @@ async function runExec(options) {
|
|
|
11781
12018
|
return result;
|
|
11782
12019
|
}
|
|
11783
12020
|
|
|
12021
|
+
// src/app/dashboard/instanceSocketClient.ts
|
|
12022
|
+
import { WebSocket as WebSocket2 } from "ws";
|
|
12023
|
+
var DEFAULT_HEARTBEAT_MS = 3e4;
|
|
12024
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
12025
|
+
function instanceSocketUrl(dashboardUrl, instanceId) {
|
|
12026
|
+
const url = new URL(dashboardUrl);
|
|
12027
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
12028
|
+
url.pathname = `/api/instances/${encodeURIComponent(instanceId)}/socket`;
|
|
12029
|
+
url.search = "";
|
|
12030
|
+
url.hash = "";
|
|
12031
|
+
return url.toString();
|
|
12032
|
+
}
|
|
12033
|
+
function createInstanceSocketClient(opts) {
|
|
12034
|
+
const heartbeatMs = opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_MS;
|
|
12035
|
+
const connectTimeoutMs = opts.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
12036
|
+
const log = opts.log ?? (() => {
|
|
12037
|
+
});
|
|
12038
|
+
const now = opts.now ?? (() => Date.now());
|
|
12039
|
+
const makeWebSocket = opts.makeWebSocket ?? ((url, accessToken) => new WebSocket2(url, [accessToken]));
|
|
12040
|
+
const frameHandlers = /* @__PURE__ */ new Set();
|
|
12041
|
+
const closeHandlers = /* @__PURE__ */ new Set();
|
|
12042
|
+
let ws = null;
|
|
12043
|
+
let heartbeat = null;
|
|
12044
|
+
let droppedSinceClose = 0;
|
|
12045
|
+
function send(frame) {
|
|
12046
|
+
if (!ws || ws.readyState !== ws.OPEN) {
|
|
12047
|
+
droppedSinceClose += 1;
|
|
12048
|
+
if (droppedSinceClose === 1) {
|
|
12049
|
+
log(
|
|
12050
|
+
"warn",
|
|
12051
|
+
`instance socket dropped frame (socket not open): type=${frame.type}`
|
|
12052
|
+
);
|
|
12053
|
+
}
|
|
12054
|
+
return;
|
|
12055
|
+
}
|
|
12056
|
+
droppedSinceClose = 0;
|
|
12057
|
+
try {
|
|
12058
|
+
ws.send(JSON.stringify(frame));
|
|
12059
|
+
} catch (err) {
|
|
12060
|
+
log(
|
|
12061
|
+
"warn",
|
|
12062
|
+
`instance socket send failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12063
|
+
);
|
|
12064
|
+
}
|
|
12065
|
+
}
|
|
12066
|
+
function startHeartbeat() {
|
|
12067
|
+
stopHeartbeat();
|
|
12068
|
+
const interval = setInterval(() => {
|
|
12069
|
+
send({ type: "ping", ts: now() });
|
|
12070
|
+
}, heartbeatMs);
|
|
12071
|
+
interval.unref();
|
|
12072
|
+
heartbeat = interval;
|
|
12073
|
+
}
|
|
12074
|
+
function stopHeartbeat() {
|
|
12075
|
+
if (heartbeat) {
|
|
12076
|
+
clearInterval(heartbeat);
|
|
12077
|
+
heartbeat = null;
|
|
12078
|
+
}
|
|
12079
|
+
}
|
|
12080
|
+
function emitClose(reason) {
|
|
12081
|
+
stopHeartbeat();
|
|
12082
|
+
for (const handler of [...closeHandlers]) {
|
|
12083
|
+
try {
|
|
12084
|
+
handler(reason);
|
|
12085
|
+
} catch {
|
|
12086
|
+
}
|
|
12087
|
+
}
|
|
12088
|
+
}
|
|
12089
|
+
function handleFrame(parsed) {
|
|
12090
|
+
for (const handler of [...frameHandlers]) {
|
|
12091
|
+
try {
|
|
12092
|
+
handler(parsed);
|
|
12093
|
+
} catch (err) {
|
|
12094
|
+
log(
|
|
12095
|
+
"warn",
|
|
12096
|
+
`instance socket frame handler threw: ${err instanceof Error ? err.message : String(err)}`
|
|
12097
|
+
);
|
|
12098
|
+
}
|
|
12099
|
+
}
|
|
12100
|
+
}
|
|
12101
|
+
async function connect2() {
|
|
12102
|
+
if (ws) throw new Error("instance socket already connected");
|
|
12103
|
+
const url = instanceSocketUrl(opts.dashboardUrl, opts.instanceId);
|
|
12104
|
+
const next = makeWebSocket(url, opts.accessToken);
|
|
12105
|
+
try {
|
|
12106
|
+
await new Promise((resolve, reject) => {
|
|
12107
|
+
let settled = false;
|
|
12108
|
+
const cleanup = () => {
|
|
12109
|
+
next.off("open", onOpen);
|
|
12110
|
+
next.off("error", onError);
|
|
12111
|
+
clearTimeout(timer);
|
|
12112
|
+
};
|
|
12113
|
+
const onOpen = () => {
|
|
12114
|
+
if (settled) return;
|
|
12115
|
+
settled = true;
|
|
12116
|
+
cleanup();
|
|
12117
|
+
resolve();
|
|
12118
|
+
};
|
|
12119
|
+
const onError = (err) => {
|
|
12120
|
+
if (settled) return;
|
|
12121
|
+
settled = true;
|
|
12122
|
+
cleanup();
|
|
12123
|
+
reject(new Error(`instance socket connect failed: ${err.message}`));
|
|
12124
|
+
};
|
|
12125
|
+
const timer = setTimeout(() => {
|
|
12126
|
+
if (settled) return;
|
|
12127
|
+
settled = true;
|
|
12128
|
+
cleanup();
|
|
12129
|
+
reject(
|
|
12130
|
+
new Error(
|
|
12131
|
+
`instance socket connect failed: timed out after ${connectTimeoutMs}ms`
|
|
12132
|
+
)
|
|
12133
|
+
);
|
|
12134
|
+
}, connectTimeoutMs);
|
|
12135
|
+
next.once("open", onOpen);
|
|
12136
|
+
next.once("error", onError);
|
|
12137
|
+
});
|
|
12138
|
+
} catch (err) {
|
|
12139
|
+
next.on("error", () => {
|
|
12140
|
+
});
|
|
12141
|
+
try {
|
|
12142
|
+
next.terminate();
|
|
12143
|
+
} catch {
|
|
12144
|
+
}
|
|
12145
|
+
throw err;
|
|
12146
|
+
}
|
|
12147
|
+
ws = next;
|
|
12148
|
+
startHeartbeat();
|
|
12149
|
+
next.on("message", (data) => {
|
|
12150
|
+
let parsed;
|
|
12151
|
+
try {
|
|
12152
|
+
parsed = JSON.parse(String(data));
|
|
12153
|
+
} catch (err) {
|
|
12154
|
+
log(
|
|
12155
|
+
"warn",
|
|
12156
|
+
`instance socket frame parse failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12157
|
+
);
|
|
12158
|
+
return;
|
|
12159
|
+
}
|
|
12160
|
+
handleFrame(parsed);
|
|
12161
|
+
});
|
|
12162
|
+
next.on("close", (_code, reasonBuf) => {
|
|
12163
|
+
if (next !== ws) return;
|
|
12164
|
+
ws = null;
|
|
12165
|
+
const reason = reasonBuf.toString() || "closed";
|
|
12166
|
+
emitClose(reason);
|
|
12167
|
+
});
|
|
12168
|
+
next.on("error", (err) => {
|
|
12169
|
+
log("warn", `instance socket error: ${err.message}`);
|
|
12170
|
+
});
|
|
12171
|
+
}
|
|
12172
|
+
function close(reason) {
|
|
12173
|
+
stopHeartbeat();
|
|
12174
|
+
if (ws) {
|
|
12175
|
+
try {
|
|
12176
|
+
ws.close(1e3, reason ?? "client closed");
|
|
12177
|
+
} catch {
|
|
12178
|
+
ws.terminate();
|
|
12179
|
+
}
|
|
12180
|
+
}
|
|
12181
|
+
ws = null;
|
|
12182
|
+
}
|
|
12183
|
+
function onFrame(handler) {
|
|
12184
|
+
frameHandlers.add(handler);
|
|
12185
|
+
}
|
|
12186
|
+
function onClose(handler) {
|
|
12187
|
+
closeHandlers.add(handler);
|
|
12188
|
+
}
|
|
12189
|
+
function sendAssignmentAccepted(runId) {
|
|
12190
|
+
send({ type: "assignment_accepted", runId });
|
|
12191
|
+
log("info", `instance socket: assignment accepted runId=${runId}`);
|
|
12192
|
+
}
|
|
12193
|
+
function sendAssignmentRejected(input) {
|
|
12194
|
+
send({ type: "assignment_rejected", ...input });
|
|
12195
|
+
log(
|
|
12196
|
+
"info",
|
|
12197
|
+
`instance socket: assignment rejected runId=${input.runId} reason=${input.reason}`
|
|
12198
|
+
);
|
|
12199
|
+
}
|
|
12200
|
+
function sendRunEvent(event) {
|
|
12201
|
+
send({ type: "run_event", ...event });
|
|
12202
|
+
}
|
|
12203
|
+
function sendFeedEvent(event) {
|
|
12204
|
+
send({ type: "feed_event", ...event });
|
|
12205
|
+
}
|
|
12206
|
+
function sendDecisionAck(input) {
|
|
12207
|
+
send({ type: "decision_ack", ...input });
|
|
12208
|
+
}
|
|
12209
|
+
return {
|
|
12210
|
+
connect: connect2,
|
|
12211
|
+
close,
|
|
12212
|
+
onFrame,
|
|
12213
|
+
onClose,
|
|
12214
|
+
sendAssignmentAccepted,
|
|
12215
|
+
sendAssignmentRejected,
|
|
12216
|
+
sendRunEvent,
|
|
12217
|
+
sendFeedEvent,
|
|
12218
|
+
sendDecisionAck
|
|
12219
|
+
};
|
|
12220
|
+
}
|
|
12221
|
+
|
|
11784
12222
|
// src/app/bootstrap/harnessOverride.ts
|
|
11785
12223
|
function normalizeHarnessOverride(value) {
|
|
11786
12224
|
switch (value) {
|
|
@@ -11798,9 +12236,9 @@ function normalizeHarnessOverride(value) {
|
|
|
11798
12236
|
}
|
|
11799
12237
|
|
|
11800
12238
|
// src/app/dashboard/runStreamClient.ts
|
|
11801
|
-
import { WebSocket as
|
|
12239
|
+
import { WebSocket as WebSocket3 } from "ws";
|
|
11802
12240
|
var DEFAULT_RECONNECT_DELAYS_MS = [250, 1e3, 2e3, 5e3, 15e3];
|
|
11803
|
-
var
|
|
12241
|
+
var DEFAULT_HEARTBEAT_MS2 = 3e4;
|
|
11804
12242
|
var DEFAULT_WATCHDOG_MS = 9e4;
|
|
11805
12243
|
var DEFAULT_MAX_QUEUE_SIZE = 5e3;
|
|
11806
12244
|
function createRunStreamClient(opts) {
|
|
@@ -11808,10 +12246,10 @@ function createRunStreamClient(opts) {
|
|
|
11808
12246
|
});
|
|
11809
12247
|
const now = opts.now ?? (() => Date.now());
|
|
11810
12248
|
const reconnectDelays = opts.reconnectDelaysMs ?? DEFAULT_RECONNECT_DELAYS_MS;
|
|
11811
|
-
const heartbeatMs = opts.heartbeatIntervalMs ??
|
|
12249
|
+
const heartbeatMs = opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_MS2;
|
|
11812
12250
|
const watchdogMs = opts.watchdogTimeoutMs ?? DEFAULT_WATCHDOG_MS;
|
|
11813
12251
|
const maxQueueSize = opts.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE;
|
|
11814
|
-
const makeWebSocket = opts.makeWebSocket ?? ((url) => new
|
|
12252
|
+
const makeWebSocket = opts.makeWebSocket ?? ((url) => new WebSocket3(url));
|
|
11815
12253
|
const setTimer = opts.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
11816
12254
|
const clearTimer = opts.clearTimer ?? ((t) => clearTimeout(t));
|
|
11817
12255
|
let nextSeq = 1;
|
|
@@ -12073,14 +12511,84 @@ function createRunStreamClient(opts) {
|
|
|
12073
12511
|
}
|
|
12074
12512
|
}
|
|
12075
12513
|
}
|
|
12076
|
-
notifyTerminated();
|
|
12514
|
+
notifyTerminated();
|
|
12515
|
+
}
|
|
12516
|
+
};
|
|
12517
|
+
}
|
|
12518
|
+
|
|
12519
|
+
// src/app/dashboard/remoteRunEventPublisher.ts
|
|
12520
|
+
async function createRemoteRunEventPublisher({
|
|
12521
|
+
runId,
|
|
12522
|
+
callbackWsUrl,
|
|
12523
|
+
callbackToken,
|
|
12524
|
+
client,
|
|
12525
|
+
log = () => {
|
|
12526
|
+
},
|
|
12527
|
+
now = Date.now,
|
|
12528
|
+
createRunStreamClient: createRunStreamClientFn = createRunStreamClient,
|
|
12529
|
+
runStreamConnectTimeoutMs = 5e3
|
|
12530
|
+
}) {
|
|
12531
|
+
let runStream = null;
|
|
12532
|
+
if (callbackWsUrl && callbackToken) {
|
|
12533
|
+
const candidate = createRunStreamClientFn({
|
|
12534
|
+
wsUrl: callbackWsUrl,
|
|
12535
|
+
token: callbackToken,
|
|
12536
|
+
log: (level, message) => log(level, `run-stream[${runId}]: ${message}`),
|
|
12537
|
+
now
|
|
12538
|
+
});
|
|
12539
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
12540
|
+
const timer = setTimeout(
|
|
12541
|
+
() => resolve("timeout"),
|
|
12542
|
+
runStreamConnectTimeoutMs
|
|
12543
|
+
);
|
|
12544
|
+
timer.unref();
|
|
12545
|
+
});
|
|
12546
|
+
try {
|
|
12547
|
+
const result = await Promise.race([
|
|
12548
|
+
candidate.connect().then(() => "connected"),
|
|
12549
|
+
timeoutPromise
|
|
12550
|
+
]);
|
|
12551
|
+
if (result === "connected") {
|
|
12552
|
+
runStream = candidate;
|
|
12553
|
+
} else {
|
|
12554
|
+
log(
|
|
12555
|
+
"warn",
|
|
12556
|
+
`run-stream[${runId}]: connect timed out after ${runStreamConnectTimeoutMs}ms; falling back to instance-socket relay`
|
|
12557
|
+
);
|
|
12558
|
+
void candidate.close("connect_timeout");
|
|
12559
|
+
}
|
|
12560
|
+
} catch (err) {
|
|
12561
|
+
log(
|
|
12562
|
+
"warn",
|
|
12563
|
+
`run-stream[${runId}]: connect failed (${err instanceof Error ? err.message : String(err)}); falling back to instance-socket relay`
|
|
12564
|
+
);
|
|
12565
|
+
}
|
|
12566
|
+
}
|
|
12567
|
+
let legacySeq = 0;
|
|
12568
|
+
return {
|
|
12569
|
+
publish(kind, payload, ts) {
|
|
12570
|
+
if (runStream) {
|
|
12571
|
+
runStream.sendEvent({ ts, kind, payload });
|
|
12572
|
+
return;
|
|
12573
|
+
}
|
|
12574
|
+
legacySeq += 1;
|
|
12575
|
+
client.sendRunEvent({ runId, seq: legacySeq, ts, kind, payload });
|
|
12576
|
+
},
|
|
12577
|
+
async close() {
|
|
12578
|
+
if (!runStream) return;
|
|
12579
|
+
const drainTimeout = new Promise((resolve) => {
|
|
12580
|
+
const timer = setTimeout(() => resolve(), 1e4);
|
|
12581
|
+
timer.unref();
|
|
12582
|
+
});
|
|
12583
|
+
await Promise.race([runStream.whenTerminated(), drainTimeout]);
|
|
12584
|
+
await runStream.close("done");
|
|
12077
12585
|
}
|
|
12078
12586
|
};
|
|
12079
12587
|
}
|
|
12080
12588
|
|
|
12081
12589
|
// src/app/dashboard/remoteRunExecutor.ts
|
|
12082
12590
|
var DEFAULT_MARKETPLACE_SLUG = "lespaceman/athena-workflow-marketplace";
|
|
12083
|
-
function
|
|
12591
|
+
function parseRemoteRunSpec(value) {
|
|
12084
12592
|
if (typeof value !== "object" || value === null) return null;
|
|
12085
12593
|
const obj = value;
|
|
12086
12594
|
const prompt = obj["prompt"];
|
|
@@ -12112,6 +12620,9 @@ function parseRunSpec(value) {
|
|
|
12112
12620
|
callbackToken: typeof callbackToken === "string" && callbackToken.length > 0 ? callbackToken : void 0
|
|
12113
12621
|
};
|
|
12114
12622
|
}
|
|
12623
|
+
function isRemoteAssignmentAdmissible(frame) {
|
|
12624
|
+
return parseRemoteRunSpec(frame.runSpec) !== null;
|
|
12625
|
+
}
|
|
12115
12626
|
function workflowNameFromRef(ref) {
|
|
12116
12627
|
if (!ref) return void 0;
|
|
12117
12628
|
const [name] = ref.split("@", 1);
|
|
@@ -12212,57 +12723,22 @@ async function executeRemoteAssignment({
|
|
|
12212
12723
|
const deferredFailedCompletion = {
|
|
12213
12724
|
current: null
|
|
12214
12725
|
};
|
|
12215
|
-
const spec =
|
|
12216
|
-
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
|
|
12222
|
-
|
|
12223
|
-
|
|
12224
|
-
|
|
12225
|
-
|
|
12226
|
-
t.unref();
|
|
12227
|
-
});
|
|
12228
|
-
try {
|
|
12229
|
-
const result = await Promise.race([
|
|
12230
|
-
connect2.connect().then(() => "connected"),
|
|
12231
|
-
timeoutPromise
|
|
12232
|
-
]);
|
|
12233
|
-
if (result === "connected") {
|
|
12234
|
-
runStream = connect2;
|
|
12235
|
-
} else {
|
|
12236
|
-
log(
|
|
12237
|
-
"warn",
|
|
12238
|
-
`run-stream[${frame.runId}]: connect timed out after ${runStreamConnectTimeoutMs}ms; falling back to instance-socket relay`
|
|
12239
|
-
);
|
|
12240
|
-
void connect2.close("connect_timeout");
|
|
12241
|
-
}
|
|
12242
|
-
} catch (err) {
|
|
12243
|
-
log(
|
|
12244
|
-
"warn",
|
|
12245
|
-
`run-stream[${frame.runId}]: connect failed (${err instanceof Error ? err.message : String(err)}); falling back to instance-socket relay`
|
|
12246
|
-
);
|
|
12247
|
-
}
|
|
12248
|
-
}
|
|
12249
|
-
let legacySeq = 0;
|
|
12726
|
+
const spec = parseRemoteRunSpec(frame.runSpec);
|
|
12727
|
+
const runEventPublisher = await createRemoteRunEventPublisher({
|
|
12728
|
+
runId: frame.runId,
|
|
12729
|
+
callbackWsUrl: spec?.callbackWsUrl,
|
|
12730
|
+
callbackToken: spec?.callbackToken,
|
|
12731
|
+
client,
|
|
12732
|
+
log,
|
|
12733
|
+
now,
|
|
12734
|
+
createRunStreamClient: createRunStreamClientFn,
|
|
12735
|
+
runStreamConnectTimeoutMs
|
|
12736
|
+
});
|
|
12250
12737
|
const send = (kind, payload, ts = now()) => {
|
|
12251
12738
|
if (kind === "error" && typeof payload === "object" && payload !== null && typeof payload.message === "string") {
|
|
12252
12739
|
lastTerminalFailureMessage.current = payload.message;
|
|
12253
12740
|
}
|
|
12254
|
-
|
|
12255
|
-
runStream.sendEvent({ ts, kind, payload });
|
|
12256
|
-
return;
|
|
12257
|
-
}
|
|
12258
|
-
legacySeq += 1;
|
|
12259
|
-
client.sendRunEvent({
|
|
12260
|
-
runId: frame.runId,
|
|
12261
|
-
seq: legacySeq,
|
|
12262
|
-
ts,
|
|
12263
|
-
kind,
|
|
12264
|
-
payload
|
|
12265
|
-
});
|
|
12741
|
+
runEventPublisher.publish(kind, payload, ts);
|
|
12266
12742
|
};
|
|
12267
12743
|
send("progress", { message: "assignment received" });
|
|
12268
12744
|
try {
|
|
@@ -12396,15 +12872,202 @@ async function executeRemoteAssignment({
|
|
|
12396
12872
|
});
|
|
12397
12873
|
}
|
|
12398
12874
|
} finally {
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12402
|
-
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12875
|
+
await runEventPublisher.close();
|
|
12876
|
+
}
|
|
12877
|
+
}
|
|
12878
|
+
|
|
12879
|
+
// src/infra/config/attachmentMirror.ts
|
|
12880
|
+
import crypto3 from "crypto";
|
|
12881
|
+
import fs21 from "fs";
|
|
12882
|
+
import os12 from "os";
|
|
12883
|
+
import path19 from "path";
|
|
12884
|
+
function attachmentMirrorPath(env = process.env) {
|
|
12885
|
+
const home = env["HOME"] ?? os12.homedir();
|
|
12886
|
+
return path19.join(home, ".config", "athena", "attachments.json");
|
|
12887
|
+
}
|
|
12888
|
+
function readAttachmentMirror(env = process.env) {
|
|
12889
|
+
const file = attachmentMirrorPath(env);
|
|
12890
|
+
let raw;
|
|
12891
|
+
try {
|
|
12892
|
+
raw = fs21.readFileSync(file, "utf-8");
|
|
12893
|
+
} catch (err) {
|
|
12894
|
+
if (err.code === "ENOENT") return null;
|
|
12895
|
+
throw err;
|
|
12896
|
+
}
|
|
12897
|
+
let parsed;
|
|
12898
|
+
try {
|
|
12899
|
+
parsed = JSON.parse(raw);
|
|
12900
|
+
} catch (err) {
|
|
12901
|
+
throw new Error(
|
|
12902
|
+
`attachment mirror ${file} is invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
12903
|
+
);
|
|
12904
|
+
}
|
|
12905
|
+
try {
|
|
12906
|
+
return parseAttachmentMirror(parsed);
|
|
12907
|
+
} catch (err) {
|
|
12908
|
+
throw new Error(
|
|
12909
|
+
`attachment mirror ${file} is invalid: ${err instanceof Error ? err.message : String(err)}`
|
|
12910
|
+
);
|
|
12911
|
+
}
|
|
12912
|
+
}
|
|
12913
|
+
function writeAttachmentMirror(mirror, env = process.env) {
|
|
12914
|
+
const validated = parseAttachmentMirror(mirror);
|
|
12915
|
+
const file = attachmentMirrorPath(env);
|
|
12916
|
+
const dir = path19.dirname(file);
|
|
12917
|
+
fs21.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
12918
|
+
const tmp = `${file}.${process.pid}.${crypto3.randomBytes(4).toString("hex")}.tmp`;
|
|
12919
|
+
const fd = fs21.openSync(tmp, "w", 384);
|
|
12920
|
+
try {
|
|
12921
|
+
fs21.writeSync(fd, JSON.stringify(validated, null, 2) + "\n");
|
|
12922
|
+
fs21.fsyncSync(fd);
|
|
12923
|
+
} finally {
|
|
12924
|
+
fs21.closeSync(fd);
|
|
12925
|
+
}
|
|
12926
|
+
try {
|
|
12927
|
+
fs21.renameSync(tmp, file);
|
|
12928
|
+
} catch (err) {
|
|
12929
|
+
try {
|
|
12930
|
+
fs21.unlinkSync(tmp);
|
|
12931
|
+
} catch {
|
|
12932
|
+
}
|
|
12933
|
+
throw err;
|
|
12934
|
+
}
|
|
12935
|
+
if (process.platform !== "win32") {
|
|
12936
|
+
try {
|
|
12937
|
+
fs21.chmodSync(dir, 448);
|
|
12938
|
+
fs21.chmodSync(file, 384);
|
|
12939
|
+
} catch {
|
|
12940
|
+
}
|
|
12941
|
+
}
|
|
12942
|
+
}
|
|
12943
|
+
function removeAttachmentMirror(env = process.env) {
|
|
12944
|
+
const file = attachmentMirrorPath(env);
|
|
12945
|
+
try {
|
|
12946
|
+
fs21.unlinkSync(file);
|
|
12947
|
+
} catch (err) {
|
|
12948
|
+
if (err.code !== "ENOENT") throw err;
|
|
12949
|
+
}
|
|
12950
|
+
}
|
|
12951
|
+
function parseAttachmentMirror(raw) {
|
|
12952
|
+
if (typeof raw !== "object" || raw === null) {
|
|
12953
|
+
throw new Error("root must be an object");
|
|
12954
|
+
}
|
|
12955
|
+
const obj = raw;
|
|
12956
|
+
if (typeof obj["instanceId"] !== "string" || obj["instanceId"].length === 0) {
|
|
12957
|
+
throw new Error("instanceId must be a non-empty string");
|
|
12958
|
+
}
|
|
12959
|
+
if (typeof obj["fetchedAt"] !== "number") {
|
|
12960
|
+
throw new Error("fetchedAt must be a number");
|
|
12961
|
+
}
|
|
12962
|
+
if (!Array.isArray(obj["attachments"])) {
|
|
12963
|
+
throw new Error("attachments must be an array");
|
|
12964
|
+
}
|
|
12965
|
+
const attachments = obj["attachments"].map((entry, idx) => {
|
|
12966
|
+
if (typeof entry !== "object" || entry === null) {
|
|
12967
|
+
throw new Error(`attachments[${idx}] must be an object`);
|
|
12968
|
+
}
|
|
12969
|
+
const e = entry;
|
|
12970
|
+
if (typeof e["runnerId"] !== "string" || e["runnerId"].length === 0) {
|
|
12971
|
+
throw new Error(
|
|
12972
|
+
`attachments[${idx}].runnerId must be a non-empty string`
|
|
12973
|
+
);
|
|
12974
|
+
}
|
|
12975
|
+
const out = { runnerId: e["runnerId"] };
|
|
12976
|
+
if (typeof e["name"] === "string") out.name = e["name"];
|
|
12977
|
+
if (typeof e["executionTarget"] === "string") {
|
|
12978
|
+
out.executionTarget = e["executionTarget"];
|
|
12979
|
+
}
|
|
12980
|
+
if (typeof e["remoteInstanceId"] === "string") {
|
|
12981
|
+
out.remoteInstanceId = e["remoteInstanceId"];
|
|
12982
|
+
}
|
|
12983
|
+
return out;
|
|
12984
|
+
});
|
|
12985
|
+
return {
|
|
12986
|
+
instanceId: obj["instanceId"],
|
|
12987
|
+
fetchedAt: obj["fetchedAt"],
|
|
12988
|
+
attachments
|
|
12989
|
+
};
|
|
12990
|
+
}
|
|
12991
|
+
|
|
12992
|
+
// src/app/dashboard/attachmentReconciler.ts
|
|
12993
|
+
async function fetchDashboardAttachments({
|
|
12994
|
+
dashboardUrl,
|
|
12995
|
+
instanceId,
|
|
12996
|
+
accessToken
|
|
12997
|
+
}) {
|
|
12998
|
+
const url = new URL(dashboardUrl);
|
|
12999
|
+
url.pathname = `/api/instances/${encodeURIComponent(instanceId)}/attachments`;
|
|
13000
|
+
url.search = "";
|
|
13001
|
+
url.hash = "";
|
|
13002
|
+
const response = await fetch(url, {
|
|
13003
|
+
headers: {
|
|
13004
|
+
authorization: `Bearer ${accessToken}`,
|
|
13005
|
+
accept: "application/json"
|
|
13006
|
+
}
|
|
13007
|
+
});
|
|
13008
|
+
if (!response.ok) {
|
|
13009
|
+
throw new Error(
|
|
13010
|
+
`attachment reconciliation failed: ${response.status} ${response.statusText}`
|
|
13011
|
+
);
|
|
13012
|
+
}
|
|
13013
|
+
const body = await response.json();
|
|
13014
|
+
if (!Array.isArray(body.attachments)) {
|
|
13015
|
+
throw new Error("attachment reconciliation failed: invalid response");
|
|
13016
|
+
}
|
|
13017
|
+
return normalizeAttachments(body.attachments);
|
|
13018
|
+
}
|
|
13019
|
+
function normalizeAttachments(raw) {
|
|
13020
|
+
return raw.map((value, idx) => {
|
|
13021
|
+
if (typeof value !== "object" || value === null) {
|
|
13022
|
+
throw new Error(`attachments[${idx}] must be an object`);
|
|
13023
|
+
}
|
|
13024
|
+
const entry = value;
|
|
13025
|
+
if (typeof entry["runnerId"] !== "string" || entry["runnerId"].length === 0) {
|
|
13026
|
+
throw new Error(
|
|
13027
|
+
`attachments[${idx}].runnerId must be a non-empty string`
|
|
13028
|
+
);
|
|
12406
13029
|
}
|
|
13030
|
+
return {
|
|
13031
|
+
runnerId: entry["runnerId"],
|
|
13032
|
+
...typeof entry["name"] === "string" ? { name: entry["name"] } : {},
|
|
13033
|
+
...typeof entry["executionTarget"] === "string" ? { executionTarget: entry["executionTarget"] } : {},
|
|
13034
|
+
...typeof entry["remoteInstanceId"] === "string" ? { remoteInstanceId: entry["remoteInstanceId"] } : {}
|
|
13035
|
+
};
|
|
13036
|
+
});
|
|
13037
|
+
}
|
|
13038
|
+
function createAttachmentReconciler(options) {
|
|
13039
|
+
const fetchAttachments = options.fetchAttachments ?? fetchDashboardAttachments;
|
|
13040
|
+
const now = options.now ?? (() => Date.now());
|
|
13041
|
+
const currentInstances = /* @__PURE__ */ new Set();
|
|
13042
|
+
let pushRevision = 0;
|
|
13043
|
+
const latestPushByInstance = /* @__PURE__ */ new Map();
|
|
13044
|
+
function write(instanceId, attachments) {
|
|
13045
|
+
options.writeMirror({ instanceId, fetchedAt: now(), attachments });
|
|
12407
13046
|
}
|
|
13047
|
+
return {
|
|
13048
|
+
async reconcileNow(input) {
|
|
13049
|
+
const revisionAtStart = pushRevision;
|
|
13050
|
+
const attachments = await fetchAttachments(input);
|
|
13051
|
+
write(input.instanceId, attachments);
|
|
13052
|
+
if (pushRevision !== revisionAtStart) {
|
|
13053
|
+
const latestPush = latestPushByInstance.get(input.instanceId);
|
|
13054
|
+
if (latestPush) write(input.instanceId, latestPush);
|
|
13055
|
+
}
|
|
13056
|
+
currentInstances.add(input.instanceId);
|
|
13057
|
+
},
|
|
13058
|
+
applyPush({ instanceId, attachments }) {
|
|
13059
|
+
pushRevision += 1;
|
|
13060
|
+
latestPushByInstance.set(instanceId, attachments);
|
|
13061
|
+
write(instanceId, attachments);
|
|
13062
|
+
currentInstances.add(instanceId);
|
|
13063
|
+
},
|
|
13064
|
+
isCurrent(instanceId) {
|
|
13065
|
+
return currentInstances.has(instanceId);
|
|
13066
|
+
},
|
|
13067
|
+
markStale(instanceId) {
|
|
13068
|
+
currentInstances.delete(instanceId);
|
|
13069
|
+
}
|
|
13070
|
+
};
|
|
12408
13071
|
}
|
|
12409
13072
|
|
|
12410
13073
|
// src/app/dashboard/dashboardDecisionInbox.ts
|
|
@@ -12557,29 +13220,15 @@ function createDashboardPairedExecution(options) {
|
|
|
12557
13220
|
runHistory.shift();
|
|
12558
13221
|
}
|
|
12559
13222
|
}
|
|
12560
|
-
function rejectAssignment(runId,
|
|
12561
|
-
try {
|
|
12562
|
-
client.sendRunEvent({
|
|
12563
|
-
runId,
|
|
12564
|
-
seq: 0,
|
|
12565
|
-
ts: now(),
|
|
12566
|
-
kind: "rejected",
|
|
12567
|
-
payload: { reason }
|
|
12568
|
-
});
|
|
12569
|
-
} catch (err) {
|
|
12570
|
-
log(
|
|
12571
|
-
"warn",
|
|
12572
|
-
`runtime daemon: failed to send rejected for ${runId}: ${err instanceof Error ? err.message : String(err)}`
|
|
12573
|
-
);
|
|
12574
|
-
}
|
|
13223
|
+
function rejectAssignment(runId, rejection) {
|
|
12575
13224
|
recordRun({
|
|
12576
13225
|
runId,
|
|
12577
13226
|
startedAt: now(),
|
|
12578
13227
|
endedAt: now(),
|
|
12579
13228
|
status: "rejected",
|
|
12580
|
-
error:
|
|
13229
|
+
error: rejection.message
|
|
12581
13230
|
});
|
|
12582
|
-
log("warn", `run ${runId} rejected: ${
|
|
13231
|
+
log("warn", `run ${runId} rejected: ${rejection.message}`);
|
|
12583
13232
|
}
|
|
12584
13233
|
function handleDecision(frame) {
|
|
12585
13234
|
decisionInbox.enqueue({
|
|
@@ -12588,6 +13237,10 @@ function createDashboardPairedExecution(options) {
|
|
|
12588
13237
|
decision: frame.decision,
|
|
12589
13238
|
receivedAt: now()
|
|
12590
13239
|
});
|
|
13240
|
+
client.sendDecisionAck({
|
|
13241
|
+
athenaSessionId: frame.athenaSessionId,
|
|
13242
|
+
requestId: frame.requestId
|
|
13243
|
+
});
|
|
12591
13244
|
}
|
|
12592
13245
|
function handleCancel(frame) {
|
|
12593
13246
|
const entry = active.get(frame.runId);
|
|
@@ -12597,20 +13250,22 @@ function createDashboardPairedExecution(options) {
|
|
|
12597
13250
|
}
|
|
12598
13251
|
function handleAssignment(frame) {
|
|
12599
13252
|
if (active.has(frame.runId)) {
|
|
12600
|
-
|
|
12601
|
-
|
|
12602
|
-
`duplicate active assignment ${frame.runId}`
|
|
12603
|
-
|
|
12604
|
-
|
|
13253
|
+
const rejection = {
|
|
13254
|
+
reason: "duplicate",
|
|
13255
|
+
message: `duplicate active assignment ${frame.runId}`
|
|
13256
|
+
};
|
|
13257
|
+
rejectAssignment(frame.runId, rejection);
|
|
13258
|
+
return { kind: "rejected", rejection };
|
|
12605
13259
|
}
|
|
12606
13260
|
const runnerKey = frame.runnerId;
|
|
12607
13261
|
const bucket = activeByRunner.get(runnerKey) ?? /* @__PURE__ */ new Set();
|
|
12608
13262
|
if (bucket.size >= maxConcurrentRuns) {
|
|
12609
|
-
|
|
12610
|
-
|
|
12611
|
-
`runtime daemon at concurrency cap (${maxConcurrentRuns}) for runner ${runnerKey ?? "<legacy>"}`
|
|
12612
|
-
|
|
12613
|
-
|
|
13263
|
+
const rejection = {
|
|
13264
|
+
reason: "local_capacity",
|
|
13265
|
+
message: `runtime daemon at concurrency cap (${maxConcurrentRuns}) for runner ${runnerKey ?? "<legacy>"}`
|
|
13266
|
+
};
|
|
13267
|
+
rejectAssignment(frame.runId, rejection);
|
|
13268
|
+
return { kind: "rejected", rejection };
|
|
12614
13269
|
}
|
|
12615
13270
|
const controller = new AbortController();
|
|
12616
13271
|
const record = {
|
|
@@ -12650,6 +13305,7 @@ function createDashboardPairedExecution(options) {
|
|
|
12650
13305
|
}
|
|
12651
13306
|
});
|
|
12652
13307
|
active.set(frame.runId, { controller, promise, record, runnerKey });
|
|
13308
|
+
return { kind: "accepted" };
|
|
12653
13309
|
}
|
|
12654
13310
|
return {
|
|
12655
13311
|
handleFrame(frame) {
|
|
@@ -12667,6 +13323,10 @@ function createDashboardPairedExecution(options) {
|
|
|
12667
13323
|
}
|
|
12668
13324
|
return false;
|
|
12669
13325
|
},
|
|
13326
|
+
admitAssignment(frame) {
|
|
13327
|
+
return handleAssignment(frame);
|
|
13328
|
+
},
|
|
13329
|
+
rejectAssignment,
|
|
12670
13330
|
snapshot() {
|
|
12671
13331
|
return {
|
|
12672
13332
|
activeRuns: active.size,
|
|
@@ -12692,6 +13352,64 @@ function createDashboardPairedExecution(options) {
|
|
|
12692
13352
|
};
|
|
12693
13353
|
}
|
|
12694
13354
|
|
|
13355
|
+
// src/app/dashboard/dashboardAssignmentIntake.ts
|
|
13356
|
+
function createDashboardAssignmentIntake(options) {
|
|
13357
|
+
const log = options.log ?? (() => {
|
|
13358
|
+
});
|
|
13359
|
+
const pending = [];
|
|
13360
|
+
let ready = false;
|
|
13361
|
+
function handle(frame) {
|
|
13362
|
+
if (!isRemoteAssignmentAdmissible(frame)) {
|
|
13363
|
+
const rejection = {
|
|
13364
|
+
reason: "malformed_assignment",
|
|
13365
|
+
message: "remote assignment missing prompt"
|
|
13366
|
+
};
|
|
13367
|
+
options.execution.rejectAssignment(frame.runId, rejection);
|
|
13368
|
+
options.client.sendAssignmentRejected({
|
|
13369
|
+
runId: frame.runId,
|
|
13370
|
+
...rejection
|
|
13371
|
+
});
|
|
13372
|
+
return;
|
|
13373
|
+
}
|
|
13374
|
+
const outcome = options.execution.admitAssignment(frame);
|
|
13375
|
+
if (outcome.kind === "accepted") {
|
|
13376
|
+
options.client.sendAssignmentAccepted(frame.runId);
|
|
13377
|
+
return;
|
|
13378
|
+
}
|
|
13379
|
+
options.client.sendAssignmentRejected({
|
|
13380
|
+
runId: frame.runId,
|
|
13381
|
+
...outcome.rejection
|
|
13382
|
+
});
|
|
13383
|
+
}
|
|
13384
|
+
function drain() {
|
|
13385
|
+
if (!ready) return;
|
|
13386
|
+
while (pending.length > 0) {
|
|
13387
|
+
const frame = pending.shift();
|
|
13388
|
+
if (frame) handle(frame);
|
|
13389
|
+
}
|
|
13390
|
+
}
|
|
13391
|
+
return {
|
|
13392
|
+
receive(frame) {
|
|
13393
|
+
if (!ready) {
|
|
13394
|
+
pending.push(frame);
|
|
13395
|
+
log(
|
|
13396
|
+
"debug",
|
|
13397
|
+
`dashboard assignment buffered until attachments are current: runId=${frame.runId}`
|
|
13398
|
+
);
|
|
13399
|
+
return;
|
|
13400
|
+
}
|
|
13401
|
+
handle(frame);
|
|
13402
|
+
},
|
|
13403
|
+
markReady() {
|
|
13404
|
+
ready = true;
|
|
13405
|
+
drain();
|
|
13406
|
+
},
|
|
13407
|
+
markNotReady() {
|
|
13408
|
+
ready = false;
|
|
13409
|
+
}
|
|
13410
|
+
};
|
|
13411
|
+
}
|
|
13412
|
+
|
|
12695
13413
|
// src/app/dashboard/runtimeDaemon.ts
|
|
12696
13414
|
var DEFAULT_RECONNECT_DELAYS_MS2 = [1e3, 2e3, 5e3, 1e4, 3e4];
|
|
12697
13415
|
var DEFAULT_MAX_CONCURRENT_RUNS2 = 1;
|
|
@@ -12700,7 +13418,6 @@ var DEFAULT_REFRESH_FAILURE_LIMIT = 5;
|
|
|
12700
13418
|
var DEFAULT_REFRESH_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
12701
13419
|
var DEFAULT_REFRESH_COOLDOWN_MS = 5 * 6e4;
|
|
12702
13420
|
var DEFAULT_RUN_HISTORY_LIMIT2 = 100;
|
|
12703
|
-
var DEFAULT_FEED_DRAIN_INTERVAL_MS = 1e3;
|
|
12704
13421
|
function delay(ms) {
|
|
12705
13422
|
return new Promise((resolve) => {
|
|
12706
13423
|
const timer = setTimeout(resolve, ms);
|
|
@@ -12729,9 +13446,12 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12729
13446
|
const runHistoryLimit = options.runHistoryLimit ?? DEFAULT_RUN_HISTORY_LIMIT2;
|
|
12730
13447
|
const now = options.now ?? (() => Date.now());
|
|
12731
13448
|
const writeMirror = options.writeMirror ?? writeAttachmentMirror;
|
|
12732
|
-
const
|
|
13449
|
+
const pairedFeedPublisher = options.pairedFeedPublisher ?? createPairedFeedPublisher({
|
|
13450
|
+
readConfig: readConfig2,
|
|
13451
|
+
now,
|
|
13452
|
+
drainIntervalMs: options.feedDrainIntervalMs
|
|
13453
|
+
});
|
|
12733
13454
|
const decisionInbox = options.decisionInbox ?? createDashboardDecisionInbox();
|
|
12734
|
-
const feedDrainIntervalMs = options.feedDrainIntervalMs ?? DEFAULT_FEED_DRAIN_INTERVAL_MS;
|
|
12735
13455
|
const retryInitialConnect = options.retryInitialConnect ?? true;
|
|
12736
13456
|
const startedAt = now();
|
|
12737
13457
|
let stopped = false;
|
|
@@ -12742,7 +13462,6 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12742
13462
|
let currentDashboardUrl;
|
|
12743
13463
|
let lastFrameAt;
|
|
12744
13464
|
let refreshTimer = null;
|
|
12745
|
-
let feedDrainTimer = null;
|
|
12746
13465
|
const refreshFailures = [];
|
|
12747
13466
|
let cooldownUntil = 0;
|
|
12748
13467
|
const executionClient = {
|
|
@@ -12756,6 +13475,11 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12756
13475
|
return;
|
|
12757
13476
|
}
|
|
12758
13477
|
current.sendRunEvent(event);
|
|
13478
|
+
},
|
|
13479
|
+
sendDecisionAck(input) {
|
|
13480
|
+
const current = client;
|
|
13481
|
+
if (!current) return;
|
|
13482
|
+
current.sendDecisionAck(input);
|
|
12759
13483
|
}
|
|
12760
13484
|
};
|
|
12761
13485
|
const pairedExecution = createDashboardPairedExecution({
|
|
@@ -12768,6 +13492,27 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12768
13492
|
now,
|
|
12769
13493
|
runHistoryLimit
|
|
12770
13494
|
});
|
|
13495
|
+
const attachmentReconciler = createAttachmentReconciler({
|
|
13496
|
+
writeMirror,
|
|
13497
|
+
...options.fetchAttachments ? { fetchAttachments: options.fetchAttachments } : {},
|
|
13498
|
+
now
|
|
13499
|
+
});
|
|
13500
|
+
const assignmentIntake = createDashboardAssignmentIntake({
|
|
13501
|
+
client: {
|
|
13502
|
+
sendAssignmentAccepted(runId) {
|
|
13503
|
+
const current = client;
|
|
13504
|
+
if (!current) return;
|
|
13505
|
+
current.sendAssignmentAccepted(runId);
|
|
13506
|
+
},
|
|
13507
|
+
sendAssignmentRejected(input) {
|
|
13508
|
+
const current = client;
|
|
13509
|
+
if (!current) return;
|
|
13510
|
+
current.sendAssignmentRejected(input);
|
|
13511
|
+
}
|
|
13512
|
+
},
|
|
13513
|
+
execution: pairedExecution,
|
|
13514
|
+
log
|
|
13515
|
+
});
|
|
12771
13516
|
function nextReconnectDelay() {
|
|
12772
13517
|
if (reconnectDelays.length === 0) return 0;
|
|
12773
13518
|
const delayMs = reconnectDelays[Math.min(reconnectAttempt, reconnectDelays.length - 1)] ?? 0;
|
|
@@ -12780,35 +13525,6 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12780
13525
|
refreshTimer = null;
|
|
12781
13526
|
}
|
|
12782
13527
|
}
|
|
12783
|
-
function clearFeedDrainTimer() {
|
|
12784
|
-
if (feedDrainTimer) {
|
|
12785
|
-
clearInterval(feedDrainTimer);
|
|
12786
|
-
feedDrainTimer = null;
|
|
12787
|
-
}
|
|
12788
|
-
}
|
|
12789
|
-
function drainFeedOutbox() {
|
|
12790
|
-
const current = client;
|
|
12791
|
-
if (!current) return;
|
|
12792
|
-
const rows = feedOutbox.pendingBatch({ limit: 100, now: now() });
|
|
12793
|
-
for (const row of rows) {
|
|
12794
|
-
current.sendFeedEvent({
|
|
12795
|
-
deliverySeq: row.deliverySeq,
|
|
12796
|
-
envelope: row.envelope
|
|
12797
|
-
});
|
|
12798
|
-
const retryDelayMs = Math.min(3e4, (row.attempt + 1) * 1e3);
|
|
12799
|
-
feedOutbox.markAttempted({
|
|
12800
|
-
deliverySeq: row.deliverySeq,
|
|
12801
|
-
nextAttemptAt: now() + retryDelayMs
|
|
12802
|
-
});
|
|
12803
|
-
}
|
|
12804
|
-
}
|
|
12805
|
-
function startFeedDrainTimer() {
|
|
12806
|
-
clearFeedDrainTimer();
|
|
12807
|
-
const timer = setInterval(drainFeedOutbox, feedDrainIntervalMs);
|
|
12808
|
-
timer.unref();
|
|
12809
|
-
feedDrainTimer = timer;
|
|
12810
|
-
drainFeedOutbox();
|
|
12811
|
-
}
|
|
12812
13528
|
function scheduleRefresh(expiresInSec) {
|
|
12813
13529
|
clearRefreshTimer();
|
|
12814
13530
|
if (!Number.isFinite(expiresInSec) || expiresInSec <= refreshLeadSec) {
|
|
@@ -12889,9 +13605,8 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12889
13605
|
lastFrameAt = now();
|
|
12890
13606
|
if (frame.type === "attachments.changed") {
|
|
12891
13607
|
try {
|
|
12892
|
-
|
|
13608
|
+
attachmentReconciler.applyPush({
|
|
12893
13609
|
instanceId: token.instanceId,
|
|
12894
|
-
fetchedAt: now(),
|
|
12895
13610
|
attachments: frame.attachments.map((a) => ({
|
|
12896
13611
|
runnerId: a.runnerId,
|
|
12897
13612
|
...a.name !== void 0 ? { name: a.name } : {},
|
|
@@ -12908,10 +13623,11 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12908
13623
|
return;
|
|
12909
13624
|
}
|
|
12910
13625
|
if (frame.type === "feed_ack") {
|
|
12911
|
-
|
|
12912
|
-
|
|
12913
|
-
|
|
12914
|
-
|
|
13626
|
+
pairedFeedPublisher.handleAck(frame);
|
|
13627
|
+
return;
|
|
13628
|
+
}
|
|
13629
|
+
if (frame.type === "job_assignment") {
|
|
13630
|
+
assignmentIntake.receive(frame);
|
|
12915
13631
|
return;
|
|
12916
13632
|
}
|
|
12917
13633
|
pairedExecution.handleFrame(frame);
|
|
@@ -12920,19 +13636,35 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12920
13636
|
if (stopped || client !== next) return;
|
|
12921
13637
|
log("warn", `instance socket closed: ${reason}`);
|
|
12922
13638
|
client = null;
|
|
13639
|
+
assignmentIntake.markNotReady();
|
|
13640
|
+
attachmentReconciler.markStale(token.instanceId);
|
|
12923
13641
|
currentInstanceId = void 0;
|
|
12924
13642
|
clearRefreshTimer();
|
|
12925
|
-
|
|
13643
|
+
pairedFeedPublisher.detachTransport();
|
|
12926
13644
|
void reconnectLoop();
|
|
12927
13645
|
});
|
|
12928
13646
|
await next.connect();
|
|
12929
13647
|
client = next;
|
|
12930
13648
|
lastSocketClient = next;
|
|
13649
|
+
try {
|
|
13650
|
+
await attachmentReconciler.reconcileNow({
|
|
13651
|
+
dashboardUrl: config.dashboardUrl,
|
|
13652
|
+
instanceId: token.instanceId,
|
|
13653
|
+
accessToken: token.accessToken
|
|
13654
|
+
});
|
|
13655
|
+
} catch (err) {
|
|
13656
|
+
client = null;
|
|
13657
|
+
assignmentIntake.markNotReady();
|
|
13658
|
+
attachmentReconciler.markStale(token.instanceId);
|
|
13659
|
+
next.close("attachment reconciliation failed");
|
|
13660
|
+
throw err;
|
|
13661
|
+
}
|
|
13662
|
+
assignmentIntake.markReady();
|
|
12931
13663
|
currentInstanceId = token.instanceId;
|
|
12932
13664
|
currentDashboardUrl = config.dashboardUrl;
|
|
12933
13665
|
reconnectAttempt = 0;
|
|
12934
13666
|
scheduleRefresh(token.expiresInSec);
|
|
12935
|
-
|
|
13667
|
+
pairedFeedPublisher.attachTransport(next);
|
|
12936
13668
|
log("info", `dashboard runtime daemon connected as ${token.instanceId}`);
|
|
12937
13669
|
}
|
|
12938
13670
|
async function reconnectLoop() {
|
|
@@ -12987,7 +13719,7 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12987
13719
|
async stop(reason = "stopped") {
|
|
12988
13720
|
stopped = true;
|
|
12989
13721
|
clearRefreshTimer();
|
|
12990
|
-
|
|
13722
|
+
pairedFeedPublisher.close();
|
|
12991
13723
|
const current = client;
|
|
12992
13724
|
client = null;
|
|
12993
13725
|
current?.close(reason);
|
|
@@ -12996,8 +13728,99 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12996
13728
|
};
|
|
12997
13729
|
}
|
|
12998
13730
|
|
|
13731
|
+
// src/infra/daemon/pidLock.ts
|
|
13732
|
+
import fs22 from "fs";
|
|
13733
|
+
function acquirePidLock(pidPath) {
|
|
13734
|
+
const ownPid = process.pid;
|
|
13735
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
13736
|
+
try {
|
|
13737
|
+
const fd = fs22.openSync(pidPath, "wx", 384);
|
|
13738
|
+
try {
|
|
13739
|
+
fs22.writeSync(fd, `${ownPid}
|
|
13740
|
+
`);
|
|
13741
|
+
fs22.fsyncSync(fd);
|
|
13742
|
+
} finally {
|
|
13743
|
+
fs22.closeSync(fd);
|
|
13744
|
+
}
|
|
13745
|
+
return makeHandle(pidPath, ownPid);
|
|
13746
|
+
} catch (err) {
|
|
13747
|
+
if (err.code !== "EEXIST") throw err;
|
|
13748
|
+
}
|
|
13749
|
+
const existing = readPidLock(pidPath);
|
|
13750
|
+
if (existing.state === "held") {
|
|
13751
|
+
throw new Error(
|
|
13752
|
+
`dashboard daemon is already running as pid ${existing.pid} (lock at ${pidPath}). Use "drisp dashboard daemon stop" to terminate it.`
|
|
13753
|
+
);
|
|
13754
|
+
}
|
|
13755
|
+
if (existing.state === "stale") {
|
|
13756
|
+
try {
|
|
13757
|
+
fs22.unlinkSync(pidPath);
|
|
13758
|
+
} catch (err) {
|
|
13759
|
+
if (err.code !== "ENOENT") throw err;
|
|
13760
|
+
}
|
|
13761
|
+
continue;
|
|
13762
|
+
}
|
|
13763
|
+
}
|
|
13764
|
+
throw new Error(
|
|
13765
|
+
`dashboard daemon: failed to acquire pid lock at ${pidPath} after retry`
|
|
13766
|
+
);
|
|
13767
|
+
}
|
|
13768
|
+
function readPidLock(pidPath) {
|
|
13769
|
+
let raw;
|
|
13770
|
+
try {
|
|
13771
|
+
raw = fs22.readFileSync(pidPath, "utf-8");
|
|
13772
|
+
} catch (err) {
|
|
13773
|
+
if (err.code === "ENOENT") {
|
|
13774
|
+
return { state: "absent" };
|
|
13775
|
+
}
|
|
13776
|
+
throw err;
|
|
13777
|
+
}
|
|
13778
|
+
const pid = Number.parseInt(raw.trim(), 10);
|
|
13779
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
13780
|
+
return { state: "stale", pid: 0 };
|
|
13781
|
+
}
|
|
13782
|
+
if (!isProcessAlive(pid)) {
|
|
13783
|
+
return { state: "stale", pid };
|
|
13784
|
+
}
|
|
13785
|
+
return { state: "held", pid };
|
|
13786
|
+
}
|
|
13787
|
+
function makeHandle(pidPath, pid) {
|
|
13788
|
+
let released = false;
|
|
13789
|
+
return {
|
|
13790
|
+
pid,
|
|
13791
|
+
release() {
|
|
13792
|
+
if (released) return;
|
|
13793
|
+
released = true;
|
|
13794
|
+
try {
|
|
13795
|
+
const raw = fs22.readFileSync(pidPath, "utf-8").trim();
|
|
13796
|
+
if (raw === String(pid)) {
|
|
13797
|
+
fs22.unlinkSync(pidPath);
|
|
13798
|
+
}
|
|
13799
|
+
} catch (err) {
|
|
13800
|
+
if (err.code !== "ENOENT") {
|
|
13801
|
+
}
|
|
13802
|
+
}
|
|
13803
|
+
}
|
|
13804
|
+
};
|
|
13805
|
+
}
|
|
13806
|
+
function isProcessAlive(pid) {
|
|
13807
|
+
if (process.platform === "win32") {
|
|
13808
|
+
return true;
|
|
13809
|
+
}
|
|
13810
|
+
try {
|
|
13811
|
+
process.kill(pid, 0);
|
|
13812
|
+
return true;
|
|
13813
|
+
} catch (err) {
|
|
13814
|
+
const code = err.code;
|
|
13815
|
+
if (code === "EPERM") {
|
|
13816
|
+
return true;
|
|
13817
|
+
}
|
|
13818
|
+
return false;
|
|
13819
|
+
}
|
|
13820
|
+
}
|
|
13821
|
+
|
|
12999
13822
|
// src/infra/daemon/udsIpc.ts
|
|
13000
|
-
import
|
|
13823
|
+
import fs23 from "fs";
|
|
13001
13824
|
import net2 from "net";
|
|
13002
13825
|
|
|
13003
13826
|
// src/infra/daemon/udsFrameCodec.ts
|
|
@@ -13042,7 +13865,7 @@ async function startUdsServer(socketPath, handler, log) {
|
|
|
13042
13865
|
});
|
|
13043
13866
|
if (process.platform !== "win32") {
|
|
13044
13867
|
try {
|
|
13045
|
-
|
|
13868
|
+
fs23.chmodSync(socketPath, 384);
|
|
13046
13869
|
} catch {
|
|
13047
13870
|
}
|
|
13048
13871
|
}
|
|
@@ -13052,7 +13875,7 @@ async function startUdsServer(socketPath, handler, log) {
|
|
|
13052
13875
|
server.close(() => resolve());
|
|
13053
13876
|
});
|
|
13054
13877
|
try {
|
|
13055
|
-
|
|
13878
|
+
fs23.unlinkSync(socketPath);
|
|
13056
13879
|
} catch (err) {
|
|
13057
13880
|
if (err.code !== "ENOENT") {
|
|
13058
13881
|
}
|
|
@@ -13170,7 +13993,7 @@ async function sendUdsRequest(socketPath, request, options = {}) {
|
|
|
13170
13993
|
async function unlinkStaleSocket(socketPath) {
|
|
13171
13994
|
let stat;
|
|
13172
13995
|
try {
|
|
13173
|
-
stat =
|
|
13996
|
+
stat = fs23.statSync(socketPath);
|
|
13174
13997
|
} catch (err) {
|
|
13175
13998
|
if (err.code === "ENOENT") return;
|
|
13176
13999
|
throw err;
|
|
@@ -13197,7 +14020,7 @@ async function unlinkStaleSocket(socketPath) {
|
|
|
13197
14020
|
`uds path ${socketPath} is in use by another process; aborting`
|
|
13198
14021
|
);
|
|
13199
14022
|
}
|
|
13200
|
-
|
|
14023
|
+
fs23.unlinkSync(socketPath);
|
|
13201
14024
|
}
|
|
13202
14025
|
|
|
13203
14026
|
export {
|
|
@@ -13217,7 +14040,7 @@ export {
|
|
|
13217
14040
|
generateId,
|
|
13218
14041
|
daemonStatePaths,
|
|
13219
14042
|
ensureDaemonStateDir,
|
|
13220
|
-
|
|
14043
|
+
createPairedFeedPublisher,
|
|
13221
14044
|
createDashboardDecisionInbox,
|
|
13222
14045
|
createSessionStore,
|
|
13223
14046
|
sessionsDir,
|
|
@@ -13266,9 +14089,13 @@ export {
|
|
|
13266
14089
|
bootstrapRuntimeConfig,
|
|
13267
14090
|
EXEC_EXIT_CODE,
|
|
13268
14091
|
runExec,
|
|
13269
|
-
|
|
14092
|
+
readAttachmentMirror,
|
|
14093
|
+
writeAttachmentMirror,
|
|
14094
|
+
removeAttachmentMirror,
|
|
13270
14095
|
runDashboardRuntimeDaemon,
|
|
14096
|
+
acquirePidLock,
|
|
14097
|
+
readPidLock,
|
|
13271
14098
|
startUdsServer,
|
|
13272
14099
|
sendUdsRequest
|
|
13273
14100
|
};
|
|
13274
|
-
//# sourceMappingURL=chunk-
|
|
14101
|
+
//# sourceMappingURL=chunk-QVXHUJPH.js.map
|