agent-relay-server 0.127.2 → 0.127.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/openapi.json +1 -1
- package/package.json +7 -5
- package/public/assets/{MessageBubble-DnXnkt4a.js → MessageBubble-D2Wzxied.js} +2 -2
- package/public/assets/{MessageBubble-DnXnkt4a.js.map → MessageBubble-D2Wzxied.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-D6CPEpQD.js → PlanGraphPanel-DH_xoWZi.js} +2 -2
- package/public/assets/{PlanGraphPanel-D6CPEpQD.js.map → PlanGraphPanel-DH_xoWZi.js.map} +1 -1
- package/public/assets/{activity-ZPwHcPLK.js → activity-B-ozOwNq.js} +2 -2
- package/public/assets/{activity-ZPwHcPLK.js.map → activity-B-ozOwNq.js.map} +1 -1
- package/public/assets/{agent-profiles-CT0E9LV1.js → agent-profiles-DZgjO25A.js} +2 -2
- package/public/assets/{agent-profiles-CT0E9LV1.js.map → agent-profiles-DZgjO25A.js.map} +1 -1
- package/public/assets/{agent-type-icon-BmBR-9CH.js → agent-type-icon-B9cLaOoz.js} +2 -2
- package/public/assets/{agent-type-icon-BmBR-9CH.js.map → agent-type-icon-B9cLaOoz.js.map} +1 -1
- package/public/assets/agents-mXBLSY6O.js +2 -0
- package/public/assets/{agents-Dt5TncjC.js.map → agents-mXBLSY6O.js.map} +1 -1
- package/public/assets/{analytics-BZtRycyL.js → analytics-5Ize_UL5.js} +3 -3
- package/public/assets/{analytics-BZtRycyL.js.map → analytics-5Ize_UL5.js.map} +1 -1
- package/public/assets/{automation-yzUJbvT2.js → automation-CidMvW2e.js} +2 -2
- package/public/assets/{automation-yzUJbvT2.js.map → automation-CidMvW2e.js.map} +1 -1
- package/public/assets/{badge-BCvp7LK3.js → badge-BkNNvFNa.js} +2 -2
- package/public/assets/{badge-BCvp7LK3.js.map → badge-BkNNvFNa.js.map} +1 -1
- package/public/assets/{branch-state-badge-Cscjqf-E.js → branch-state-badge-DnS40KCb.js} +2 -2
- package/public/assets/{branch-state-badge-Cscjqf-E.js.map → branch-state-badge-DnS40KCb.js.map} +1 -1
- package/public/assets/{button-DyHjsHY3.js → button-DUaC2wSQ.js} +2 -2
- package/public/assets/{button-DyHjsHY3.js.map → button-DUaC2wSQ.js.map} +1 -1
- package/public/assets/{card-BoqYxpVW.js → card-r-yAV4cH.js} +2 -2
- package/public/assets/{card-BoqYxpVW.js.map → card-r-yAV4cH.js.map} +1 -1
- package/public/assets/{channels-DAtOnA6o.js → channels-MPO2FOBv.js} +2 -2
- package/public/assets/{channels-DAtOnA6o.js.map → channels-MPO2FOBv.js.map} +1 -1
- package/public/assets/chat-Ca4ERso5.js +2 -0
- package/public/assets/chat-Ca4ERso5.js.map +1 -0
- package/public/assets/{connectors-B2grC-hl.js → connectors-BbYdtRkW.js} +2 -2
- package/public/assets/{connectors-B2grC-hl.js.map → connectors-BbYdtRkW.js.map} +1 -1
- package/public/assets/copy-button-u463GPZR.js +2 -0
- package/public/assets/{copy-button-C67FUG3E.js.map → copy-button-u463GPZR.js.map} +1 -1
- package/public/assets/{display-aTnwsqQh.js → display-BNI-7rdq.js} +2 -2
- package/public/assets/{display-aTnwsqQh.js.map → display-BNI-7rdq.js.map} +1 -1
- package/public/assets/{dist-D5w04z0l.js → dist-5e_is3Xr.js} +2 -2
- package/public/assets/{dist-D5w04z0l.js.map → dist-5e_is3Xr.js.map} +1 -1
- package/public/assets/{dist-BD4Xc13v.js → dist-ActI2qb5.js} +2 -2
- package/public/assets/{dist-BD4Xc13v.js.map → dist-ActI2qb5.js.map} +1 -1
- package/public/assets/dist-B-FQ0-X3.js +2 -0
- package/public/assets/{dist-G8YBD-wp.js.map → dist-B-FQ0-X3.js.map} +1 -1
- package/public/assets/{dist-f6MW74eX.js → dist-BduURKro.js} +2 -2
- package/public/assets/{dist-f6MW74eX.js.map → dist-BduURKro.js.map} +1 -1
- package/public/assets/{dist-BFDfbfNC.js → dist-Bp0-OBcd.js} +2 -2
- package/public/assets/{dist-BFDfbfNC.js.map → dist-Bp0-OBcd.js.map} +1 -1
- package/public/assets/{dist-C_VOBSaK.js → dist-CJ7e7uqU.js} +2 -2
- package/public/assets/{dist-C_VOBSaK.js.map → dist-CJ7e7uqU.js.map} +1 -1
- package/public/assets/{dist-BNB3fTO-.js → dist-CYzOsD_n.js} +2 -2
- package/public/assets/{dist-BNB3fTO-.js.map → dist-CYzOsD_n.js.map} +1 -1
- package/public/assets/{dist-CQMQ5iku.js → dist-CpcQJrKV.js} +2 -2
- package/public/assets/{dist-CQMQ5iku.js.map → dist-CpcQJrKV.js.map} +1 -1
- package/public/assets/dist-DFgmDjLv.js +2 -0
- package/public/assets/{dist-CHKra2JV.js.map → dist-DFgmDjLv.js.map} +1 -1
- package/public/assets/{dist-DG75bvPp.js → dist-DrpSpMKL.js} +2 -2
- package/public/assets/{dist-DG75bvPp.js.map → dist-DrpSpMKL.js.map} +1 -1
- package/public/assets/dist-DzWoiN2z.js +2 -0
- package/public/assets/{dist-BJKxqIQd.js.map → dist-DzWoiN2z.js.map} +1 -1
- package/public/assets/{es2015-a6fysEVz.js → es2015-DNuudVtQ.js} +2 -2
- package/public/assets/{es2015-a6fysEVz.js.map → es2015-DNuudVtQ.js.map} +1 -1
- package/public/assets/formatted-body-BEI1zP7i.js +3 -0
- package/public/assets/{formatted-body-D5-1aiyB.js.map → formatted-body-BEI1zP7i.js.map} +1 -1
- package/public/assets/{formatted-body-impl-Do5NbJUA.js → formatted-body-impl-CNQ5sqwK.js} +2 -2
- package/public/assets/{formatted-body-impl-Do5NbJUA.js.map → formatted-body-impl-CNQ5sqwK.js.map} +1 -1
- package/public/assets/index-D2Mpzpft.js +26 -0
- package/public/assets/{index-BdNafiPz.js.map → index-D2Mpzpft.js.map} +1 -1
- package/public/assets/{input-Rc4oWv4q.js → input-BvNUEkDd.js} +2 -2
- package/public/assets/{input-Rc4oWv4q.js.map → input-BvNUEkDd.js.map} +1 -1
- package/public/assets/{insights-i6AEZT_a.js → insights-5rkMFRgf.js} +2 -2
- package/public/assets/{insights-i6AEZT_a.js.map → insights-5rkMFRgf.js.map} +1 -1
- package/public/assets/{integrations-9c6IdRU4.js → integrations-BEaqjfP4.js} +2 -2
- package/public/assets/{integrations-9c6IdRU4.js.map → integrations-BEaqjfP4.js.map} +1 -1
- package/public/assets/{lib-BZ6WPg2t.js → lib-BvrbNA2I.js} +2 -2
- package/public/assets/{lib-BZ6WPg2t.js.map → lib-BvrbNA2I.js.map} +1 -1
- package/public/assets/{lucide-react-NXHPIMsX.js → lucide-react-DD_zIava.js} +2 -2
- package/public/assets/{lucide-react-NXHPIMsX.js.map → lucide-react-DD_zIava.js.map} +1 -1
- package/public/assets/maintenance-CEiURaYZ.js +2 -0
- package/public/assets/{maintenance-CJ6wikpg.js.map → maintenance-CEiURaYZ.js.map} +1 -1
- package/public/assets/{managed-agents-JZn0xNJR.js → managed-agents-CetHyuQW.js} +4 -4
- package/public/assets/{managed-agents-JZn0xNJR.js.map → managed-agents-CetHyuQW.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-BsvAkpR4.js → markdown-preview-impl-ZwGYvObh.js} +2 -2
- package/public/assets/{markdown-preview-impl-BsvAkpR4.js.map → markdown-preview-impl-ZwGYvObh.js.map} +1 -1
- package/public/assets/memory-BTm8XzCg.js +2 -0
- package/public/assets/{memory-BE9IwCdC.js.map → memory-BTm8XzCg.js.map} +1 -1
- package/public/assets/{messages-vXgdc3H4.js → messages-fJd17pzv.js} +2 -2
- package/public/assets/{messages-vXgdc3H4.js.map → messages-fJd17pzv.js.map} +1 -1
- package/public/assets/{orchestrators-CribhLg-.js → orchestrators-C5XQ2UYy.js} +2 -2
- package/public/assets/{orchestrators-CribhLg-.js.map → orchestrators-C5XQ2UYy.js.map} +1 -1
- package/public/assets/overview-Bhk-tqKc.js +2 -0
- package/public/assets/{overview-q3O9K9VK.js.map → overview-Bhk-tqKc.js.map} +1 -1
- package/public/assets/{pairs-BNOnd0IE.js → pairs-CBrszSZh.js} +2 -2
- package/public/assets/{pairs-BNOnd0IE.js.map → pairs-CBrszSZh.js.map} +1 -1
- package/public/assets/{projects-iDkxAGBW.js → projects-DXy9JviE.js} +2 -2
- package/public/assets/{projects-iDkxAGBW.js.map → projects-DXy9JviE.js.map} +1 -1
- package/public/assets/prompt-settings-DEQhAt2X.js +2 -0
- package/public/assets/{prompt-settings-Bdz_xCgD.js.map → prompt-settings-DEQhAt2X.js.map} +1 -1
- package/public/assets/{react-dom-8yaD9iJG.js → react-dom-CADlISeR.js} +2 -2
- package/public/assets/{react-dom-8yaD9iJG.js.map → react-dom-CADlISeR.js.map} +1 -1
- package/public/assets/{registry-DPcyGypi.js → registry-DsZILce1.js} +4 -4
- package/public/assets/{registry-DPcyGypi.js.map → registry-DsZILce1.js.map} +1 -1
- package/public/assets/{security-Z3l3u-Pl.js → security-C-wVZm5k.js} +2 -2
- package/public/assets/{security-Z3l3u-Pl.js.map → security-C-wVZm5k.js.map} +1 -1
- package/public/assets/{select-BX_lW49D.js → select-DsEGBLJk.js} +2 -2
- package/public/assets/{select-BX_lW49D.js.map → select-DsEGBLJk.js.map} +1 -1
- package/public/assets/settings-D3_r5IGA.js +6 -0
- package/public/assets/{settings-Y381jZt7.js.map → settings-D3_r5IGA.js.map} +1 -1
- package/public/assets/{store-D-Frk_EC.js → store-DKTb9O0v.js} +5 -5
- package/public/assets/{store-D-Frk_EC.js.map → store-DKTb9O0v.js.map} +1 -1
- package/public/assets/{task-chip-CeujtXYT.js → task-chip-DwdauC08.js} +2 -2
- package/public/assets/{task-chip-CeujtXYT.js.map → task-chip-DwdauC08.js.map} +1 -1
- package/public/assets/{tasks-Di6d0_Ch.js → tasks-DnEzBku4.js} +2 -2
- package/public/assets/{tasks-Di6d0_Ch.js.map → tasks-DnEzBku4.js.map} +1 -1
- package/public/assets/{teams-DJv4l-_l.js → teams-DpAbZ3ye.js} +2 -2
- package/public/assets/{teams-DJv4l-_l.js.map → teams-DpAbZ3ye.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-3zBLpRel.js → terminal-viewer-impl-_IU5o8ya.js} +3 -3
- package/public/assets/{terminal-viewer-impl-3zBLpRel.js.map → terminal-viewer-impl-_IU5o8ya.js.map} +1 -1
- package/public/assets/types-BqeSkWrv.js.map +1 -1
- package/public/assets/{use-keyboard-viewport-cGEmrGE7.js → use-keyboard-viewport-wTh5CR4-.js} +2 -2
- package/public/assets/{use-keyboard-viewport-cGEmrGE7.js.map → use-keyboard-viewport-wTh5CR4-.js.map} +1 -1
- package/public/assets/user-avatar-CZ3XO8ml.js +2 -0
- package/public/assets/{user-avatar-qbo-B3dQ.js.map → user-avatar-CZ3XO8ml.js.map} +1 -1
- package/public/assets/{work-queue-D73-hP0c.js → work-queue-DKcLZWRl.js} +2 -2
- package/public/assets/{work-queue-D73-hP0c.js.map → work-queue-DKcLZWRl.js.map} +1 -1
- package/public/assets/workspaces-Cs2IZZOI.js +3 -0
- package/public/assets/{workspaces-CoDz-iZd.js.map → workspaces-Cs2IZZOI.js.map} +1 -1
- package/public/index.html +24 -24
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +4 -1
- package/runner/src/adapter.ts +5 -1
- package/runner/src/adapters/claude-delivery.ts +5 -1
- package/runner/src/adapters/claude-transcript.ts +52 -3
- package/runner/src/control-server.ts +34 -17
- package/runner/src/runner-core.ts +73 -32
- package/scripts/orchestrator-spawn-smoke.ts +81 -15
- package/src/bus.ts +6 -41
- package/src/db/messages.ts +20 -8
- package/src/prompt-resolver.ts +12 -12
- package/src/self-resume.ts +50 -8
- package/src/services/bus-command-update.ts +59 -0
- package/src/services/task-delivery.ts +30 -3
- package/public/assets/agents-Dt5TncjC.js +0 -2
- package/public/assets/chat-DhYX9BDG.js +0 -2
- package/public/assets/chat-DhYX9BDG.js.map +0 -1
- package/public/assets/copy-button-C67FUG3E.js +0 -2
- package/public/assets/dist-BJKxqIQd.js +0 -2
- package/public/assets/dist-CHKra2JV.js +0 -2
- package/public/assets/dist-G8YBD-wp.js +0 -2
- package/public/assets/formatted-body-D5-1aiyB.js +0 -3
- package/public/assets/index-BdNafiPz.js +0 -26
- package/public/assets/maintenance-CJ6wikpg.js +0 -2
- package/public/assets/memory-BE9IwCdC.js +0 -2
- package/public/assets/overview-q3O9K9VK.js +0 -2
- package/public/assets/prompt-settings-Bdz_xCgD.js +0 -2
- package/public/assets/settings-Y381jZt7.js +0 -6
- package/public/assets/user-avatar-qbo-B3dQ.js +0 -2
- package/public/assets/workspaces-CoDz-iZd.js +0 -3
package/src/bus.ts
CHANGED
|
@@ -3,9 +3,7 @@ import { ValidationError, getAgent, getDb, heartbeat, markReady, mergeAgentMeta,
|
|
|
3
3
|
import { getOutboxCursor, hasReplayGap, replayEventsSlice, type BusEvent } from "./bus-outbox";
|
|
4
4
|
import { projectAgentStatusData } from "./agent-card-projection";
|
|
5
5
|
import { emitRelayEvent, subscribeRelayEvents, type RelayEvent } from "./events";
|
|
6
|
-
import {
|
|
7
|
-
import { emitCommandEvent } from "./command-events";
|
|
8
|
-
import { noteAgentTimelineEvent, noteCompactionCommandCompleted } from "./compaction-watch";
|
|
6
|
+
import { noteAgentTimelineEvent } from "./compaction-watch";
|
|
9
7
|
import { reconcileTerminalProviderExit } from "./services/terminal-provider-exit";
|
|
10
8
|
import { bindSpawnedTaskToReadyAgent, registerAgent } from "./services/register-agent";
|
|
11
9
|
import { authContextFromBus } from "./services/auth-context";
|
|
@@ -15,9 +13,8 @@ import { agentProviderTimelineEvent, auditRunnerTimelineEvent } from "./provider
|
|
|
15
13
|
import { ServiceAuthError } from "./services/errors";
|
|
16
14
|
import { ShutdownAuthError, ShutdownTargetError, shutdownAgent, shutdownInputFromBusFrame } from "./services/shutdown-agent";
|
|
17
15
|
import { flushQueuedDirectMessages } from "./services/managed-running";
|
|
16
|
+
import { updateCommandFromBus } from "./services/bus-command-update";
|
|
18
17
|
import { isAgentUnavailable } from "./db/agent-predicates";
|
|
19
|
-
import { applyCommandToRecipe } from "./recipe-runner";
|
|
20
|
-
import { enqueueContinuationInjectionAfterSelfResume } from "./self-resume";
|
|
21
18
|
import { messageMatchesAgent, targetMatchesAgent } from "./agent-ref";
|
|
22
19
|
import { probeWorkspaceOnTurnEnd } from "./workspace-probe";
|
|
23
20
|
import { busStaleGraceMs } from "./config";
|
|
@@ -31,7 +28,7 @@ import {
|
|
|
31
28
|
} from "agent-relay-sdk/protocol";
|
|
32
29
|
import { errMessage, isRecord } from "agent-relay-sdk";
|
|
33
30
|
import { getComponentAuth, isComponentAuthorizedFor, isAuthorized, isOriginAllowed, unauthorized } from "./security";
|
|
34
|
-
import type { AgentCard,
|
|
31
|
+
import type { AgentCard, ComponentToken, ContextState, Message, ProviderCapabilities, QuotaState, RegisterAgentInput, Task } from "./types";
|
|
35
32
|
|
|
36
33
|
interface BusSocketData {
|
|
37
34
|
kind: "bus";
|
|
@@ -238,30 +235,9 @@ function handleCommandFrame(
|
|
|
238
235
|
params: Record<string, unknown>,
|
|
239
236
|
): void {
|
|
240
237
|
if (commandType === "command.update") {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (!busCommandAuthorized(conn, command)) {
|
|
247
|
-
sendCommandResult(ws, frameId, "rejected", undefined, "component token lacks command scope");
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
const status = typeof params.status === "string" ? params.status : undefined;
|
|
251
|
-
const updated = updateCommand(command.id, {
|
|
252
|
-
status: status as any,
|
|
253
|
-
result: isRecord(params.result) ? params.result : undefined,
|
|
254
|
-
error: typeof params.error === "string" ? params.error : undefined,
|
|
255
|
-
});
|
|
256
|
-
if (updated) {
|
|
257
|
-
applyCommandToRecipe(updated);
|
|
258
|
-
emitCommandEvent(updated, `command.${updated.status}`);
|
|
259
|
-
// Production command completions arrive here over the bus, not the HTTP
|
|
260
|
-
// PATCH route — arm the stall watch for finished compact/clear commands.
|
|
261
|
-
noteCompactionCommandCompleted(updated.type, updated.status, updated.id, updated.target);
|
|
262
|
-
enqueueContinuationInjectionAfterSelfResume(updated);
|
|
263
|
-
}
|
|
264
|
-
sendCommandResult(ws, frameId, "succeeded", updated ? { command: updated } : undefined);
|
|
238
|
+
void updateCommandFromBus({ target, params, componentAuth: conn.componentAuth })
|
|
239
|
+
.then((result) => sendCommandResult(ws, frameId, result.status, result.result, result.error))
|
|
240
|
+
.catch((error) => sendError(ws, frameId, "FRAME_FAILED", errMessage(error)));
|
|
265
241
|
return;
|
|
266
242
|
}
|
|
267
243
|
|
|
@@ -303,17 +279,6 @@ function handleCommandFrame(
|
|
|
303
279
|
}
|
|
304
280
|
}
|
|
305
281
|
|
|
306
|
-
function busCommandAuthorized(
|
|
307
|
-
conn: BusConnection,
|
|
308
|
-
command: Pick<Command, "target" | "params">,
|
|
309
|
-
): boolean {
|
|
310
|
-
if (!conn.componentAuth) return true;
|
|
311
|
-
return isComponentAuthorizedFor(conn.componentAuth, {
|
|
312
|
-
scope: "command:write",
|
|
313
|
-
resource: commandAuthorizationResource(command),
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
|
|
317
282
|
function handleRegister(ws: BusWebSocket, frame: RegisterFrame): void {
|
|
318
283
|
const payload = frame.payload;
|
|
319
284
|
const runnerManaged = payload.meta?.runnerManaged === true || typeof payload.meta?.runnerId === "string";
|
package/src/db/messages.ts
CHANGED
|
@@ -138,8 +138,10 @@ function normalizeMessagePayload(payload: MessagePayload | undefined): MessagePa
|
|
|
138
138
|
* stable `payload.session.stepId`. Instead of appending a second row (which renders as a
|
|
139
139
|
* duplicate on dashboard reload), update the EXISTING row in place: same DB id, so the
|
|
140
140
|
* dashboard's id-keyed merge replaces it. Gated on stepId presence + matching step, so the
|
|
141
|
-
* Claude transcript path (no stepId) is byte-identical.
|
|
142
|
-
*
|
|
141
|
+
* Claude transcript path (no stepId) is byte-identical. The row keeps the first event's
|
|
142
|
+
* occurredAt so long-running tools stay anchored at their start; completion time rides in
|
|
143
|
+
* payload.session.completedAt. Lifecycle rank still prevents a late running retry from
|
|
144
|
+
* clobbering an already-completed row.
|
|
143
145
|
*/
|
|
144
146
|
function upsertSessionStepInPlace(existing: Message, input: SendMessageInput, now: number): Message | null {
|
|
145
147
|
const incomingStep = sessionStepId(input.payload);
|
|
@@ -147,14 +149,24 @@ function upsertSessionStepInPlace(existing: Message, input: SendMessageInput, no
|
|
|
147
149
|
if (existing.kind !== "session") return null;
|
|
148
150
|
if (sessionStepId(existing.payload) !== incomingStep) return null;
|
|
149
151
|
const incomingAt = sanitizeOccurredAt(input.occurredAt, now) ?? now;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
getDb()
|
|
153
|
-
.query("UPDATE messages SET body = ?, payload = ?, occurred_at = ? WHERE id = ?")
|
|
154
|
-
.run(input.body, JSON.stringify(input.payload ?? {}), incomingAt, existing.id);
|
|
152
|
+
if (sessionStepStatusRank(input.payload) < sessionStepStatusRank(existing.payload)) return null;
|
|
153
|
+
const payload = sessionPayloadWithCompletion(input.payload, incomingAt);
|
|
154
|
+
getDb().query("UPDATE messages SET body = ?, payload = ? WHERE id = ?").run(input.body, JSON.stringify(payload), existing.id);
|
|
155
155
|
return getMessage(existing.id);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
function sessionStepStatusRank(payload: MessagePayload | undefined): number {
|
|
159
|
+
const status = stringValue(isRecord(payload?.session) ? payload.session.status : undefined);
|
|
160
|
+
return status === "completed" || status === "failed" ? 2 : status === "running" ? 1 : 0;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function sessionPayloadWithCompletion(payload: MessagePayload | undefined, completedAt: number): MessagePayload {
|
|
164
|
+
const original = payload ?? {};
|
|
165
|
+
const session = isRecord(original.session) ? original.session : undefined;
|
|
166
|
+
const status = stringValue(session?.status);
|
|
167
|
+
return status === "completed" || status === "failed" ? { ...original, session: { ...session, completedAt } } : original;
|
|
168
|
+
}
|
|
169
|
+
|
|
158
170
|
function policyNameFromTarget(target: string): string | null {
|
|
159
171
|
if (!target.startsWith("policy:")) return null;
|
|
160
172
|
const name = target.slice("policy:".length).trim();
|
|
@@ -256,7 +268,7 @@ function lineageStreamTurnId(message: Message, session: Record<string, unknown>)
|
|
|
256
268
|
}
|
|
257
269
|
|
|
258
270
|
function lineageStreamEventId(message: Message, session: Record<string, unknown>): string {
|
|
259
|
-
const occurredAt = message.occurredAt ?? message.createdAt;
|
|
271
|
+
const occurredAt = typeof session.completedAt === "number" && Number.isFinite(session.completedAt) ? Math.floor(session.completedAt) : message.occurredAt ?? message.createdAt;
|
|
260
272
|
const stepId = stringValue(session.stepId);
|
|
261
273
|
return stepId ? `${stepId}:${occurredAt}` : `message:${occurredAt}`;
|
|
262
274
|
}
|
package/src/prompt-resolver.ts
CHANGED
|
@@ -147,35 +147,35 @@ const DEFAULT_PROMPT_TEMPLATES = [
|
|
|
147
147
|
"Objective (verbatim, relay-owned):",
|
|
148
148
|
"{{objective}}",
|
|
149
149
|
"",
|
|
150
|
-
"Ruled-out ledger (append-only):",
|
|
151
|
-
"{{ruledOut}}",
|
|
152
|
-
"",
|
|
153
|
-
"Decision log (append-only):",
|
|
154
|
-
"{{decisions}}",
|
|
155
|
-
"",
|
|
156
150
|
"Working state:",
|
|
157
151
|
"{{workingState}}",
|
|
158
152
|
"",
|
|
159
153
|
"Archive refs:",
|
|
160
154
|
"{{archiveRefs}}",
|
|
161
|
-
),
|
|
162
|
-
defaultTemplate: lines(
|
|
163
|
-
"{{intro}}",
|
|
164
|
-
"",
|
|
165
|
-
"Objective (verbatim, relay-owned):",
|
|
166
|
-
"{{objective}}",
|
|
167
155
|
"",
|
|
168
156
|
"Ruled-out ledger (append-only):",
|
|
169
157
|
"{{ruledOut}}",
|
|
170
158
|
"",
|
|
171
159
|
"Decision log (append-only):",
|
|
172
160
|
"{{decisions}}",
|
|
161
|
+
),
|
|
162
|
+
defaultTemplate: lines(
|
|
163
|
+
"{{intro}}",
|
|
164
|
+
"",
|
|
165
|
+
"Objective (verbatim, relay-owned):",
|
|
166
|
+
"{{objective}}",
|
|
173
167
|
"",
|
|
174
168
|
"Working state:",
|
|
175
169
|
"{{workingState}}",
|
|
176
170
|
"",
|
|
177
171
|
"Archive refs:",
|
|
178
172
|
"{{archiveRefs}}",
|
|
173
|
+
"",
|
|
174
|
+
"Ruled-out ledger (append-only):",
|
|
175
|
+
"{{ruledOut}}",
|
|
176
|
+
"",
|
|
177
|
+
"Decision log (append-only):",
|
|
178
|
+
"{{decisions}}",
|
|
179
179
|
),
|
|
180
180
|
variables: ["intro", "generation", "objective", "ruledOut", "decisions", "workingState", "archiveRefs"],
|
|
181
181
|
},
|
package/src/self-resume.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
findMessageByIdempotencyKey,
|
|
10
10
|
getAgent,
|
|
11
11
|
getContinuationEnvelope,
|
|
12
|
+
sendMessage,
|
|
12
13
|
updateContinuationAfterCompact,
|
|
13
14
|
ValidationError,
|
|
14
15
|
} from "./db";
|
|
@@ -31,6 +32,7 @@ interface CompactAndResumeResult {
|
|
|
31
32
|
generation: number;
|
|
32
33
|
commandId: string;
|
|
33
34
|
continuationChars?: number;
|
|
35
|
+
continuationMessageId?: number;
|
|
34
36
|
ledgerEntries: number;
|
|
35
37
|
exhausted?: boolean;
|
|
36
38
|
reason?: string;
|
|
@@ -91,10 +93,12 @@ export function compactAndResume(input: CompactAndResumeInput): CompactAndResume
|
|
|
91
93
|
now,
|
|
92
94
|
});
|
|
93
95
|
if (updated.droppedLedgerEntries.length) archiveDroppedLedgerEntries(agent.id, generation, updated.droppedLedgerEntries, now);
|
|
94
|
-
const
|
|
96
|
+
const fullContinuation = renderContinuation(updated.envelope);
|
|
97
|
+
const continuationMessage = createContinuationRecoveryMessage(agent.id, generation, fullContinuation, now);
|
|
98
|
+
const continuation = insertRecoveryPointerAfterIntro(fullContinuation, continuationMessage.id);
|
|
95
99
|
const command = mode === "native"
|
|
96
|
-
? createNativeCompact(agent.id, generation, continuation)
|
|
97
|
-
: createClearThenInject(agent.id, generation, continuation);
|
|
100
|
+
? createNativeCompact(agent.id, generation, continuation, continuationMessage.id)
|
|
101
|
+
: createClearThenInject(agent.id, generation, continuation, continuationMessage.id);
|
|
98
102
|
emitCommandEvent(command, "command.requested");
|
|
99
103
|
return {
|
|
100
104
|
ok: true,
|
|
@@ -102,10 +106,45 @@ export function compactAndResume(input: CompactAndResumeInput): CompactAndResume
|
|
|
102
106
|
generation,
|
|
103
107
|
commandId: command.id,
|
|
104
108
|
continuationChars: continuation.length,
|
|
109
|
+
continuationMessageId: continuationMessage.id,
|
|
105
110
|
ledgerEntries: updated.envelope.ledger.length,
|
|
106
111
|
};
|
|
107
112
|
}
|
|
108
113
|
|
|
114
|
+
function continuationRecoveryPointer(messageId: number): string {
|
|
115
|
+
return `Recovery pointer: use relay_get_message with message id ${messageId} to read your full prior context.`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function insertRecoveryPointerAfterIntro(continuation: string, messageId: number): string {
|
|
119
|
+
const pointer = continuationRecoveryPointer(messageId);
|
|
120
|
+
const firstNewline = continuation.indexOf("\n");
|
|
121
|
+
if (firstNewline === -1) return `${continuation.trimEnd()}\n\n${pointer}`;
|
|
122
|
+
return `${continuation.slice(0, firstNewline).trimEnd()}\n${pointer}${continuation.slice(firstNewline)}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function createContinuationRecoveryMessage(agentId: string, generation: number, continuation: string, now: number) {
|
|
126
|
+
const idempotencyKey = `self-resume-continuation:${agentId}:${generation}`;
|
|
127
|
+
const existing = findMessageByIdempotencyKey("system", idempotencyKey);
|
|
128
|
+
if (existing) return existing;
|
|
129
|
+
return sendMessage({
|
|
130
|
+
from: "system",
|
|
131
|
+
to: agentId,
|
|
132
|
+
kind: "system",
|
|
133
|
+
subject: `Self-resume continuation generation ${generation}`,
|
|
134
|
+
body: continuation,
|
|
135
|
+
replyExpected: false,
|
|
136
|
+
idempotencyKey,
|
|
137
|
+
maxAgeSeconds: null,
|
|
138
|
+
occurredAt: now,
|
|
139
|
+
payload: {
|
|
140
|
+
kind: "agent.self_resume_continuation",
|
|
141
|
+
agentId,
|
|
142
|
+
generation,
|
|
143
|
+
fullEnvelope: true,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
109
148
|
// #1023 — the ruledOut ledger bound (see updateContinuationAfterCompact) drops the
|
|
110
149
|
// oldest entries once the persisted ledger grows past its cap instead of letting a
|
|
111
150
|
// long-running agent render a multi-megabyte continuation. Dropped entries are not
|
|
@@ -142,6 +181,7 @@ interface PendingInjection {
|
|
|
142
181
|
continuation: string;
|
|
143
182
|
mode: string;
|
|
144
183
|
generation?: number;
|
|
184
|
+
fullContextMessageId?: number;
|
|
145
185
|
}
|
|
146
186
|
|
|
147
187
|
function extractPendingInjection(command: Command): PendingInjection | null {
|
|
@@ -158,7 +198,8 @@ function extractPendingInjection(command: Command): PendingInjection | null {
|
|
|
158
198
|
: undefined;
|
|
159
199
|
if (!continuation) return null;
|
|
160
200
|
const generation = typeof resume?.generation === "number" ? resume.generation : undefined;
|
|
161
|
-
|
|
201
|
+
const fullContextMessageId = typeof resume?.fullContextMessageId === "number" ? resume.fullContextMessageId : undefined;
|
|
202
|
+
return { continuation, mode, generation, fullContextMessageId };
|
|
162
203
|
}
|
|
163
204
|
|
|
164
205
|
function buildInjectionParams(command: Command, injection: PendingInjection): Record<string, unknown> {
|
|
@@ -168,6 +209,7 @@ function buildInjectionParams(command: Command, injection: PendingInjection): Re
|
|
|
168
209
|
selfResume: {
|
|
169
210
|
generation: injection.generation,
|
|
170
211
|
mode: injection.mode,
|
|
212
|
+
fullContextMessageId: injection.fullContextMessageId,
|
|
171
213
|
...(command.type === "agent.clearContext" ? { afterClearCommandId: command.id } : {}),
|
|
172
214
|
...(command.type === "agent.compact" ? { afterCompactCommandId: command.id } : {}),
|
|
173
215
|
},
|
|
@@ -376,7 +418,7 @@ function hardLimit(limit: number, multiplier: number): number {
|
|
|
376
418
|
return Math.ceil(limit * multiplier);
|
|
377
419
|
}
|
|
378
420
|
|
|
379
|
-
function createNativeCompact(agentId: string, generation: number, continuation: string): Command {
|
|
421
|
+
function createNativeCompact(agentId: string, generation: number, continuation: string, fullContextMessageId: number): Command {
|
|
380
422
|
return createCommand({
|
|
381
423
|
type: "agent.compact",
|
|
382
424
|
source: "system",
|
|
@@ -384,19 +426,19 @@ function createNativeCompact(agentId: string, generation: number, continuation:
|
|
|
384
426
|
params: {
|
|
385
427
|
reason: "self-resume",
|
|
386
428
|
instructions: continuation,
|
|
387
|
-
selfResume: { generation, mode: "native", continuation },
|
|
429
|
+
selfResume: { generation, mode: "native", continuation, fullContextMessageId },
|
|
388
430
|
},
|
|
389
431
|
});
|
|
390
432
|
}
|
|
391
433
|
|
|
392
|
-
function createClearThenInject(agentId: string, generation: number, continuation: string): Command {
|
|
434
|
+
function createClearThenInject(agentId: string, generation: number, continuation: string, fullContextMessageId: number): Command {
|
|
393
435
|
return createCommand({
|
|
394
436
|
type: "agent.clearContext",
|
|
395
437
|
source: "system",
|
|
396
438
|
target: agentId,
|
|
397
439
|
params: {
|
|
398
440
|
reason: "self-resume",
|
|
399
|
-
selfResume: { generation, mode: "clear-inject", continuation },
|
|
441
|
+
selfResume: { generation, mode: "clear-inject", continuation, fullContextMessageId },
|
|
400
442
|
},
|
|
401
443
|
});
|
|
402
444
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { isRecord } from "agent-relay-sdk";
|
|
2
|
+
import { getCommand, updateCommand } from "../commands-db";
|
|
3
|
+
import { emitCommandEvent } from "../command-events";
|
|
4
|
+
import { noteCompactionCommandCompleted } from "../compaction-watch";
|
|
5
|
+
import { applyCommandToRecipe } from "../recipe-runner";
|
|
6
|
+
import { enqueueContinuationInjectionAfterSelfResume } from "../self-resume";
|
|
7
|
+
import { isComponentAuthorizedFor } from "../security";
|
|
8
|
+
import type { Command, ComponentToken } from "../types";
|
|
9
|
+
import { commandAuthorizationResource } from "./dispatch-command";
|
|
10
|
+
import { prepareScheduledCommandResultForStorage, settleScheduledCommandTimer } from "./scheduler-command";
|
|
11
|
+
|
|
12
|
+
type BusCommandUpdateResult = {
|
|
13
|
+
status: "succeeded" | "failed" | "rejected";
|
|
14
|
+
result?: Record<string, unknown>;
|
|
15
|
+
error?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export async function updateCommandFromBus(input: {
|
|
19
|
+
target: string;
|
|
20
|
+
params: Record<string, unknown>;
|
|
21
|
+
componentAuth?: ComponentToken;
|
|
22
|
+
}): Promise<BusCommandUpdateResult> {
|
|
23
|
+
const command = getCommand(input.target);
|
|
24
|
+
if (!command) return { status: "failed", error: "command not found" };
|
|
25
|
+
if (!busCommandAuthorized(input.componentAuth, command)) {
|
|
26
|
+
return { status: "rejected", error: "component token lacks command scope" };
|
|
27
|
+
}
|
|
28
|
+
const status = typeof input.params.status === "string" ? input.params.status : undefined;
|
|
29
|
+
let result = isRecord(input.params.result) ? input.params.result : undefined;
|
|
30
|
+
if (result && command.type === "scheduler.command") {
|
|
31
|
+
result = await prepareScheduledCommandResultForStorage(command, result);
|
|
32
|
+
}
|
|
33
|
+
const updated = updateCommand(command.id, {
|
|
34
|
+
status: status as any,
|
|
35
|
+
result,
|
|
36
|
+
error: typeof input.params.error === "string" ? input.params.error : undefined,
|
|
37
|
+
});
|
|
38
|
+
if (updated) {
|
|
39
|
+
applyCommandToRecipe(updated);
|
|
40
|
+
if (updated.type === "scheduler.command") {
|
|
41
|
+
await settleScheduledCommandTimer(updated);
|
|
42
|
+
}
|
|
43
|
+
emitCommandEvent(updated, `command.${updated.status}`);
|
|
44
|
+
noteCompactionCommandCompleted(updated.type, updated.status, updated.id, updated.target);
|
|
45
|
+
enqueueContinuationInjectionAfterSelfResume(updated);
|
|
46
|
+
}
|
|
47
|
+
return { status: "succeeded", result: updated ? { command: updated } : undefined };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function busCommandAuthorized(
|
|
51
|
+
auth: ComponentToken | undefined,
|
|
52
|
+
command: Pick<Command, "target" | "params">,
|
|
53
|
+
): boolean {
|
|
54
|
+
if (!auth) return true;
|
|
55
|
+
return isComponentAuthorizedFor(auth, {
|
|
56
|
+
scope: "command:write",
|
|
57
|
+
resource: commandAuthorizationResource(command),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ownedIsolatedWorkspace,
|
|
7
7
|
recordGate,
|
|
8
8
|
recordTaskDeliverable,
|
|
9
|
+
setTaskStage,
|
|
9
10
|
setTaskStatus,
|
|
10
11
|
ValidationError,
|
|
11
12
|
} from "../db";
|
|
@@ -62,7 +63,17 @@ function resolveTaskId(ctx: AuthContext, explicit: unknown): number {
|
|
|
62
63
|
throw new ValidationError("caller is bound to multiple Tasks; pass taskId explicitly");
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
function
|
|
66
|
+
function canRebindToWorkspace(ctx: AuthContext, task: TaskDetail, ws: WorkspaceRecord): boolean {
|
|
67
|
+
const caller = ctx.callerAgentId;
|
|
68
|
+
if (!caller || ws.ownerAgentId !== caller) return false;
|
|
69
|
+
return task.ownerAgentId === caller || agentBoundTaskIds(caller).has(task.id);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function shouldRebindToWorkspace(task: TaskDetail, ws: WorkspaceRecord | undefined): ws is WorkspaceRecord {
|
|
73
|
+
return Boolean(task.branch && ws?.branch && task.branch !== ws.branch);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function resolveWorkspace(ctx: AuthContext, input: { workspaceId?: string }, taskId: number, opts: { allowRebind?: boolean } = {}): WorkspaceRecord | undefined {
|
|
66
77
|
const caller = ctx.callerAgentId;
|
|
67
78
|
const explicit = input.workspaceId?.trim();
|
|
68
79
|
const ws = explicit ? getWorkspace(explicit) : caller ? ownedIsolatedWorkspace(caller) : undefined;
|
|
@@ -73,11 +84,26 @@ function resolveWorkspace(ctx: AuthContext, input: { workspaceId?: string }, tas
|
|
|
73
84
|
const task = getTaskDetail(taskId);
|
|
74
85
|
if (!task) throw new ValidationError("task not found");
|
|
75
86
|
if (task.branch && ws.branch && task.branch !== ws.branch) {
|
|
87
|
+
if (opts.allowRebind && canRebindToWorkspace(ctx, task, ws)) return ws;
|
|
76
88
|
throw new ValidationError(`task ${taskId} is bound to branch ${task.branch}, not workspace branch ${ws.branch}`);
|
|
77
89
|
}
|
|
78
90
|
return ws;
|
|
79
91
|
}
|
|
80
92
|
|
|
93
|
+
function rebindTaskToWorkspaceIfNeeded(task: TaskDetail, ws: WorkspaceRecord | undefined, actor: string): TaskDetail {
|
|
94
|
+
if (!shouldRebindToWorkspace(task, ws)) return task;
|
|
95
|
+
setTaskStatus(task.id, {
|
|
96
|
+
status: "in_progress",
|
|
97
|
+
note: `fix-forward rebind to workspace ${ws.id} (${ws.branch})`,
|
|
98
|
+
actor,
|
|
99
|
+
});
|
|
100
|
+
return setTaskStage(task.id, {
|
|
101
|
+
deliverableStage: "committed-on-branch",
|
|
102
|
+
branch: ws.branch,
|
|
103
|
+
actor,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
81
107
|
function gateWrites(gates: TaskDeliveryGateReports | undefined, deliveryKey: string): GateWrite[] {
|
|
82
108
|
const writes: GateWrite[] = [];
|
|
83
109
|
if (gates?.typecheck) writes.push({ gate: "typecheck", ...gatePayload(gates.typecheck, `${deliveryKey}:typecheck`) });
|
|
@@ -207,10 +233,11 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
|
|
|
207
233
|
if (gateProblem) throw new ValidationError(`complete delivery cannot land without passing gate block (${gateProblem})`);
|
|
208
234
|
const reason = input.disposition === "blocked" || input.disposition === "failed" ? cleanReason(input.reason, input.disposition) : undefined;
|
|
209
235
|
const blockedBy = input.disposition === "blocked" ? cleanBlockedBy(input.blockedBy) : input.blockedBy;
|
|
210
|
-
const workspace = wantsLand || input.workspaceId ? resolveWorkspace(ctx, input, taskId) : undefined;
|
|
236
|
+
const workspace = wantsLand || input.workspaceId ? resolveWorkspace(ctx, input, taskId, { allowRebind: wantsLand }) : undefined;
|
|
211
237
|
if (wantsLand && (!workspace || workspace.mode !== "isolated" || !workspace.worktreePath)) {
|
|
212
238
|
throw new ValidationError("complete delivery requires a live isolated workspace");
|
|
213
239
|
}
|
|
240
|
+
const currentTask = wantsLand ? rebindTaskToWorkspaceIfNeeded(before, workspace, actor) : before;
|
|
214
241
|
const landMeta: TaskDeliverableEventMetadata["land"] | undefined = wantsLand && workspace
|
|
215
242
|
? { requested: true, triggered: false, reason: "pending", workspaceId: workspace.id, workspaceStatus: workspace.status }
|
|
216
243
|
: undefined;
|
|
@@ -236,7 +263,7 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
|
|
|
236
263
|
} else if (isVerdictOnlyComplete) {
|
|
237
264
|
setTaskStatus(taskId, { status: "done", note: "complete delivery recorded without land", actor });
|
|
238
265
|
}
|
|
239
|
-
const detail = getTaskDetail(taskId);
|
|
266
|
+
const detail = getTaskDetail(taskId) ?? currentTask;
|
|
240
267
|
if (detail) {
|
|
241
268
|
emitTaskChanged(detail, "task.deliverable");
|
|
242
269
|
notifyDelivery(taskId, delivery.event.id, eventMeta ?? (delivery.event.metadata as unknown as TaskDeliverableEventMetadata));
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{B as t,Gn as n,H as r,Ht as i,Qt as a,Xn as o,_ as s,_t as c,a as l,et as u,g as d,gr as f,q as p,rr as m,rt as h,tr as g,u as _}from"./lucide-react-NXHPIMsX.js";import{p as ee,t as v}from"./store-D-Frk_EC.js";import{_ as te,h as y}from"./types-BqeSkWrv.js";import{J as b,K as x,W as S,Y as C,a as w,d as T,i as ne,n as re}from"./display-aTnwsqQh.js";import{o as E,r as D}from"./dist-BNB3fTO-.js";import{t as O}from"./dist-BD4Xc13v.js";import{i as ie,n as k}from"./dist-BFDfbfNC.js";import{t as A}from"./dist-DG75bvPp.js";import{t as j}from"./dist-CQMQ5iku.js";import{a as M,i as N,n as P,o as F,r as I,s as ae,t as oe}from"./es2015-a6fysEVz.js";import{a as L,i as se,n as R,r as z,t as B}from"./dist-C_VOBSaK.js";import{t as V}from"./badge-BCvp7LK3.js";import{t as H}from"./button-DyHjsHY3.js";import{t as ce}from"./copy-button-C67FUG3E.js";import{t as U}from"./agent-type-icon-BmBR-9CH.js";import{Dt as W,Et as le,J as ue,Ot as de,Y as fe,Z as pe,bt as me,ct as G,et as he,kt as ge,nt as _e,q as ve,rt as ye,tt as be}from"./index-BdNafiPz.js";import{r as xe,t as Se}from"./card-BoqYxpVW.js";import{i as Ce,n as we,r as Te,t as Ee}from"./branch-state-badge-Cscjqf-E.js";var K=e(f(),1),q=m(),J=`Popover`,[De,Oe]=ie(J,[L]),Y=L(),[ke,X]=De(J),Ae=e=>{let{__scopePopover:t,children:n,open:r,defaultOpen:i,onOpenChange:a,modal:o=!1}=e,s=Y(t),c=K.useRef(null),[l,u]=K.useState(!1),[d,f]=A({prop:r,defaultProp:i??!1,onChange:a,caller:J});return(0,q.jsx)(se,{...s,children:(0,q.jsx)(ke,{scope:t,contentId:ae(),triggerRef:c,open:d,onOpenChange:f,onOpenToggle:K.useCallback(()=>f(e=>!e),[f]),hasCustomAnchor:l,onCustomAnchorAdd:K.useCallback(()=>u(!0),[]),onCustomAnchorRemove:K.useCallback(()=>u(!1),[]),modal:o,children:n})})};Ae.displayName=J;var je=`PopoverAnchor`,Me=K.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=X(je,n),a=Y(n),{onCustomAnchorAdd:o,onCustomAnchorRemove:s}=i;return K.useEffect(()=>(o(),()=>s()),[o,s]),(0,q.jsx)(B,{...a,...r,ref:t})});Me.displayName=je;var Z=`PopoverTrigger`,Ne=K.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=X(Z,n),a=Y(n),o=E(t,i.triggerRef),s=(0,q.jsx)(O.button,{type:`button`,"aria-haspopup":`dialog`,"aria-expanded":i.open,"aria-controls":i.contentId,"data-state":Ke(i.open),...r,ref:o,onClick:k(e.onClick,i.onOpenToggle)});return i.hasCustomAnchor?s:(0,q.jsx)(B,{asChild:!0,...a,children:s})});Ne.displayName=Z;var Q=`PopoverPortal`,[Pe,Fe]=De(Q,{forceMount:void 0}),Ie=e=>{let{__scopePopover:t,forceMount:n,children:r,container:i}=e,a=X(Q,t);return(0,q.jsx)(Pe,{scope:t,forceMount:n,children:(0,q.jsx)(j,{present:n||a.open,children:(0,q.jsx)(N,{asChild:!0,container:i,children:r})})})};Ie.displayName=Q;var $=`PopoverContent`,Le=K.forwardRef((e,t)=>{let n=Fe($,e.__scopePopover),{forceMount:r=n.forceMount,...i}=e,a=X($,e.__scopePopover);return(0,q.jsx)(j,{present:r||a.open,children:a.modal?(0,q.jsx)(ze,{...i,ref:t}):(0,q.jsx)(Be,{...i,ref:t})})});Le.displayName=$;var Re=D(`PopoverContent.RemoveScroll`),ze=K.forwardRef((e,t)=>{let n=X($,e.__scopePopover),r=K.useRef(null),i=E(t,r),a=K.useRef(!1);return K.useEffect(()=>{let e=r.current;if(e)return oe(e)},[]),(0,q.jsx)(P,{as:Re,allowPinchZoom:!0,children:(0,q.jsx)(Ve,{...e,ref:i,trapFocus:n.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:k(e.onCloseAutoFocus,e=>{e.preventDefault(),a.current||n.triggerRef.current?.focus()}),onPointerDownOutside:k(e.onPointerDownOutside,e=>{let t=e.detail.originalEvent,n=t.button===0&&t.ctrlKey===!0;a.current=t.button===2||n},{checkForDefaultPrevented:!1}),onFocusOutside:k(e.onFocusOutside,e=>e.preventDefault(),{checkForDefaultPrevented:!1})})})}),Be=K.forwardRef((e,t)=>{let n=X($,e.__scopePopover),r=K.useRef(!1),i=K.useRef(!1);return(0,q.jsx)(Ve,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{e.onCloseAutoFocus?.(t),t.defaultPrevented||(r.current||n.triggerRef.current?.focus(),t.preventDefault()),r.current=!1,i.current=!1},onInteractOutside:t=>{e.onInteractOutside?.(t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type===`pointerdown`&&(i.current=!0));let a=t.target;n.triggerRef.current?.contains(a)&&t.preventDefault(),t.detail.originalEvent.type===`focusin`&&i.current&&t.preventDefault()}})}),Ve=K.forwardRef((e,t)=>{let{__scopePopover:n,trapFocus:r,onOpenAutoFocus:i,onCloseAutoFocus:a,disableOutsidePointerEvents:o,onEscapeKeyDown:s,onPointerDownOutside:c,onFocusOutside:l,onInteractOutside:u,...d}=e,f=X($,n),p=Y(n);return I(),(0,q.jsx)(M,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:i,onUnmountAutoFocus:a,children:(0,q.jsx)(F,{asChild:!0,disableOutsidePointerEvents:o,onInteractOutside:u,onEscapeKeyDown:s,onPointerDownOutside:c,onFocusOutside:l,onDismiss:()=>f.onOpenChange(!1),children:(0,q.jsx)(z,{"data-state":Ke(f.open),role:`dialog`,id:f.contentId,...p,...d,ref:t,style:{...d.style,"--radix-popover-content-transform-origin":`var(--radix-popper-transform-origin)`,"--radix-popover-content-available-width":`var(--radix-popper-available-width)`,"--radix-popover-content-available-height":`var(--radix-popper-available-height)`,"--radix-popover-trigger-width":`var(--radix-popper-anchor-width)`,"--radix-popover-trigger-height":`var(--radix-popper-anchor-height)`}})})})}),He=`PopoverClose`,Ue=K.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=X(He,n);return(0,q.jsx)(O.button,{type:`button`,...r,ref:t,onClick:k(e.onClick,()=>i.onOpenChange(!1))})});Ue.displayName=He;var We=`PopoverArrow`,Ge=K.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=Y(n);return(0,q.jsx)(R,{...i,...r,ref:t})});Ge.displayName=We;function Ke(e){return e?`open`:`closed`}var qe=Ae,Je=Ne,Ye=Ie,Xe=Le;function Ze({...e}){return(0,q.jsx)(qe,{"data-slot":`popover`,...e})}function Qe({...e}){return(0,q.jsx)(Je,{"data-slot":`popover-trigger`,...e})}function $e({className:e,align:t=`center`,sideOffset:n=4,...r}){return(0,q.jsx)(Ye,{children:(0,q.jsx)(Xe,{"data-slot":`popover-content`,align:t,sideOffset:n,className:g(`z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95`,e),...r})})}function et({className:e,...t}){return(0,q.jsx)(`div`,{"data-slot":`popover-header`,className:g(`flex flex-col gap-0.5 text-sm`,e),...t})}function tt({className:e,...t}){return(0,q.jsx)(`div`,{"data-slot":`popover-title`,className:g(`font-medium`,e),...t})}function nt({agent:e,childAgents:n=[],parentAgent:r}){let o=ee();v(e=>e.set);let l=v(e=>e.switchView),f=v(e=>e.openInboxThread),m=v(e=>e.openAgentDetail),g=v(e=>e.openPairInvite),te=v(e=>e.openRename),y=v(e=>e.openConfirm),E=v(e=>e.doAgentAction),D=v(e=>e.doDeleteAgent),O=v(e=>e.openFilesForAgent),ie=v(e=>e.workspaceAction),k=v(e=>e.openWorkspaceFocus),{terminalOpen:A,terminalTarget:j,terminalOpening:M,openTerminal:N,closeTerminal:P}=Ce(e.id),F=le(),I=ne(o,e,me(e),F[e.id]||null),ae=w(e,`shutdown`),oe=w(e,`compact`),L=w(e,`clearContext`),se=!!(e.providerCapabilities?.terminal?.live?.read||e.providerCapabilities?.terminal?.attach?.create),R=!!e.providerCapabilities?.terminal?.live?.write,z=re(e),B=r?T(r):e.spawnedBy,W=n.length>0;return(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(Se,{className:`group hover:border-zinc-600 transition-colors cursor-pointer`,onClick:()=>m(e),children:(0,q.jsxs)(xe,{className:`p-4`,children:[(0,q.jsxs)(`div`,{className:`flex items-start gap-2.5 mb-2.5`,children:[(0,q.jsx)(G,{agent:e,now:o,className:`mt-0.5`}),(0,q.jsx)(U,{agent:e}),(0,q.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,q.jsxs)(`div`,{className:`flex items-center gap-1 min-w-0`,children:[(0,q.jsx)(we,{profile:Te(e),className:`text-sm shrink-0`}),(0,q.jsx)(`span`,{className:`text-sm font-medium truncate`,children:T(e)})]}),(0,q.jsx)(`div`,{className:`text-xs mt-0.5 ${b(I.tone)}`,children:I.label}),typeof e.meta?.cwd==`string`&&e.meta.cwd&&(0,q.jsx)(`button`,{type:`button`,className:`mt-0.5 block max-w-full truncate font-mono text-[10px] text-muted-foreground hover:text-foreground`,title:`Open ${e.meta.cwd} in Files`,onClick:t=>{t.stopPropagation(),O(e)},children:S(e.meta.cwd)}),(0,q.jsx)(pe,{agent:e,className:`mt-1`})]}),e.branchState&&e.branchWorkspaceId&&(0,q.jsx)(Ee,{state:e.branchState,className:`mt-0.5 shrink-0`,onClick:t=>{t.stopPropagation(),k(e.branchWorkspaceId)}})]}),I.badges.length>0&&(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1 mb-2`,children:I.badges.map(e=>(0,q.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded-full font-medium ${e.className}`,children:e.label},e.label))}),(W||e.spawnedBy&&B)&&(0,q.jsxs)(`div`,{className:`mb-2 flex flex-wrap gap-1.5`,onClick:e=>e.stopPropagation(),children:[W&&(0,q.jsxs)(Ze,{children:[(0,q.jsx)(Qe,{asChild:!0,children:(0,q.jsxs)(`button`,{type:`button`,className:`inline-flex h-6 max-w-full items-center gap-1.5 rounded-full border border-sky-500/30 bg-sky-500/10 px-2 text-[10px] font-medium text-sky-300 transition-colors hover:bg-sky-500/15`,title:`${n.length} live child ${n.length===1?`agent`:`agents`}`,children:[(0,q.jsx)(_,{className:`h-3 w-3`}),(0,q.jsx)(`span`,{children:n.length}),(0,q.jsx)(`span`,{className:`flex -space-x-1`,children:n.slice(0,4).map(e=>(0,q.jsx)(G,{agent:e,now:o,className:`h-2 w-2 ring-1 ring-background`},e.id))})]})}),(0,q.jsxs)($e,{align:`start`,className:`w-80`,onClick:e=>e.stopPropagation(),children:[(0,q.jsx)(et,{children:(0,q.jsx)(tt,{children:`Team`})}),(0,q.jsx)(`div`,{className:`space-y-1.5`,children:n.map(e=>(0,q.jsxs)(`div`,{className:`rounded-md border border-border bg-card/60 p-2`,children:[(0,q.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,q.jsx)(G,{agent:e,now:o,className:`mt-1`}),(0,q.jsx)(U,{agent:e}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`truncate text-xs font-medium`,children:T(e)}),(0,q.jsx)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:e.providerCapabilities?.model?.alias||e.providerCapabilities?.model?.id||e.providerCapabilities?.model?.provider||e.status})]}),(0,q.jsx)(V,{variant:`outline`,className:`h-4 px-1.5 text-[9px]`,children:e.status})]}),(0,q.jsxs)(`div`,{className:`mt-2 flex gap-1`,children:[(0,q.jsx)(H,{size:`xs`,variant:`outline`,onClick:()=>m(e),children:`Open`}),(0,q.jsxs)(H,{size:`xs`,variant:`ghost`,onClick:()=>{f(e.id),l(`chat`)},children:[(0,q.jsx)(h,{className:`h-3 w-3`}),`Chat`]})]})]},e.id))})]})]}),e.spawnedBy&&B&&(0,q.jsx)(V,{variant:`outline`,className:`max-w-full text-[10px] text-muted-foreground`,children:(0,q.jsxs)(`span`,{className:`truncate`,children:[`spawned by `,B]})})]}),(e.tags.length>0||C(e.capabilities).length>0)&&(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-1 mb-2`,children:[e.tags.slice(0,3).map(e=>(0,q.jsx)(V,{variant:`outline`,className:`text-[9px] px-1 py-0 h-4`,children:e},e)),C(e.capabilities).slice(0,2).map(e=>(0,q.jsx)(V,{variant:`secondary`,className:`text-[9px] px-1 py-0 h-4`,children:e},e))]}),(0,q.jsxs)(`div`,{className:`space-y-2 mb-2`,children:[(0,q.jsx)(_e,{agent:e}),(0,q.jsx)(be,{agent:e,compact:!0}),(0,q.jsx)(ye,{agent:e})]}),(0,q.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:e.id!==`user`&&e.id!==`system`&&x(o,e.lastSeen)}),(0,q.jsxs)(`div`,{className:`flex gap-1 mt-2.5 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity`,onClick:e=>e.stopPropagation(),children:[(0,q.jsx)(ce,{value:e.id,label:`Copy agent ID`,size:`icon`,className:`h-7 w-7`,iconClassName:`w-3 h-3`}),(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7`,title:`Chat`,onClick:()=>{f(e.id),l(`chat`)},children:(0,q.jsx)(h,{className:`w-3 h-3`})}),(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7`,title:`Pair`,onClick:()=>g(e.id),children:(0,q.jsx)(c,{className:`w-3 h-3`})}),(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7`,title:`Rename`,onClick:()=>te(e),children:(0,q.jsx)(p,{className:`w-3 h-3`})}),se&&(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7`,title:`Terminal`,disabled:M,onClick:()=>void N(),children:(0,q.jsx)(s,{className:`w-3 h-3`})}),(e.branchState===`changes`||e.branchState===`idle`)&&e.branchWorkspaceId&&(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7 text-amber-400 hover:text-amber-300`,title:`Mark workspace ready — hand off to the auto-merge`,onClick:()=>y(`Mark Workspace Ready`,`Mark ${T(e)}'s branch ready to land? The relay auto-merge will rebase and land it.`,()=>ie(e.branchWorkspaceId,`ready`)),children:(0,q.jsx)(i,{className:`w-3 h-3`})}),oe&&(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7`,title:`Compact`,onClick:()=>y(`Compact Agent`,`Compact context for ${T(e)}?`,()=>E(e,`compact`,`agents-grid`)),children:(0,q.jsx)(u,{className:`w-3 h-3`})}),L&&(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7`,title:`Clear Context`,onClick:()=>y(`Clear Context`,`Clear context for ${T(e)}?`,()=>E(e,`clearContext`,`agents-grid`)),children:(0,q.jsx)(a,{className:`w-3 h-3`})}),ae&&(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7 text-red-400 hover:text-red-300`,title:`Shutdown`,onClick:()=>y(`Shutdown Agent`,`Shutdown ${T(e)}?`,()=>E(e,`shutdown`,`agents-grid`)),children:(0,q.jsx)(t,{className:`w-3 h-3`})}),z&&(0,q.jsx)(H,{size:`icon`,variant:`ghost`,className:`h-7 w-7 text-red-400 hover:text-red-300`,title:`Forget stale agent`,onClick:()=>y(`Forget Agent`,`Forget ${T(e)}?`,()=>D(e.id)),children:(0,q.jsx)(d,{className:`w-3 h-3`})})]})]})}),j&&(0,q.jsx)(he,{open:A,onOpenChange:P,orchestratorId:j.orchestratorId,session:j.session,interactive:j.interactive||R,canWrite:R})]})}function rt(){let e=v(e=>e.agentPresetFilter),t=v(e=>e.agentStatusFilter),i=v(e=>e.agentTagFilter),a=v(e=>e.agentHostFilter),s=v(e=>e.agentSort),c=v(e=>e.agentSortDir),u=v(e=>e.showOffline),d=v(e=>e.set),f=v(e=>e.openAgentSpawn),p=v(e=>e.agentsById),m=ee(),h=W(),g=ge(),_=de(),b=ve(h,m),x=fe(h,m),S=e||t||i||a;function C(){d({agentPresetFilter:``,agentStatusFilter:``,agentTagFilter:``,agentHostFilter:``})}function w(){d({agentSortDir:c===`asc`?`desc`:`asc`})}return(0,q.jsxs)(`div`,{className:`space-y-4`,children:[(0,q.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,q.jsxs)(`select`,{value:e,onChange:e=>d({agentPresetFilter:e.target.value}),className:`h-8 rounded-md border border-border bg-card text-sm px-2 text-foreground`,children:[(0,q.jsx)(`option`,{value:``,children:`All agents`}),(0,q.jsx)(`option`,{value:`active`,children:`Active`}),y().map(e=>(0,q.jsx)(`option`,{value:e,children:te(e)},e)),(0,q.jsx)(`option`,{value:`paired`,children:`Paired`}),(0,q.jsx)(`option`,{value:`unpaired`,children:`Unpaired`}),(0,q.jsx)(`option`,{value:`offline_stale`,children:`Offline / Stale`})]}),(0,q.jsxs)(`select`,{value:t,onChange:e=>d({agentStatusFilter:e.target.value}),className:`h-8 rounded-md border border-border bg-card text-sm px-2 text-foreground`,children:[(0,q.jsx)(`option`,{value:``,children:`Any status`}),(0,q.jsx)(`option`,{value:`online`,children:`Online`}),(0,q.jsx)(`option`,{value:`idle`,children:`Idle`}),(0,q.jsx)(`option`,{value:`busy`,children:`Busy`}),(0,q.jsx)(`option`,{value:`offline`,children:`Offline`}),(0,q.jsx)(`option`,{value:`starting`,children:`Starting`})]}),g.length>0&&(0,q.jsxs)(`select`,{value:i,onChange:e=>d({agentTagFilter:e.target.value}),className:`h-8 rounded-md border border-border bg-card text-sm px-2 text-foreground`,children:[(0,q.jsx)(`option`,{value:``,children:`Any tag`}),g.map(e=>(0,q.jsx)(`option`,{value:e,children:e},e))]}),_.length>1&&(0,q.jsxs)(`select`,{value:a,onChange:e=>d({agentHostFilter:e.target.value}),className:`h-8 rounded-md border border-border bg-card text-sm px-2 text-foreground`,children:[(0,q.jsx)(`option`,{value:``,children:`Any host`}),_.map(e=>(0,q.jsx)(`option`,{value:e,children:e},e))]}),(0,q.jsxs)(`select`,{value:s,onChange:e=>d({agentSort:e.target.value}),className:`h-8 rounded-md border border-border bg-card text-sm px-2 text-foreground`,children:[(0,q.jsx)(`option`,{value:`status`,children:`Sort: Status`}),(0,q.jsx)(`option`,{value:`name`,children:`Sort: Name`}),(0,q.jsx)(`option`,{value:`lastSeen`,children:`Sort: Last seen`}),(0,q.jsx)(`option`,{value:`created`,children:`Sort: Created`})]}),(0,q.jsx)(H,{size:`icon`,variant:`outline`,className:`h-8 w-8`,title:`Toggle sort direction`,onClick:w,children:c===`asc`?(0,q.jsx)(n,{className:`w-3.5 h-3.5`}):(0,q.jsx)(o,{className:`w-3.5 h-3.5`})}),(0,q.jsxs)(`label`,{className:`flex items-center gap-1.5 text-sm text-muted-foreground cursor-pointer select-none`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:u,onChange:e=>d({showOffline:e.target.checked}),className:`rounded`}),`Show offline`]}),S&&(0,q.jsxs)(H,{size:`sm`,variant:`ghost`,className:`h-8 text-muted-foreground hover:text-foreground gap-1`,onClick:C,children:[(0,q.jsx)(l,{className:`w-3 h-3`}),`Clear filters`]}),(0,q.jsx)(`div`,{className:`ml-auto`,children:(0,q.jsxs)(H,{size:`sm`,onClick:f,className:`gap-1`,children:[(0,q.jsx)(r,{className:`w-3.5 h-3.5`}),`Spawn`]})})]}),x.length===0?(0,q.jsx)(`div`,{className:`text-center py-16 text-muted-foreground text-sm`,children:`No agents match the current filters.`}):(0,q.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-3`,children:x.map(e=>(0,q.jsx)(nt,{agent:e,parentAgent:e.spawnedBy?p[e.spawnedBy]??null:null,childAgents:ue(b.get(e.id)??[])},e.id))})]})}export{rt as AgentsView};
|
|
2
|
-
//# sourceMappingURL=agents-Dt5TncjC.js.map
|