@drisp/cli 0.5.2 → 0.5.6
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 +4130 -4
- package/dist/{chunk-A54HGVML.js → chunk-7E54JMXH.js} +126 -114
- package/dist/{chunk-PC46SGTK.js → chunk-ZU7M6YZW.js} +2054 -1110
- 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-JV7CRNTC.js +0 -406
- package/dist/chunk-LKLNEXTK.js +0 -4124
- 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-JV7CRNTC.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
|
-
|
|
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"]);
|
|
8497
8598
|
results.push(
|
|
8498
8599
|
makeEvent(
|
|
8499
|
-
"
|
|
8600
|
+
"permission.request",
|
|
8500
8601
|
"info",
|
|
8501
8602
|
"system",
|
|
8502
8603
|
{
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
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
|
|
8509
8614
|
},
|
|
8510
8615
|
event
|
|
8511
8616
|
)
|
|
8512
8617
|
);
|
|
8513
|
-
|
|
8618
|
+
return results;
|
|
8514
8619
|
}
|
|
8515
|
-
|
|
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": {
|
|
8620
|
+
if (event.kind === "stop.request") {
|
|
8544
8621
|
results.push(
|
|
8545
8622
|
makeEvent(
|
|
8546
|
-
"
|
|
8623
|
+
"stop.request",
|
|
8547
8624
|
"info",
|
|
8548
|
-
"
|
|
8625
|
+
"agent:root",
|
|
8549
8626
|
{
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8627
|
+
stop_hook_active: readBoolean(data["stop_hook_active"]) ?? false,
|
|
8628
|
+
last_assistant_message: readString(
|
|
8629
|
+
data["last_assistant_message"]
|
|
8630
|
+
)
|
|
8554
8631
|
},
|
|
8555
8632
|
event
|
|
8556
8633
|
)
|
|
8557
8634
|
);
|
|
8558
|
-
|
|
8635
|
+
return results;
|
|
8559
8636
|
}
|
|
8560
|
-
|
|
8561
|
-
results.push(...ensureRunArray(event));
|
|
8562
|
-
const toolUseId = resolveToolUseId(event, d);
|
|
8563
|
-
const toolName = event.toolName ?? readString(d["tool_name"]) ?? "Unknown";
|
|
8564
|
-
const parentId = toolCorrelation.lookupParent(toolUseId);
|
|
8565
|
-
const chunk = readString(d["delta"]) ?? "";
|
|
8566
|
-
const cumulative = toolCorrelation.appendDelta(toolUseId, chunk);
|
|
8637
|
+
if (event.kind === "stop.failure") {
|
|
8567
8638
|
results.push(
|
|
8568
8639
|
makeEvent(
|
|
8569
|
-
"
|
|
8570
|
-
"
|
|
8571
|
-
|
|
8640
|
+
"stop.failure",
|
|
8641
|
+
"error",
|
|
8642
|
+
"system",
|
|
8572
8643
|
{
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
tool_use_id: toolUseId,
|
|
8576
|
-
delta: cumulative
|
|
8644
|
+
error_type: readString(data["error_type"]) ?? "unknown",
|
|
8645
|
+
error_message: readString(data["error_message"])
|
|
8577
8646
|
},
|
|
8578
|
-
event
|
|
8579
|
-
toolUseCause(toolUseId, parentId)
|
|
8647
|
+
event
|
|
8580
8648
|
)
|
|
8581
8649
|
);
|
|
8582
|
-
|
|
8650
|
+
return results;
|
|
8583
8651
|
}
|
|
8584
|
-
|
|
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;
|
|
8639
|
-
}
|
|
8640
|
-
case "tool.post": {
|
|
8641
|
-
results.push(...ensureRunArray(event));
|
|
8642
|
-
const toolUseId = resolveToolUseId(event, d);
|
|
8643
|
-
if (toolUseId) toolCorrelation.forgetTool(toolUseId);
|
|
8644
|
-
const parentId = toolCorrelation.lookupParent(toolUseId);
|
|
8645
|
-
const toolName = event.toolName ?? readString(d["tool_name"]) ?? "Unknown";
|
|
8646
|
-
const postEvent = makeEvent(
|
|
8647
|
-
"tool.post",
|
|
8648
|
-
"info",
|
|
8649
|
-
resolveToolActor(),
|
|
8650
|
-
{
|
|
8651
|
-
tool_name: toolName,
|
|
8652
|
-
tool_input: readObject(d["tool_input"]),
|
|
8653
|
-
tool_use_id: toolUseId,
|
|
8654
|
-
tool_response: d.tool_response
|
|
8655
|
-
},
|
|
8656
|
-
event,
|
|
8657
|
-
toolUseCause(toolUseId, parentId)
|
|
8658
|
-
);
|
|
8659
|
-
results.push(postEvent);
|
|
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;
|
|
8689
|
-
}
|
|
8690
|
-
case "tool.failure": {
|
|
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";
|
|
8652
|
+
if (event.kind === "permission.denied") {
|
|
8697
8653
|
results.push(
|
|
8698
8654
|
makeEvent(
|
|
8699
|
-
"
|
|
8700
|
-
"
|
|
8701
|
-
|
|
8655
|
+
"permission.denied",
|
|
8656
|
+
"warn",
|
|
8657
|
+
"system",
|
|
8702
8658
|
{
|
|
8703
|
-
tool_name: toolName,
|
|
8704
|
-
tool_input: readObject(
|
|
8705
|
-
tool_use_id:
|
|
8706
|
-
|
|
8707
|
-
is_interrupt: readBoolean(d["is_interrupt"])
|
|
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"])
|
|
8708
8663
|
},
|
|
8709
|
-
event
|
|
8710
|
-
toolUseCause(toolUseId, parentId)
|
|
8664
|
+
event
|
|
8711
8665
|
)
|
|
8712
8666
|
);
|
|
8713
|
-
|
|
8667
|
+
return results;
|
|
8714
8668
|
}
|
|
8715
|
-
|
|
8716
|
-
results.push(...ensureRunArray(event));
|
|
8717
|
-
runLifecycle.incrementCounter("permission_requests");
|
|
8718
|
-
const toolName = event.toolName ?? readString(d["tool_name"]) ?? "Unknown";
|
|
8669
|
+
if (event.kind === "elicitation.request") {
|
|
8719
8670
|
results.push(
|
|
8720
8671
|
makeEvent(
|
|
8721
|
-
"
|
|
8722
|
-
"
|
|
8672
|
+
"elicitation.request",
|
|
8673
|
+
"warn",
|
|
8723
8674
|
"system",
|
|
8724
8675
|
{
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
tool_use_id: resolveToolUseId(event, d),
|
|
8728
|
-
permission_suggestions: readSuggestionArray(
|
|
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
|
|
8676
|
+
mcp_server: readString(data["mcp_server"]) ?? "unknown",
|
|
8677
|
+
form: data["form"]
|
|
8739
8678
|
},
|
|
8740
8679
|
event
|
|
8741
8680
|
)
|
|
8742
8681
|
);
|
|
8743
|
-
|
|
8682
|
+
return results;
|
|
8744
8683
|
}
|
|
8745
|
-
|
|
8746
|
-
|
|
8747
|
-
const
|
|
8748
|
-
"
|
|
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;
|
|
8994
|
+
return results;
|
|
9039
8995
|
}
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
const
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
8996
|
+
if (event.kind === "session.end") {
|
|
8997
|
+
agentMessageStream.clearPending();
|
|
8998
|
+
const closeEvt = closeRunIntoEvent(event, "completed");
|
|
8999
|
+
if (closeEvt) results.push(closeEvt);
|
|
9000
|
+
results.push(
|
|
9001
|
+
makeEvent(
|
|
9002
|
+
"session.end",
|
|
9003
|
+
"info",
|
|
9004
|
+
"system",
|
|
9005
|
+
{
|
|
9006
|
+
reason: readString(data["reason"]) ?? "unknown"
|
|
9007
|
+
},
|
|
9008
|
+
event
|
|
9009
|
+
)
|
|
9050
9010
|
);
|
|
9051
|
-
|
|
9052
|
-
results
|
|
9053
|
-
break;
|
|
9011
|
+
runLifecycle.endSession(event.timestamp);
|
|
9012
|
+
return results;
|
|
9054
9013
|
}
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
"
|
|
9059
|
-
"info",
|
|
9060
|
-
"system",
|
|
9061
|
-
{
|
|
9062
|
-
teammate_name: readString(d["teammate_name"]) ?? "",
|
|
9063
|
-
team_name: readString(d["team_name"]) ?? ""
|
|
9064
|
-
},
|
|
9065
|
-
event
|
|
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))
|
|
9066
9018
|
);
|
|
9067
|
-
idleEvt.ui = { collapsed_default: true };
|
|
9068
|
-
results.push(idleEvt);
|
|
9069
|
-
break;
|
|
9070
|
-
}
|
|
9071
|
-
case "task.completed": {
|
|
9072
|
-
results.push(...ensureRunArray(event));
|
|
9073
9019
|
results.push(
|
|
9074
9020
|
makeEvent(
|
|
9075
|
-
"
|
|
9021
|
+
"user.prompt",
|
|
9076
9022
|
"info",
|
|
9077
|
-
"
|
|
9023
|
+
"user",
|
|
9078
9024
|
{
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
teammate_name: readString(d["teammate_name"]),
|
|
9083
|
-
team_name: readString(d["team_name"])
|
|
9025
|
+
prompt,
|
|
9026
|
+
cwd: event.context.cwd,
|
|
9027
|
+
permission_mode: event.context.permissionMode ?? readString(data["permission_mode"])
|
|
9084
9028
|
},
|
|
9085
9029
|
event
|
|
9086
9030
|
)
|
|
9087
9031
|
);
|
|
9088
|
-
|
|
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;
|
|
9069
|
+
}
|
|
9070
|
+
if (event.kind === "message.complete") {
|
|
9071
|
+
results.push(...ensureRunArray(event));
|
|
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",
|
|
9089
|
+
"info",
|
|
9090
|
+
"agent:root",
|
|
9091
|
+
{
|
|
9092
|
+
stop_hook_active: false
|
|
9093
|
+
},
|
|
9094
|
+
event
|
|
9095
|
+
);
|
|
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;
|
|
9089
9108
|
}
|
|
9090
|
-
|
|
9091
|
-
|
|
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
|
+
}
|
|
9092
9134
|
results.push(
|
|
9093
9135
|
makeEvent(
|
|
9094
|
-
"
|
|
9136
|
+
"plan.update",
|
|
9095
9137
|
"info",
|
|
9096
9138
|
"system",
|
|
9097
9139
|
{
|
|
9098
|
-
|
|
9099
|
-
|
|
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
|
|
9100
9146
|
},
|
|
9101
9147
|
event
|
|
9102
9148
|
)
|
|
9103
9149
|
);
|
|
9104
|
-
|
|
9150
|
+
return results;
|
|
9105
9151
|
}
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
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;
|
|
9120
9180
|
}
|
|
9121
|
-
|
|
9122
|
-
results.push(...ensureRunArray(event));
|
|
9181
|
+
if (event.kind === "usage.update") {
|
|
9123
9182
|
results.push(
|
|
9124
9183
|
makeEvent(
|
|
9125
|
-
"
|
|
9184
|
+
"usage.update",
|
|
9126
9185
|
"info",
|
|
9127
9186
|
"system",
|
|
9128
9187
|
{
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
team_name: readString(d["team_name"])
|
|
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
|
|
9134
9192
|
},
|
|
9135
9193
|
event
|
|
9136
9194
|
)
|
|
9137
9195
|
);
|
|
9138
|
-
break;
|
|
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;
|
|
9154
9196
|
}
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
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",
|
|
9159
9211
|
"info",
|
|
9160
9212
|
"system",
|
|
9161
9213
|
{
|
|
9162
|
-
|
|
9214
|
+
teammate_name: readString(data["teammate_name"]) ?? "",
|
|
9215
|
+
team_name: readString(data["team_name"]) ?? ""
|
|
9163
9216
|
},
|
|
9164
9217
|
event
|
|
9165
9218
|
);
|
|
9166
|
-
|
|
9167
|
-
results.push(
|
|
9168
|
-
|
|
9169
|
-
}
|
|
9170
|
-
case "stop.failure": {
|
|
9171
|
-
results.push(...ensureRunArray(event));
|
|
9172
|
-
results.push(
|
|
9173
|
-
makeEvent(
|
|
9174
|
-
"stop.failure",
|
|
9175
|
-
"error",
|
|
9176
|
-
"system",
|
|
9177
|
-
{
|
|
9178
|
-
error_type: readString(d["error_type"]) ?? "unknown",
|
|
9179
|
-
error_message: readString(d["error_message"])
|
|
9180
|
-
},
|
|
9181
|
-
event
|
|
9182
|
-
)
|
|
9183
|
-
);
|
|
9184
|
-
break;
|
|
9219
|
+
idleEvt.ui = { collapsed_default: true };
|
|
9220
|
+
results.push(idleEvt);
|
|
9221
|
+
return results;
|
|
9185
9222
|
}
|
|
9186
|
-
|
|
9187
|
-
results.push(...ensureRunArray(event));
|
|
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;
|
|
@@ -12078,9 +12516,79 @@ function createRunStreamClient(opts) {
|
|
|
12078
12516
|
};
|
|
12079
12517
|
}
|
|
12080
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");
|
|
12585
|
+
}
|
|
12586
|
+
};
|
|
12587
|
+
}
|
|
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);
|
|
@@ -12193,7 +12704,7 @@ function mergeRunSpecEnvIntoWorkflow(workflow, env) {
|
|
|
12193
12704
|
async function executeRemoteAssignment({
|
|
12194
12705
|
frame,
|
|
12195
12706
|
client,
|
|
12196
|
-
projectDir
|
|
12707
|
+
projectDir,
|
|
12197
12708
|
log = () => {
|
|
12198
12709
|
},
|
|
12199
12710
|
runExecFn = runExec,
|
|
@@ -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
|
-
lastTerminalFailureMessage.current = payload.message;
|
|
12253
|
-
}
|
|
12254
|
-
if (runStream) {
|
|
12255
|
-
runStream.sendEvent({ ts, kind, payload });
|
|
12256
|
-
return;
|
|
12739
|
+
lastTerminalFailureMessage.current = payload.message;
|
|
12257
12740
|
}
|
|
12258
|
-
|
|
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 {
|
|
@@ -12270,7 +12746,6 @@ async function executeRemoteAssignment({
|
|
|
12270
12746
|
send("error", { message: "remote assignment missing prompt" });
|
|
12271
12747
|
return;
|
|
12272
12748
|
}
|
|
12273
|
-
const projectDir = spec.projectDir ?? fallbackProjectDir;
|
|
12274
12749
|
let runtimeConfig;
|
|
12275
12750
|
try {
|
|
12276
12751
|
const workflowOverride = ensureRemoteWorkflowInstalled({
|
|
@@ -12396,15 +12871,202 @@ async function executeRemoteAssignment({
|
|
|
12396
12871
|
});
|
|
12397
12872
|
}
|
|
12398
12873
|
} finally {
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12402
|
-
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12874
|
+
await runEventPublisher.close();
|
|
12875
|
+
}
|
|
12876
|
+
}
|
|
12877
|
+
|
|
12878
|
+
// src/infra/config/attachmentMirror.ts
|
|
12879
|
+
import crypto3 from "crypto";
|
|
12880
|
+
import fs21 from "fs";
|
|
12881
|
+
import os12 from "os";
|
|
12882
|
+
import path19 from "path";
|
|
12883
|
+
function attachmentMirrorPath(env = process.env) {
|
|
12884
|
+
const home = env["HOME"] ?? os12.homedir();
|
|
12885
|
+
return path19.join(home, ".config", "athena", "attachments.json");
|
|
12886
|
+
}
|
|
12887
|
+
function readAttachmentMirror(env = process.env) {
|
|
12888
|
+
const file = attachmentMirrorPath(env);
|
|
12889
|
+
let raw;
|
|
12890
|
+
try {
|
|
12891
|
+
raw = fs21.readFileSync(file, "utf-8");
|
|
12892
|
+
} catch (err) {
|
|
12893
|
+
if (err.code === "ENOENT") return null;
|
|
12894
|
+
throw err;
|
|
12895
|
+
}
|
|
12896
|
+
let parsed;
|
|
12897
|
+
try {
|
|
12898
|
+
parsed = JSON.parse(raw);
|
|
12899
|
+
} catch (err) {
|
|
12900
|
+
throw new Error(
|
|
12901
|
+
`attachment mirror ${file} is invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
12902
|
+
);
|
|
12903
|
+
}
|
|
12904
|
+
try {
|
|
12905
|
+
return parseAttachmentMirror(parsed);
|
|
12906
|
+
} catch (err) {
|
|
12907
|
+
throw new Error(
|
|
12908
|
+
`attachment mirror ${file} is invalid: ${err instanceof Error ? err.message : String(err)}`
|
|
12909
|
+
);
|
|
12910
|
+
}
|
|
12911
|
+
}
|
|
12912
|
+
function writeAttachmentMirror(mirror, env = process.env) {
|
|
12913
|
+
const validated = parseAttachmentMirror(mirror);
|
|
12914
|
+
const file = attachmentMirrorPath(env);
|
|
12915
|
+
const dir = path19.dirname(file);
|
|
12916
|
+
fs21.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
12917
|
+
const tmp = `${file}.${process.pid}.${crypto3.randomBytes(4).toString("hex")}.tmp`;
|
|
12918
|
+
const fd = fs21.openSync(tmp, "w", 384);
|
|
12919
|
+
try {
|
|
12920
|
+
fs21.writeSync(fd, JSON.stringify(validated, null, 2) + "\n");
|
|
12921
|
+
fs21.fsyncSync(fd);
|
|
12922
|
+
} finally {
|
|
12923
|
+
fs21.closeSync(fd);
|
|
12924
|
+
}
|
|
12925
|
+
try {
|
|
12926
|
+
fs21.renameSync(tmp, file);
|
|
12927
|
+
} catch (err) {
|
|
12928
|
+
try {
|
|
12929
|
+
fs21.unlinkSync(tmp);
|
|
12930
|
+
} catch {
|
|
12931
|
+
}
|
|
12932
|
+
throw err;
|
|
12933
|
+
}
|
|
12934
|
+
if (process.platform !== "win32") {
|
|
12935
|
+
try {
|
|
12936
|
+
fs21.chmodSync(dir, 448);
|
|
12937
|
+
fs21.chmodSync(file, 384);
|
|
12938
|
+
} catch {
|
|
12939
|
+
}
|
|
12940
|
+
}
|
|
12941
|
+
}
|
|
12942
|
+
function removeAttachmentMirror(env = process.env) {
|
|
12943
|
+
const file = attachmentMirrorPath(env);
|
|
12944
|
+
try {
|
|
12945
|
+
fs21.unlinkSync(file);
|
|
12946
|
+
} catch (err) {
|
|
12947
|
+
if (err.code !== "ENOENT") throw err;
|
|
12948
|
+
}
|
|
12949
|
+
}
|
|
12950
|
+
function parseAttachmentMirror(raw) {
|
|
12951
|
+
if (typeof raw !== "object" || raw === null) {
|
|
12952
|
+
throw new Error("root must be an object");
|
|
12953
|
+
}
|
|
12954
|
+
const obj = raw;
|
|
12955
|
+
if (typeof obj["instanceId"] !== "string" || obj["instanceId"].length === 0) {
|
|
12956
|
+
throw new Error("instanceId must be a non-empty string");
|
|
12957
|
+
}
|
|
12958
|
+
if (typeof obj["fetchedAt"] !== "number") {
|
|
12959
|
+
throw new Error("fetchedAt must be a number");
|
|
12960
|
+
}
|
|
12961
|
+
if (!Array.isArray(obj["attachments"])) {
|
|
12962
|
+
throw new Error("attachments must be an array");
|
|
12963
|
+
}
|
|
12964
|
+
const attachments = obj["attachments"].map((entry, idx) => {
|
|
12965
|
+
if (typeof entry !== "object" || entry === null) {
|
|
12966
|
+
throw new Error(`attachments[${idx}] must be an object`);
|
|
12967
|
+
}
|
|
12968
|
+
const e = entry;
|
|
12969
|
+
if (typeof e["runnerId"] !== "string" || e["runnerId"].length === 0) {
|
|
12970
|
+
throw new Error(
|
|
12971
|
+
`attachments[${idx}].runnerId must be a non-empty string`
|
|
12972
|
+
);
|
|
12973
|
+
}
|
|
12974
|
+
const out = { runnerId: e["runnerId"] };
|
|
12975
|
+
if (typeof e["name"] === "string") out.name = e["name"];
|
|
12976
|
+
if (typeof e["executionTarget"] === "string") {
|
|
12977
|
+
out.executionTarget = e["executionTarget"];
|
|
12978
|
+
}
|
|
12979
|
+
if (typeof e["remoteInstanceId"] === "string") {
|
|
12980
|
+
out.remoteInstanceId = e["remoteInstanceId"];
|
|
12981
|
+
}
|
|
12982
|
+
return out;
|
|
12983
|
+
});
|
|
12984
|
+
return {
|
|
12985
|
+
instanceId: obj["instanceId"],
|
|
12986
|
+
fetchedAt: obj["fetchedAt"],
|
|
12987
|
+
attachments
|
|
12988
|
+
};
|
|
12989
|
+
}
|
|
12990
|
+
|
|
12991
|
+
// src/app/dashboard/attachmentReconciler.ts
|
|
12992
|
+
async function fetchDashboardAttachments({
|
|
12993
|
+
dashboardUrl,
|
|
12994
|
+
instanceId,
|
|
12995
|
+
accessToken
|
|
12996
|
+
}) {
|
|
12997
|
+
const url = new URL(dashboardUrl);
|
|
12998
|
+
url.pathname = `/api/instances/${encodeURIComponent(instanceId)}/attachments`;
|
|
12999
|
+
url.search = "";
|
|
13000
|
+
url.hash = "";
|
|
13001
|
+
const response = await fetch(url, {
|
|
13002
|
+
headers: {
|
|
13003
|
+
authorization: `Bearer ${accessToken}`,
|
|
13004
|
+
accept: "application/json"
|
|
13005
|
+
}
|
|
13006
|
+
});
|
|
13007
|
+
if (!response.ok) {
|
|
13008
|
+
throw new Error(
|
|
13009
|
+
`attachment reconciliation failed: ${response.status} ${response.statusText}`
|
|
13010
|
+
);
|
|
13011
|
+
}
|
|
13012
|
+
const body = await response.json();
|
|
13013
|
+
if (!Array.isArray(body.attachments)) {
|
|
13014
|
+
throw new Error("attachment reconciliation failed: invalid response");
|
|
13015
|
+
}
|
|
13016
|
+
return normalizeAttachments(body.attachments);
|
|
13017
|
+
}
|
|
13018
|
+
function normalizeAttachments(raw) {
|
|
13019
|
+
return raw.map((value, idx) => {
|
|
13020
|
+
if (typeof value !== "object" || value === null) {
|
|
13021
|
+
throw new Error(`attachments[${idx}] must be an object`);
|
|
13022
|
+
}
|
|
13023
|
+
const entry = value;
|
|
13024
|
+
if (typeof entry["runnerId"] !== "string" || entry["runnerId"].length === 0) {
|
|
13025
|
+
throw new Error(
|
|
13026
|
+
`attachments[${idx}].runnerId must be a non-empty string`
|
|
13027
|
+
);
|
|
12406
13028
|
}
|
|
13029
|
+
return {
|
|
13030
|
+
runnerId: entry["runnerId"],
|
|
13031
|
+
...typeof entry["name"] === "string" ? { name: entry["name"] } : {},
|
|
13032
|
+
...typeof entry["executionTarget"] === "string" ? { executionTarget: entry["executionTarget"] } : {},
|
|
13033
|
+
...typeof entry["remoteInstanceId"] === "string" ? { remoteInstanceId: entry["remoteInstanceId"] } : {}
|
|
13034
|
+
};
|
|
13035
|
+
});
|
|
13036
|
+
}
|
|
13037
|
+
function createAttachmentReconciler(options) {
|
|
13038
|
+
const fetchAttachments = options.fetchAttachments ?? fetchDashboardAttachments;
|
|
13039
|
+
const now = options.now ?? (() => Date.now());
|
|
13040
|
+
const currentInstances = /* @__PURE__ */ new Set();
|
|
13041
|
+
let pushRevision = 0;
|
|
13042
|
+
const latestPushByInstance = /* @__PURE__ */ new Map();
|
|
13043
|
+
function write(instanceId, attachments) {
|
|
13044
|
+
options.writeMirror({ instanceId, fetchedAt: now(), attachments });
|
|
12407
13045
|
}
|
|
13046
|
+
return {
|
|
13047
|
+
async reconcileNow(input) {
|
|
13048
|
+
const revisionAtStart = pushRevision;
|
|
13049
|
+
const attachments = await fetchAttachments(input);
|
|
13050
|
+
write(input.instanceId, attachments);
|
|
13051
|
+
if (pushRevision !== revisionAtStart) {
|
|
13052
|
+
const latestPush = latestPushByInstance.get(input.instanceId);
|
|
13053
|
+
if (latestPush) write(input.instanceId, latestPush);
|
|
13054
|
+
}
|
|
13055
|
+
currentInstances.add(input.instanceId);
|
|
13056
|
+
},
|
|
13057
|
+
applyPush({ instanceId, attachments }) {
|
|
13058
|
+
pushRevision += 1;
|
|
13059
|
+
latestPushByInstance.set(instanceId, attachments);
|
|
13060
|
+
write(instanceId, attachments);
|
|
13061
|
+
currentInstances.add(instanceId);
|
|
13062
|
+
},
|
|
13063
|
+
isCurrent(instanceId) {
|
|
13064
|
+
return currentInstances.has(instanceId);
|
|
13065
|
+
},
|
|
13066
|
+
markStale(instanceId) {
|
|
13067
|
+
currentInstances.delete(instanceId);
|
|
13068
|
+
}
|
|
13069
|
+
};
|
|
12408
13070
|
}
|
|
12409
13071
|
|
|
12410
13072
|
// src/app/dashboard/dashboardDecisionInbox.ts
|
|
@@ -12557,29 +13219,15 @@ function createDashboardPairedExecution(options) {
|
|
|
12557
13219
|
runHistory.shift();
|
|
12558
13220
|
}
|
|
12559
13221
|
}
|
|
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
|
-
}
|
|
13222
|
+
function rejectAssignment(runId, rejection) {
|
|
12575
13223
|
recordRun({
|
|
12576
13224
|
runId,
|
|
12577
13225
|
startedAt: now(),
|
|
12578
13226
|
endedAt: now(),
|
|
12579
13227
|
status: "rejected",
|
|
12580
|
-
error:
|
|
13228
|
+
error: rejection.message
|
|
12581
13229
|
});
|
|
12582
|
-
log("warn", `run ${runId} rejected: ${
|
|
13230
|
+
log("warn", `run ${runId} rejected: ${rejection.message}`);
|
|
12583
13231
|
}
|
|
12584
13232
|
function handleDecision(frame) {
|
|
12585
13233
|
decisionInbox.enqueue({
|
|
@@ -12599,22 +13247,24 @@ function createDashboardPairedExecution(options) {
|
|
|
12599
13247
|
entry.record.status = "cancelled";
|
|
12600
13248
|
entry.controller.abort();
|
|
12601
13249
|
}
|
|
12602
|
-
function handleAssignment(frame) {
|
|
13250
|
+
function handleAssignment(frame, input = {}) {
|
|
12603
13251
|
if (active.has(frame.runId)) {
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
`duplicate active assignment ${frame.runId}`
|
|
12607
|
-
|
|
12608
|
-
|
|
13252
|
+
const rejection = {
|
|
13253
|
+
reason: "duplicate",
|
|
13254
|
+
message: `duplicate active assignment ${frame.runId}`
|
|
13255
|
+
};
|
|
13256
|
+
rejectAssignment(frame.runId, rejection);
|
|
13257
|
+
return { kind: "rejected", rejection };
|
|
12609
13258
|
}
|
|
12610
13259
|
const runnerKey = frame.runnerId;
|
|
12611
13260
|
const bucket = activeByRunner.get(runnerKey) ?? /* @__PURE__ */ new Set();
|
|
12612
13261
|
if (bucket.size >= maxConcurrentRuns) {
|
|
12613
|
-
|
|
12614
|
-
|
|
12615
|
-
`runtime daemon at concurrency cap (${maxConcurrentRuns}) for runner ${runnerKey ?? "<legacy>"}`
|
|
12616
|
-
|
|
12617
|
-
|
|
13262
|
+
const rejection = {
|
|
13263
|
+
reason: "local_capacity",
|
|
13264
|
+
message: `runtime daemon at concurrency cap (${maxConcurrentRuns}) for runner ${runnerKey ?? "<legacy>"}`
|
|
13265
|
+
};
|
|
13266
|
+
rejectAssignment(frame.runId, rejection);
|
|
13267
|
+
return { kind: "rejected", rejection };
|
|
12618
13268
|
}
|
|
12619
13269
|
const controller = new AbortController();
|
|
12620
13270
|
const record = {
|
|
@@ -12628,7 +13278,7 @@ function createDashboardPairedExecution(options) {
|
|
|
12628
13278
|
const promise = executor({
|
|
12629
13279
|
frame,
|
|
12630
13280
|
client,
|
|
12631
|
-
projectDir,
|
|
13281
|
+
projectDir: input.projectDir ?? projectDir,
|
|
12632
13282
|
log,
|
|
12633
13283
|
abortSignal: controller.signal,
|
|
12634
13284
|
decisionInbox
|
|
@@ -12654,6 +13304,7 @@ function createDashboardPairedExecution(options) {
|
|
|
12654
13304
|
}
|
|
12655
13305
|
});
|
|
12656
13306
|
active.set(frame.runId, { controller, promise, record, runnerKey });
|
|
13307
|
+
return { kind: "accepted" };
|
|
12657
13308
|
}
|
|
12658
13309
|
return {
|
|
12659
13310
|
handleFrame(frame) {
|
|
@@ -12671,6 +13322,10 @@ function createDashboardPairedExecution(options) {
|
|
|
12671
13322
|
}
|
|
12672
13323
|
return false;
|
|
12673
13324
|
},
|
|
13325
|
+
admitAssignment(frame, input) {
|
|
13326
|
+
return handleAssignment(frame, input);
|
|
13327
|
+
},
|
|
13328
|
+
rejectAssignment,
|
|
12674
13329
|
snapshot() {
|
|
12675
13330
|
return {
|
|
12676
13331
|
activeRuns: active.size,
|
|
@@ -12696,6 +13351,190 @@ function createDashboardPairedExecution(options) {
|
|
|
12696
13351
|
};
|
|
12697
13352
|
}
|
|
12698
13353
|
|
|
13354
|
+
// src/app/dashboard/remoteWorkspaceResolver.ts
|
|
13355
|
+
import fs22 from "fs";
|
|
13356
|
+
import os13 from "os";
|
|
13357
|
+
import path20 from "path";
|
|
13358
|
+
function resolveRemoteWorkspace(frame, options = {}) {
|
|
13359
|
+
const spec = parseRemoteRunSpec(frame.runSpec);
|
|
13360
|
+
if (!spec) {
|
|
13361
|
+
return {
|
|
13362
|
+
kind: "rejected",
|
|
13363
|
+
rejection: {
|
|
13364
|
+
reason: "workspace_unresolved",
|
|
13365
|
+
message: "remote assignment missing prompt"
|
|
13366
|
+
}
|
|
13367
|
+
};
|
|
13368
|
+
}
|
|
13369
|
+
if (spec.projectDir) {
|
|
13370
|
+
return validateProjectDir(spec.projectDir, options.env);
|
|
13371
|
+
}
|
|
13372
|
+
const sessionId = spec.athenaSessionId ?? spec.sessionId;
|
|
13373
|
+
const runnerId = frame.runnerId ?? "legacy";
|
|
13374
|
+
const deploymentSlug = deploymentSlugFromUrl(options.dashboardUrl);
|
|
13375
|
+
const stateDir = daemonStatePaths(options.env).dir;
|
|
13376
|
+
const projectDir = sessionId ? path20.join(
|
|
13377
|
+
stateDir,
|
|
13378
|
+
"remote-workspaces",
|
|
13379
|
+
deploymentSlug,
|
|
13380
|
+
sanitizePathSegment(runnerId),
|
|
13381
|
+
"sessions",
|
|
13382
|
+
sanitizePathSegment(sessionId)
|
|
13383
|
+
) : path20.join(
|
|
13384
|
+
stateDir,
|
|
13385
|
+
"remote-workspaces",
|
|
13386
|
+
deploymentSlug,
|
|
13387
|
+
sanitizePathSegment(runnerId),
|
|
13388
|
+
"runs",
|
|
13389
|
+
sanitizePathSegment(frame.runId)
|
|
13390
|
+
);
|
|
13391
|
+
try {
|
|
13392
|
+
fs22.mkdirSync(projectDir, { recursive: true, mode: 448 });
|
|
13393
|
+
if (process.platform !== "win32") {
|
|
13394
|
+
try {
|
|
13395
|
+
fs22.chmodSync(projectDir, 448);
|
|
13396
|
+
} catch {
|
|
13397
|
+
}
|
|
13398
|
+
}
|
|
13399
|
+
} catch (err) {
|
|
13400
|
+
return {
|
|
13401
|
+
kind: "rejected",
|
|
13402
|
+
rejection: {
|
|
13403
|
+
reason: "workspace_unresolved",
|
|
13404
|
+
message: `failed to create remote workspace: ${err instanceof Error ? err.message : String(err)}`
|
|
13405
|
+
}
|
|
13406
|
+
};
|
|
13407
|
+
}
|
|
13408
|
+
return validateProjectDir(projectDir, options.env);
|
|
13409
|
+
}
|
|
13410
|
+
function validateProjectDir(projectDir, env = process.env) {
|
|
13411
|
+
const resolved = path20.resolve(projectDir);
|
|
13412
|
+
if (!path20.isAbsolute(projectDir)) {
|
|
13413
|
+
return {
|
|
13414
|
+
kind: "rejected",
|
|
13415
|
+
rejection: {
|
|
13416
|
+
reason: "workspace_invalid",
|
|
13417
|
+
message: `remote workspace must be an absolute path: ${projectDir}`
|
|
13418
|
+
}
|
|
13419
|
+
};
|
|
13420
|
+
}
|
|
13421
|
+
const home = path20.resolve(env["HOME"] ?? os13.homedir());
|
|
13422
|
+
if (resolved === home) {
|
|
13423
|
+
return {
|
|
13424
|
+
kind: "rejected",
|
|
13425
|
+
rejection: {
|
|
13426
|
+
reason: "workspace_invalid",
|
|
13427
|
+
message: "remote workspace cannot be the user home directory"
|
|
13428
|
+
}
|
|
13429
|
+
};
|
|
13430
|
+
}
|
|
13431
|
+
let stat;
|
|
13432
|
+
try {
|
|
13433
|
+
stat = fs22.statSync(resolved);
|
|
13434
|
+
} catch {
|
|
13435
|
+
return {
|
|
13436
|
+
kind: "rejected",
|
|
13437
|
+
rejection: {
|
|
13438
|
+
reason: "workspace_invalid",
|
|
13439
|
+
message: `remote workspace does not exist: ${resolved}`
|
|
13440
|
+
}
|
|
13441
|
+
};
|
|
13442
|
+
}
|
|
13443
|
+
if (!stat.isDirectory()) {
|
|
13444
|
+
return {
|
|
13445
|
+
kind: "rejected",
|
|
13446
|
+
rejection: {
|
|
13447
|
+
reason: "workspace_invalid",
|
|
13448
|
+
message: `remote workspace is not a directory: ${resolved}`
|
|
13449
|
+
}
|
|
13450
|
+
};
|
|
13451
|
+
}
|
|
13452
|
+
return { kind: "resolved", projectDir: resolved };
|
|
13453
|
+
}
|
|
13454
|
+
function deploymentSlugFromUrl(dashboardUrl) {
|
|
13455
|
+
if (!dashboardUrl) return "unknown-dashboard";
|
|
13456
|
+
try {
|
|
13457
|
+
const url = new URL(dashboardUrl);
|
|
13458
|
+
return sanitizePathSegment(url.host);
|
|
13459
|
+
} catch {
|
|
13460
|
+
return sanitizePathSegment(dashboardUrl);
|
|
13461
|
+
}
|
|
13462
|
+
}
|
|
13463
|
+
function sanitizePathSegment(value) {
|
|
13464
|
+
const cleaned = value.trim().replaceAll(/[^a-zA-Z0-9._-]+/g, "-").replaceAll(/^-+|-+$/g, "");
|
|
13465
|
+
return cleaned.length > 0 ? cleaned : "unknown";
|
|
13466
|
+
}
|
|
13467
|
+
|
|
13468
|
+
// src/app/dashboard/dashboardAssignmentIntake.ts
|
|
13469
|
+
function createDashboardAssignmentIntake(options) {
|
|
13470
|
+
const log = options.log ?? (() => {
|
|
13471
|
+
});
|
|
13472
|
+
const resolveWorkspace = options.resolveWorkspace ?? ((frame) => resolveRemoteWorkspace(frame));
|
|
13473
|
+
const pending = [];
|
|
13474
|
+
let ready = false;
|
|
13475
|
+
function handle(frame) {
|
|
13476
|
+
if (!isRemoteAssignmentAdmissible(frame)) {
|
|
13477
|
+
const rejection = {
|
|
13478
|
+
reason: "malformed_assignment",
|
|
13479
|
+
message: "remote assignment missing prompt"
|
|
13480
|
+
};
|
|
13481
|
+
options.execution.rejectAssignment(frame.runId, rejection);
|
|
13482
|
+
options.client.sendAssignmentRejected({
|
|
13483
|
+
runId: frame.runId,
|
|
13484
|
+
...rejection
|
|
13485
|
+
});
|
|
13486
|
+
return;
|
|
13487
|
+
}
|
|
13488
|
+
const workspace = resolveWorkspace(frame);
|
|
13489
|
+
if (workspace.kind === "rejected") {
|
|
13490
|
+
options.execution.rejectAssignment(frame.runId, workspace.rejection);
|
|
13491
|
+
options.client.sendAssignmentRejected({
|
|
13492
|
+
runId: frame.runId,
|
|
13493
|
+
...workspace.rejection
|
|
13494
|
+
});
|
|
13495
|
+
return;
|
|
13496
|
+
}
|
|
13497
|
+
const outcome = options.execution.admitAssignment(frame, {
|
|
13498
|
+
projectDir: workspace.projectDir
|
|
13499
|
+
});
|
|
13500
|
+
if (outcome.kind === "accepted") {
|
|
13501
|
+
options.client.sendAssignmentAccepted(frame.runId);
|
|
13502
|
+
return;
|
|
13503
|
+
}
|
|
13504
|
+
options.client.sendAssignmentRejected({
|
|
13505
|
+
runId: frame.runId,
|
|
13506
|
+
...outcome.rejection
|
|
13507
|
+
});
|
|
13508
|
+
}
|
|
13509
|
+
function drain() {
|
|
13510
|
+
if (!ready) return;
|
|
13511
|
+
while (pending.length > 0) {
|
|
13512
|
+
const frame = pending.shift();
|
|
13513
|
+
if (frame) handle(frame);
|
|
13514
|
+
}
|
|
13515
|
+
}
|
|
13516
|
+
return {
|
|
13517
|
+
receive(frame) {
|
|
13518
|
+
if (!ready) {
|
|
13519
|
+
pending.push(frame);
|
|
13520
|
+
log(
|
|
13521
|
+
"debug",
|
|
13522
|
+
`dashboard assignment buffered until attachments are current: runId=${frame.runId}`
|
|
13523
|
+
);
|
|
13524
|
+
return;
|
|
13525
|
+
}
|
|
13526
|
+
handle(frame);
|
|
13527
|
+
},
|
|
13528
|
+
markReady() {
|
|
13529
|
+
ready = true;
|
|
13530
|
+
drain();
|
|
13531
|
+
},
|
|
13532
|
+
markNotReady() {
|
|
13533
|
+
ready = false;
|
|
13534
|
+
}
|
|
13535
|
+
};
|
|
13536
|
+
}
|
|
13537
|
+
|
|
12699
13538
|
// src/app/dashboard/runtimeDaemon.ts
|
|
12700
13539
|
var DEFAULT_RECONNECT_DELAYS_MS2 = [1e3, 2e3, 5e3, 1e4, 3e4];
|
|
12701
13540
|
var DEFAULT_MAX_CONCURRENT_RUNS2 = 1;
|
|
@@ -12704,7 +13543,6 @@ var DEFAULT_REFRESH_FAILURE_LIMIT = 5;
|
|
|
12704
13543
|
var DEFAULT_REFRESH_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
12705
13544
|
var DEFAULT_REFRESH_COOLDOWN_MS = 5 * 6e4;
|
|
12706
13545
|
var DEFAULT_RUN_HISTORY_LIMIT2 = 100;
|
|
12707
|
-
var DEFAULT_FEED_DRAIN_INTERVAL_MS = 1e3;
|
|
12708
13546
|
function delay(ms) {
|
|
12709
13547
|
return new Promise((resolve) => {
|
|
12710
13548
|
const timer = setTimeout(resolve, ms);
|
|
@@ -12733,9 +13571,12 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12733
13571
|
const runHistoryLimit = options.runHistoryLimit ?? DEFAULT_RUN_HISTORY_LIMIT2;
|
|
12734
13572
|
const now = options.now ?? (() => Date.now());
|
|
12735
13573
|
const writeMirror = options.writeMirror ?? writeAttachmentMirror;
|
|
12736
|
-
const
|
|
13574
|
+
const pairedFeedPublisher = options.pairedFeedPublisher ?? createPairedFeedPublisher({
|
|
13575
|
+
readConfig: readConfig2,
|
|
13576
|
+
now,
|
|
13577
|
+
drainIntervalMs: options.feedDrainIntervalMs
|
|
13578
|
+
});
|
|
12737
13579
|
const decisionInbox = options.decisionInbox ?? createDashboardDecisionInbox();
|
|
12738
|
-
const feedDrainIntervalMs = options.feedDrainIntervalMs ?? DEFAULT_FEED_DRAIN_INTERVAL_MS;
|
|
12739
13580
|
const retryInitialConnect = options.retryInitialConnect ?? true;
|
|
12740
13581
|
const startedAt = now();
|
|
12741
13582
|
let stopped = false;
|
|
@@ -12746,7 +13587,6 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12746
13587
|
let currentDashboardUrl;
|
|
12747
13588
|
let lastFrameAt;
|
|
12748
13589
|
let refreshTimer = null;
|
|
12749
|
-
let feedDrainTimer = null;
|
|
12750
13590
|
const refreshFailures = [];
|
|
12751
13591
|
let cooldownUntil = 0;
|
|
12752
13592
|
const executionClient = {
|
|
@@ -12777,6 +13617,28 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12777
13617
|
now,
|
|
12778
13618
|
runHistoryLimit
|
|
12779
13619
|
});
|
|
13620
|
+
const attachmentReconciler = createAttachmentReconciler({
|
|
13621
|
+
writeMirror,
|
|
13622
|
+
...options.fetchAttachments ? { fetchAttachments: options.fetchAttachments } : {},
|
|
13623
|
+
now
|
|
13624
|
+
});
|
|
13625
|
+
const assignmentIntake = createDashboardAssignmentIntake({
|
|
13626
|
+
client: {
|
|
13627
|
+
sendAssignmentAccepted(runId) {
|
|
13628
|
+
const current = client;
|
|
13629
|
+
if (!current) return;
|
|
13630
|
+
current.sendAssignmentAccepted(runId);
|
|
13631
|
+
},
|
|
13632
|
+
sendAssignmentRejected(input) {
|
|
13633
|
+
const current = client;
|
|
13634
|
+
if (!current) return;
|
|
13635
|
+
current.sendAssignmentRejected(input);
|
|
13636
|
+
}
|
|
13637
|
+
},
|
|
13638
|
+
execution: pairedExecution,
|
|
13639
|
+
log,
|
|
13640
|
+
resolveWorkspace: (frame) => resolveRemoteWorkspace(frame, { dashboardUrl: currentDashboardUrl })
|
|
13641
|
+
});
|
|
12780
13642
|
function nextReconnectDelay() {
|
|
12781
13643
|
if (reconnectDelays.length === 0) return 0;
|
|
12782
13644
|
const delayMs = reconnectDelays[Math.min(reconnectAttempt, reconnectDelays.length - 1)] ?? 0;
|
|
@@ -12789,35 +13651,6 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12789
13651
|
refreshTimer = null;
|
|
12790
13652
|
}
|
|
12791
13653
|
}
|
|
12792
|
-
function clearFeedDrainTimer() {
|
|
12793
|
-
if (feedDrainTimer) {
|
|
12794
|
-
clearInterval(feedDrainTimer);
|
|
12795
|
-
feedDrainTimer = null;
|
|
12796
|
-
}
|
|
12797
|
-
}
|
|
12798
|
-
function drainFeedOutbox() {
|
|
12799
|
-
const current = client;
|
|
12800
|
-
if (!current) return;
|
|
12801
|
-
const rows = feedOutbox.pendingBatch({ limit: 100, now: now() });
|
|
12802
|
-
for (const row of rows) {
|
|
12803
|
-
current.sendFeedEvent({
|
|
12804
|
-
deliverySeq: row.deliverySeq,
|
|
12805
|
-
envelope: row.envelope
|
|
12806
|
-
});
|
|
12807
|
-
const retryDelayMs = Math.min(3e4, (row.attempt + 1) * 1e3);
|
|
12808
|
-
feedOutbox.markAttempted({
|
|
12809
|
-
deliverySeq: row.deliverySeq,
|
|
12810
|
-
nextAttemptAt: now() + retryDelayMs
|
|
12811
|
-
});
|
|
12812
|
-
}
|
|
12813
|
-
}
|
|
12814
|
-
function startFeedDrainTimer() {
|
|
12815
|
-
clearFeedDrainTimer();
|
|
12816
|
-
const timer = setInterval(drainFeedOutbox, feedDrainIntervalMs);
|
|
12817
|
-
timer.unref();
|
|
12818
|
-
feedDrainTimer = timer;
|
|
12819
|
-
drainFeedOutbox();
|
|
12820
|
-
}
|
|
12821
13654
|
function scheduleRefresh(expiresInSec) {
|
|
12822
13655
|
clearRefreshTimer();
|
|
12823
13656
|
if (!Number.isFinite(expiresInSec) || expiresInSec <= refreshLeadSec) {
|
|
@@ -12898,9 +13731,8 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12898
13731
|
lastFrameAt = now();
|
|
12899
13732
|
if (frame.type === "attachments.changed") {
|
|
12900
13733
|
try {
|
|
12901
|
-
|
|
13734
|
+
attachmentReconciler.applyPush({
|
|
12902
13735
|
instanceId: token.instanceId,
|
|
12903
|
-
fetchedAt: now(),
|
|
12904
13736
|
attachments: frame.attachments.map((a) => ({
|
|
12905
13737
|
runnerId: a.runnerId,
|
|
12906
13738
|
...a.name !== void 0 ? { name: a.name } : {},
|
|
@@ -12917,10 +13749,11 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12917
13749
|
return;
|
|
12918
13750
|
}
|
|
12919
13751
|
if (frame.type === "feed_ack") {
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
13752
|
+
pairedFeedPublisher.handleAck(frame);
|
|
13753
|
+
return;
|
|
13754
|
+
}
|
|
13755
|
+
if (frame.type === "job_assignment") {
|
|
13756
|
+
assignmentIntake.receive(frame);
|
|
12924
13757
|
return;
|
|
12925
13758
|
}
|
|
12926
13759
|
pairedExecution.handleFrame(frame);
|
|
@@ -12929,19 +13762,35 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12929
13762
|
if (stopped || client !== next) return;
|
|
12930
13763
|
log("warn", `instance socket closed: ${reason}`);
|
|
12931
13764
|
client = null;
|
|
13765
|
+
assignmentIntake.markNotReady();
|
|
13766
|
+
attachmentReconciler.markStale(token.instanceId);
|
|
12932
13767
|
currentInstanceId = void 0;
|
|
12933
13768
|
clearRefreshTimer();
|
|
12934
|
-
|
|
13769
|
+
pairedFeedPublisher.detachTransport();
|
|
12935
13770
|
void reconnectLoop();
|
|
12936
13771
|
});
|
|
12937
13772
|
await next.connect();
|
|
12938
13773
|
client = next;
|
|
12939
13774
|
lastSocketClient = next;
|
|
13775
|
+
try {
|
|
13776
|
+
await attachmentReconciler.reconcileNow({
|
|
13777
|
+
dashboardUrl: config.dashboardUrl,
|
|
13778
|
+
instanceId: token.instanceId,
|
|
13779
|
+
accessToken: token.accessToken
|
|
13780
|
+
});
|
|
13781
|
+
} catch (err) {
|
|
13782
|
+
client = null;
|
|
13783
|
+
assignmentIntake.markNotReady();
|
|
13784
|
+
attachmentReconciler.markStale(token.instanceId);
|
|
13785
|
+
next.close("attachment reconciliation failed");
|
|
13786
|
+
throw err;
|
|
13787
|
+
}
|
|
12940
13788
|
currentInstanceId = token.instanceId;
|
|
12941
13789
|
currentDashboardUrl = config.dashboardUrl;
|
|
13790
|
+
assignmentIntake.markReady();
|
|
12942
13791
|
reconnectAttempt = 0;
|
|
12943
13792
|
scheduleRefresh(token.expiresInSec);
|
|
12944
|
-
|
|
13793
|
+
pairedFeedPublisher.attachTransport(next);
|
|
12945
13794
|
log("info", `dashboard runtime daemon connected as ${token.instanceId}`);
|
|
12946
13795
|
}
|
|
12947
13796
|
async function reconnectLoop() {
|
|
@@ -12996,7 +13845,7 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
12996
13845
|
async stop(reason = "stopped") {
|
|
12997
13846
|
stopped = true;
|
|
12998
13847
|
clearRefreshTimer();
|
|
12999
|
-
|
|
13848
|
+
pairedFeedPublisher.close();
|
|
13000
13849
|
const current = client;
|
|
13001
13850
|
client = null;
|
|
13002
13851
|
current?.close(reason);
|
|
@@ -13005,8 +13854,99 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
13005
13854
|
};
|
|
13006
13855
|
}
|
|
13007
13856
|
|
|
13857
|
+
// src/infra/daemon/pidLock.ts
|
|
13858
|
+
import fs23 from "fs";
|
|
13859
|
+
function acquirePidLock(pidPath) {
|
|
13860
|
+
const ownPid = process.pid;
|
|
13861
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
13862
|
+
try {
|
|
13863
|
+
const fd = fs23.openSync(pidPath, "wx", 384);
|
|
13864
|
+
try {
|
|
13865
|
+
fs23.writeSync(fd, `${ownPid}
|
|
13866
|
+
`);
|
|
13867
|
+
fs23.fsyncSync(fd);
|
|
13868
|
+
} finally {
|
|
13869
|
+
fs23.closeSync(fd);
|
|
13870
|
+
}
|
|
13871
|
+
return makeHandle(pidPath, ownPid);
|
|
13872
|
+
} catch (err) {
|
|
13873
|
+
if (err.code !== "EEXIST") throw err;
|
|
13874
|
+
}
|
|
13875
|
+
const existing = readPidLock(pidPath);
|
|
13876
|
+
if (existing.state === "held") {
|
|
13877
|
+
throw new Error(
|
|
13878
|
+
`dashboard daemon is already running as pid ${existing.pid} (lock at ${pidPath}). Use "drisp dashboard daemon stop" to terminate it.`
|
|
13879
|
+
);
|
|
13880
|
+
}
|
|
13881
|
+
if (existing.state === "stale") {
|
|
13882
|
+
try {
|
|
13883
|
+
fs23.unlinkSync(pidPath);
|
|
13884
|
+
} catch (err) {
|
|
13885
|
+
if (err.code !== "ENOENT") throw err;
|
|
13886
|
+
}
|
|
13887
|
+
continue;
|
|
13888
|
+
}
|
|
13889
|
+
}
|
|
13890
|
+
throw new Error(
|
|
13891
|
+
`dashboard daemon: failed to acquire pid lock at ${pidPath} after retry`
|
|
13892
|
+
);
|
|
13893
|
+
}
|
|
13894
|
+
function readPidLock(pidPath) {
|
|
13895
|
+
let raw;
|
|
13896
|
+
try {
|
|
13897
|
+
raw = fs23.readFileSync(pidPath, "utf-8");
|
|
13898
|
+
} catch (err) {
|
|
13899
|
+
if (err.code === "ENOENT") {
|
|
13900
|
+
return { state: "absent" };
|
|
13901
|
+
}
|
|
13902
|
+
throw err;
|
|
13903
|
+
}
|
|
13904
|
+
const pid = Number.parseInt(raw.trim(), 10);
|
|
13905
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
13906
|
+
return { state: "stale", pid: 0 };
|
|
13907
|
+
}
|
|
13908
|
+
if (!isProcessAlive(pid)) {
|
|
13909
|
+
return { state: "stale", pid };
|
|
13910
|
+
}
|
|
13911
|
+
return { state: "held", pid };
|
|
13912
|
+
}
|
|
13913
|
+
function makeHandle(pidPath, pid) {
|
|
13914
|
+
let released = false;
|
|
13915
|
+
return {
|
|
13916
|
+
pid,
|
|
13917
|
+
release() {
|
|
13918
|
+
if (released) return;
|
|
13919
|
+
released = true;
|
|
13920
|
+
try {
|
|
13921
|
+
const raw = fs23.readFileSync(pidPath, "utf-8").trim();
|
|
13922
|
+
if (raw === String(pid)) {
|
|
13923
|
+
fs23.unlinkSync(pidPath);
|
|
13924
|
+
}
|
|
13925
|
+
} catch (err) {
|
|
13926
|
+
if (err.code !== "ENOENT") {
|
|
13927
|
+
}
|
|
13928
|
+
}
|
|
13929
|
+
}
|
|
13930
|
+
};
|
|
13931
|
+
}
|
|
13932
|
+
function isProcessAlive(pid) {
|
|
13933
|
+
if (process.platform === "win32") {
|
|
13934
|
+
return true;
|
|
13935
|
+
}
|
|
13936
|
+
try {
|
|
13937
|
+
process.kill(pid, 0);
|
|
13938
|
+
return true;
|
|
13939
|
+
} catch (err) {
|
|
13940
|
+
const code = err.code;
|
|
13941
|
+
if (code === "EPERM") {
|
|
13942
|
+
return true;
|
|
13943
|
+
}
|
|
13944
|
+
return false;
|
|
13945
|
+
}
|
|
13946
|
+
}
|
|
13947
|
+
|
|
13008
13948
|
// src/infra/daemon/udsIpc.ts
|
|
13009
|
-
import
|
|
13949
|
+
import fs24 from "fs";
|
|
13010
13950
|
import net2 from "net";
|
|
13011
13951
|
|
|
13012
13952
|
// src/infra/daemon/udsFrameCodec.ts
|
|
@@ -13051,7 +13991,7 @@ async function startUdsServer(socketPath, handler, log) {
|
|
|
13051
13991
|
});
|
|
13052
13992
|
if (process.platform !== "win32") {
|
|
13053
13993
|
try {
|
|
13054
|
-
|
|
13994
|
+
fs24.chmodSync(socketPath, 384);
|
|
13055
13995
|
} catch {
|
|
13056
13996
|
}
|
|
13057
13997
|
}
|
|
@@ -13061,7 +14001,7 @@ async function startUdsServer(socketPath, handler, log) {
|
|
|
13061
14001
|
server.close(() => resolve());
|
|
13062
14002
|
});
|
|
13063
14003
|
try {
|
|
13064
|
-
|
|
14004
|
+
fs24.unlinkSync(socketPath);
|
|
13065
14005
|
} catch (err) {
|
|
13066
14006
|
if (err.code !== "ENOENT") {
|
|
13067
14007
|
}
|
|
@@ -13179,7 +14119,7 @@ async function sendUdsRequest(socketPath, request, options = {}) {
|
|
|
13179
14119
|
async function unlinkStaleSocket(socketPath) {
|
|
13180
14120
|
let stat;
|
|
13181
14121
|
try {
|
|
13182
|
-
stat =
|
|
14122
|
+
stat = fs24.statSync(socketPath);
|
|
13183
14123
|
} catch (err) {
|
|
13184
14124
|
if (err.code === "ENOENT") return;
|
|
13185
14125
|
throw err;
|
|
@@ -13206,7 +14146,7 @@ async function unlinkStaleSocket(socketPath) {
|
|
|
13206
14146
|
`uds path ${socketPath} is in use by another process; aborting`
|
|
13207
14147
|
);
|
|
13208
14148
|
}
|
|
13209
|
-
|
|
14149
|
+
fs24.unlinkSync(socketPath);
|
|
13210
14150
|
}
|
|
13211
14151
|
|
|
13212
14152
|
export {
|
|
@@ -13226,7 +14166,7 @@ export {
|
|
|
13226
14166
|
generateId,
|
|
13227
14167
|
daemonStatePaths,
|
|
13228
14168
|
ensureDaemonStateDir,
|
|
13229
|
-
|
|
14169
|
+
createPairedFeedPublisher,
|
|
13230
14170
|
createDashboardDecisionInbox,
|
|
13231
14171
|
createSessionStore,
|
|
13232
14172
|
sessionsDir,
|
|
@@ -13275,9 +14215,13 @@ export {
|
|
|
13275
14215
|
bootstrapRuntimeConfig,
|
|
13276
14216
|
EXEC_EXIT_CODE,
|
|
13277
14217
|
runExec,
|
|
13278
|
-
|
|
14218
|
+
readAttachmentMirror,
|
|
14219
|
+
writeAttachmentMirror,
|
|
14220
|
+
removeAttachmentMirror,
|
|
13279
14221
|
runDashboardRuntimeDaemon,
|
|
14222
|
+
acquirePidLock,
|
|
14223
|
+
readPidLock,
|
|
13280
14224
|
startUdsServer,
|
|
13281
14225
|
sendUdsRequest
|
|
13282
14226
|
};
|
|
13283
|
-
//# sourceMappingURL=chunk-
|
|
14227
|
+
//# sourceMappingURL=chunk-ZU7M6YZW.js.map
|