agent-relay-server 0.107.0 → 0.109.0
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 +589 -1
- package/package.json +4 -4
- package/public/assets/MessageBubble-XgN61quY.js +4 -0
- package/public/assets/{MessageBubble-PEdvVh_m.js.map → MessageBubble-XgN61quY.js.map} +1 -1
- package/public/assets/PlanGraphPanel-LY-msOsr.js +2 -0
- package/public/assets/PlanGraphPanel-LY-msOsr.js.map +1 -0
- package/public/assets/activity-D0EotVU9.js +2 -0
- package/public/assets/activity-D0EotVU9.js.map +1 -0
- package/public/assets/{agent-profiles-CuTQtmV6.js → agent-profiles-CAGvryb9.js} +2 -2
- package/public/assets/{agent-profiles-CuTQtmV6.js.map → agent-profiles-CAGvryb9.js.map} +1 -1
- package/public/assets/agents-CXXZ_sU9.js +2 -0
- package/public/assets/{agents-CgRFJyks.js.map → agents-CXXZ_sU9.js.map} +1 -1
- package/public/assets/{analytics-C3OTFIXo.js → analytics-Q6Dl_CE9.js} +3 -3
- package/public/assets/{analytics-C3OTFIXo.js.map → analytics-Q6Dl_CE9.js.map} +1 -1
- package/public/assets/{automation-CH9YGYoE.js → automation-zig0cp23.js} +2 -2
- package/public/assets/{automation-CH9YGYoE.js.map → automation-zig0cp23.js.map} +1 -1
- package/public/assets/{badge-D8fABzMs.js → badge-kdQDWO6e.js} +2 -2
- package/public/assets/{badge-D8fABzMs.js.map → badge-kdQDWO6e.js.map} +1 -1
- package/public/assets/{branch-state-badge-CcLZ_u86.js → branch-state-badge-BRjUWyMT.js} +2 -2
- package/public/assets/{branch-state-badge-CcLZ_u86.js.map → branch-state-badge-BRjUWyMT.js.map} +1 -1
- package/public/assets/{button-KASZcscA.js → button-BKFvNXa3.js} +2 -2
- package/public/assets/{button-KASZcscA.js.map → button-BKFvNXa3.js.map} +1 -1
- package/public/assets/card-B0y1i_2D.js +2 -0
- package/public/assets/{card-Cds0MWME.js.map → card-B0y1i_2D.js.map} +1 -1
- package/public/assets/{channels-CcSnLzCG.js → channels-DOYB1iiA.js} +2 -2
- package/public/assets/{channels-CcSnLzCG.js.map → channels-DOYB1iiA.js.map} +1 -1
- package/public/assets/chat-C3QlsFBd.js +2 -0
- package/public/assets/{chat-BLcm2Aht.js.map → chat-C3QlsFBd.js.map} +1 -1
- package/public/assets/{connectors-DbPOlQhL.js → connectors-C5CeK-2M.js} +2 -2
- package/public/assets/{connectors-DbPOlQhL.js.map → connectors-C5CeK-2M.js.map} +1 -1
- package/public/assets/{copy-button-d9DFNX9v.js → copy-button-aLaiAkv2.js} +2 -2
- package/public/assets/{copy-button-d9DFNX9v.js.map → copy-button-aLaiAkv2.js.map} +1 -1
- package/public/assets/display-_5kFrHJh.js +3 -0
- package/public/assets/display-_5kFrHJh.js.map +1 -0
- package/public/assets/{dist-DOAjFOS4.js → dist-BDYU37NZ.js} +2 -2
- package/public/assets/{dist-DOAjFOS4.js.map → dist-BDYU37NZ.js.map} +1 -1
- package/public/assets/dist-BnfqT2cl.js +2 -0
- package/public/assets/{dist-DC-TqTz2.js.map → dist-BnfqT2cl.js.map} +1 -1
- package/public/assets/dist-CF28Y5wI.js +2 -0
- package/public/assets/{dist-CBVZk9U8.js.map → dist-CF28Y5wI.js.map} +1 -1
- package/public/assets/{dist-DTXKbk2K.js → dist-DDh8a_SK.js} +2 -2
- package/public/assets/{dist-DTXKbk2K.js.map → dist-DDh8a_SK.js.map} +1 -1
- package/public/assets/{dist-BbUJ1Vht.js → dist-DKoRwEZq.js} +2 -2
- package/public/assets/{dist-BbUJ1Vht.js.map → dist-DKoRwEZq.js.map} +1 -1
- package/public/assets/{dist-UhEAFdvZ.js → dist-DQPz52Zx.js} +2 -2
- package/public/assets/{dist-UhEAFdvZ.js.map → dist-DQPz52Zx.js.map} +1 -1
- package/public/assets/{dist-CgqfdHSt.js → dist-D_qcpfbI.js} +2 -2
- package/public/assets/{dist-CgqfdHSt.js.map → dist-D_qcpfbI.js.map} +1 -1
- package/public/assets/{dist-DybScJmm.js → dist-DnyQI0qt.js} +2 -2
- package/public/assets/{dist-DybScJmm.js.map → dist-DnyQI0qt.js.map} +1 -1
- package/public/assets/{dist-BwwlmyBq.js → dist-EO8jbi2F.js} +2 -2
- package/public/assets/{dist-BwwlmyBq.js.map → dist-EO8jbi2F.js.map} +1 -1
- package/public/assets/{dist-BlZvUZZB.js → dist-avJPT3qF.js} +2 -2
- package/public/assets/{dist-BlZvUZZB.js.map → dist-avJPT3qF.js.map} +1 -1
- package/public/assets/dist-cyag2tir.js +2 -0
- package/public/assets/{dist-DreO5AcZ.js.map → dist-cyag2tir.js.map} +1 -1
- package/public/assets/{es2015-DUjFyjDp.js → es2015-C9FSEGd7.js} +2 -2
- package/public/assets/{es2015-DUjFyjDp.js.map → es2015-C9FSEGd7.js.map} +1 -1
- package/public/assets/{formatted-body-impl-BJTthVHg.js → formatted-body-impl-DCQSVyWB.js} +2 -2
- package/public/assets/{formatted-body-impl-BJTthVHg.js.map → formatted-body-impl-DCQSVyWB.js.map} +1 -1
- package/public/assets/index-D6hQkte1.css +2 -0
- package/public/assets/index-RCbIyk26.js +23 -0
- package/public/assets/index-RCbIyk26.js.map +1 -0
- package/public/assets/{input-CtHfLn1i.js → input-DfN6sUbX.js} +2 -2
- package/public/assets/{input-CtHfLn1i.js.map → input-DfN6sUbX.js.map} +1 -1
- package/public/assets/{insights-DklrIhb6.js → insights-CsLs6NbL.js} +2 -2
- package/public/assets/{insights-DklrIhb6.js.map → insights-CsLs6NbL.js.map} +1 -1
- package/public/assets/{integrations-hkSW8CzM.js → integrations-CztQfrI7.js} +2 -2
- package/public/assets/{integrations-hkSW8CzM.js.map → integrations-CztQfrI7.js.map} +1 -1
- package/public/assets/{lib-l-JkMVR9.js → lib-DRRHEqRZ.js} +2 -2
- package/public/assets/{lib-l-JkMVR9.js.map → lib-DRRHEqRZ.js.map} +1 -1
- package/public/assets/{lucide-react-C4eXYCwx.js → lucide-react-DmbfpRvJ.js} +2 -2
- package/public/assets/{lucide-react-C4eXYCwx.js.map → lucide-react-DmbfpRvJ.js.map} +1 -1
- package/public/assets/{maintenance-FAAMGpuZ.js → maintenance-BN5F0Lnc.js} +2 -2
- package/public/assets/{maintenance-FAAMGpuZ.js.map → maintenance-BN5F0Lnc.js.map} +1 -1
- package/public/assets/managed-agents-R_LI9qS5.js +4 -0
- package/public/assets/{managed-agents-CVca-s3t.js.map → managed-agents-R_LI9qS5.js.map} +1 -1
- package/public/assets/markdown-preview-impl-DQlmK_ev.js +2 -0
- package/public/assets/{markdown-preview-impl-BPW4OQo9.js.map → markdown-preview-impl-DQlmK_ev.js.map} +1 -1
- package/public/assets/memory-kn4bgMXC.js +2 -0
- package/public/assets/{memory-BzuDTHC5.js.map → memory-kn4bgMXC.js.map} +1 -1
- package/public/assets/{messages-_W24PNvT.js → messages-Dv3Tv7zC.js} +2 -2
- package/public/assets/{messages-_W24PNvT.js.map → messages-Dv3Tv7zC.js.map} +1 -1
- package/public/assets/{orchestrators-Du6I_n8i.js → orchestrators-DcNLRMzk.js} +2 -2
- package/public/assets/{orchestrators-Du6I_n8i.js.map → orchestrators-DcNLRMzk.js.map} +1 -1
- package/public/assets/overview-BOLzPSSC.js +2 -0
- package/public/assets/{overview-Dyvm1qpT.js.map → overview-BOLzPSSC.js.map} +1 -1
- package/public/assets/{pairs-B8x1RCNd.js → pairs-B4r0egpx.js} +2 -2
- package/public/assets/{pairs-B8x1RCNd.js.map → pairs-B4r0egpx.js.map} +1 -1
- package/public/assets/projects-cOeuiMjl.js +2 -0
- package/public/assets/{projects-vt63bwHN.js.map → projects-cOeuiMjl.js.map} +1 -1
- package/public/assets/prompt-settings-E7-6Osj4.js +2 -0
- package/public/assets/{prompt-settings-xVXmvxB5.js.map → prompt-settings-E7-6Osj4.js.map} +1 -1
- package/public/assets/{react-dom-BMF4hNzG.js → react-dom-jQ4Vs380.js} +2 -2
- package/public/assets/{react-dom-BMF4hNzG.js.map → react-dom-jQ4Vs380.js.map} +1 -1
- package/public/assets/registry-CTN3jOnb.js +2 -0
- package/public/assets/{registry-ypiICauZ.js.map → registry-CTN3jOnb.js.map} +1 -1
- package/public/assets/{security-BfOQ6T5r.js → security-BctIcBZb.js} +2 -2
- package/public/assets/{security-BfOQ6T5r.js.map → security-BctIcBZb.js.map} +1 -1
- package/public/assets/{select-Dx8Ro-A3.js → select-BndvVb0A.js} +2 -2
- package/public/assets/{select-Dx8Ro-A3.js.map → select-BndvVb0A.js.map} +1 -1
- package/public/assets/settings-B_tRq-P4.js +6 -0
- package/public/assets/{settings-87clTx4N.js.map → settings-B_tRq-P4.js.map} +1 -1
- package/public/assets/store-DDWg67Pg.js +9 -0
- package/public/assets/store-DDWg67Pg.js.map +1 -0
- package/public/assets/tasks-BgTTxVET.js +2 -0
- package/public/assets/tasks-BgTTxVET.js.map +1 -0
- package/public/assets/teams-DJiLBEgF.js +2 -0
- package/public/assets/{teams-DJWp4AKi.js.map → teams-DJiLBEgF.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-DgMuRAe_.js → terminal-viewer-impl-BLdiyCNR.js} +3 -3
- package/public/assets/{terminal-viewer-impl-DgMuRAe_.js.map → terminal-viewer-impl-BLdiyCNR.js.map} +1 -1
- package/public/assets/types-DSwhOFcJ.js +2 -0
- package/public/assets/types-DSwhOFcJ.js.map +1 -0
- package/public/assets/{use-keyboard-viewport-RYMALvu1.js → use-keyboard-viewport-Dw2CHZ50.js} +2 -2
- package/public/assets/{use-keyboard-viewport-RYMALvu1.js.map → use-keyboard-viewport-Dw2CHZ50.js.map} +1 -1
- package/public/assets/user-avatar-rt59cEsc.js +2 -0
- package/public/assets/{user-avatar-CfAUS3PZ.js.map → user-avatar-rt59cEsc.js.map} +1 -1
- package/public/assets/{work-queue-D-Otxd9u.js → work-queue-BYRdBuLR.js} +2 -2
- package/public/assets/{work-queue-D-Otxd9u.js.map → work-queue-BYRdBuLR.js.map} +1 -1
- package/public/assets/workspaces-DCRT3l9H.js +3 -0
- package/public/assets/workspaces-DCRT3l9H.js.map +1 -0
- package/public/index.html +23 -23
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +6 -0
- package/src/branch-landed.ts +17 -3
- package/src/config-store.ts +12 -1
- package/src/db/agents.ts +3 -2
- package/src/db/continuations.ts +13 -3
- package/src/db/index.ts +3 -0
- package/src/db/issue-lifecycle.ts +12 -0
- package/src/db/mappers.ts +17 -0
- package/src/db/messages.ts +9 -4
- package/src/db/migrations.ts +112 -2
- package/src/db/notification-subscriptions.ts +1 -1
- package/src/db/prompt-templates.ts +19 -0
- package/src/db/schema.ts +74 -2
- package/src/db/stats.ts +3 -2
- package/src/db/task-comment-through.ts +112 -0
- package/src/db/task-core.ts +14 -1
- package/src/db/task-entity.ts +629 -0
- package/src/db/task-maintenance.ts +4 -3
- package/src/db/task-memory.ts +180 -0
- package/src/db/tasks.ts +24 -10
- package/src/issue-tracker/adapter.ts +15 -0
- package/src/issue-tracker/github.ts +40 -2
- package/src/issue-tracker/index.ts +1 -0
- package/src/mcp/index.ts +12 -1
- package/src/mcp/tools-spawn.ts +4 -0
- package/src/mcp-dispatch-tools.ts +193 -0
- package/src/mcp-notification-subscription-tools.ts +62 -4
- package/src/mcp-plan-tools.ts +30 -3
- package/src/mcp-release-tools.ts +33 -0
- package/src/mcp-task-memory-tools.ts +115 -0
- package/src/mcp-task-tools.ts +232 -0
- package/src/mcp-task-weave-tools.ts +66 -0
- package/src/notification-router.ts +24 -2
- package/src/notification-rules.ts +4 -0
- package/src/notification-types.ts +23 -0
- package/src/prompt-resolver.ts +66 -3
- package/src/routes/agents-spawn.ts +10 -0
- package/src/routes/index.ts +17 -1
- package/src/routes/messages.ts +6 -6
- package/src/routes/plans.ts +10 -2
- package/src/routes/tasks.ts +335 -2
- package/src/routing-policy-store.ts +147 -2
- package/src/security.ts +4 -0
- package/src/self-resume.ts +13 -2
- package/src/services/issue-lifecycle.ts +9 -1
- package/src/services/plan-graph.ts +107 -9
- package/src/services/release-readiness.ts +142 -0
- package/src/services/send-message.ts +31 -0
- package/src/services/spawn-agent.ts +81 -4
- package/src/services/task-context-hydration.ts +361 -0
- package/src/services/task-entity.ts +149 -0
- package/src/services/task-issue-weave.ts +558 -0
- package/src/services/task-lifecycle.ts +465 -0
- package/src/services/task-plan-view.ts +178 -0
- package/src/services/task-semantic-events.ts +137 -0
- package/src/services/transient-agent-reaper.ts +55 -22
- package/src/spawn-targets.ts +27 -2
- package/src/task-authz.ts +52 -0
- package/src/task-dispatcher.ts +461 -0
- package/src/upgrade-install-verify.ts +20 -1
- package/public/assets/MessageBubble-PEdvVh_m.js +0 -4
- package/public/assets/PlanGraphPanel-DSts7Rtq.js +0 -2
- package/public/assets/PlanGraphPanel-DSts7Rtq.js.map +0 -1
- package/public/assets/activity-BcYf8YNO.js +0 -2
- package/public/assets/activity-BcYf8YNO.js.map +0 -1
- package/public/assets/agents-CgRFJyks.js +0 -2
- package/public/assets/card-Cds0MWME.js +0 -2
- package/public/assets/chat-BLcm2Aht.js +0 -2
- package/public/assets/display-BWi8DQCp.js +0 -3
- package/public/assets/display-BWi8DQCp.js.map +0 -1
- package/public/assets/dist-CBVZk9U8.js +0 -2
- package/public/assets/dist-DC-TqTz2.js +0 -2
- package/public/assets/dist-DreO5AcZ.js +0 -2
- package/public/assets/index-3ydeNO0c.js +0 -23
- package/public/assets/index-3ydeNO0c.js.map +0 -1
- package/public/assets/index-BjjzI2LT.css +0 -2
- package/public/assets/managed-agents-CVca-s3t.js +0 -4
- package/public/assets/markdown-preview-impl-BPW4OQo9.js +0 -2
- package/public/assets/memory-BzuDTHC5.js +0 -2
- package/public/assets/overview-Dyvm1qpT.js +0 -2
- package/public/assets/projects-vt63bwHN.js +0 -2
- package/public/assets/prompt-settings-xVXmvxB5.js +0 -2
- package/public/assets/registry-ypiICauZ.js +0 -2
- package/public/assets/settings-87clTx4N.js +0 -6
- package/public/assets/store-DUfrGvOE.js +0 -9
- package/public/assets/store-DUfrGvOE.js.map +0 -1
- package/public/assets/tasks-1Kvp53wh.js +0 -2
- package/public/assets/tasks-1Kvp53wh.js.map +0 -1
- package/public/assets/teams-DJWp4AKi.js +0 -2
- package/public/assets/types-DorDDvEb.js +0 -2
- package/public/assets/types-DorDDvEb.js.map +0 -1
- package/public/assets/user-avatar-CfAUS3PZ.js +0 -2
- package/public/assets/workspaces-CIsQqQby.js +0 -3
- package/public/assets/workspaces-CIsQqQby.js.map +0 -1
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
// #839 — the declarative task dispatcher.
|
|
2
|
+
//
|
|
3
|
+
// A pure function from (Task work-shape + live system state) → a concrete spawn
|
|
4
|
+
// (provider / model / effort) plus a human-readable rationale. The work-shape is the
|
|
5
|
+
// small, stable taxonomy a coordinator declares on the Task's `dispatch` field
|
|
6
|
+
// ({complexity, type, contextFootprint, criticality}); the routing heuristics that map
|
|
7
|
+
// it onto an agent live as INSPECTABLE, EDITABLE policy (RoutingPolicy.dispatch, with a
|
|
8
|
+
// built-in default) — never hardcoded here, never tribal coordinator knowledge.
|
|
9
|
+
//
|
|
10
|
+
// Guarantees this module is built to keep (the #839 GUARD):
|
|
11
|
+
// 1. Every decision reports WHY (rationale string + structured factors).
|
|
12
|
+
// 2. Every decision is overridable by an explicit model/provider pin.
|
|
13
|
+
// 3. The function is PURE — no DB writes, no spawning. The MCP entrypoint
|
|
14
|
+
// (mcp-dispatch-tools.ts) consumes the decision; #838 (spawn-with-task) will
|
|
15
|
+
// hydrate + actually spawn. Auto-review surfaces as a PLAN the caller may enact.
|
|
16
|
+
import type {
|
|
17
|
+
DispatchAutoReview,
|
|
18
|
+
DispatchMatch,
|
|
19
|
+
DispatchModelTarget,
|
|
20
|
+
DispatchPolicy,
|
|
21
|
+
DispatchRule,
|
|
22
|
+
SpawnProvider,
|
|
23
|
+
TaskDispatch,
|
|
24
|
+
} from "agent-relay-sdk";
|
|
25
|
+
import type { ProviderCatalogEntry, ProviderModelCatalogEntry } from "agent-relay-sdk/provider-catalog";
|
|
26
|
+
import { effectiveProviderCatalogList } from "./provider-catalog-store";
|
|
27
|
+
import { getDispatchPolicy } from "./routing-policy-store";
|
|
28
|
+
import { providerQuotaBands, type ProviderQuotaBand, type QuotaBand } from "./spawn-targets";
|
|
29
|
+
|
|
30
|
+
/** An explicit per-case override. Any field set wins over the policy-derived target. */
|
|
31
|
+
export interface DispatchPin {
|
|
32
|
+
provider?: SpawnProvider;
|
|
33
|
+
model?: string;
|
|
34
|
+
effort?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Live-state inputs. All optional + injectable so the dispatcher is unit-testable without a
|
|
39
|
+
* running fleet; each defaults to the real source (policy store / quota bands / catalog).
|
|
40
|
+
*/
|
|
41
|
+
export interface DispatchContext {
|
|
42
|
+
policy?: DispatchPolicy;
|
|
43
|
+
bands?: ProviderQuotaBand[];
|
|
44
|
+
catalog?: ProviderCatalogEntry[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface DispatchTarget {
|
|
48
|
+
provider: SpawnProvider;
|
|
49
|
+
model?: string;
|
|
50
|
+
effort?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Structured trace of the inputs that produced the decision (the machine-readable rationale). */
|
|
54
|
+
export interface DispatchFactors {
|
|
55
|
+
complexity?: string;
|
|
56
|
+
type?: string;
|
|
57
|
+
contextFootprint?: string;
|
|
58
|
+
criticality?: string;
|
|
59
|
+
/** Label of the matched rule, or a "fallback"/"pin" marker. */
|
|
60
|
+
matchedRule: string;
|
|
61
|
+
/** The final provider's live quota band. */
|
|
62
|
+
band: QuotaBand;
|
|
63
|
+
/** Context window of the chosen model, when known. */
|
|
64
|
+
contextWindowTokens?: number;
|
|
65
|
+
/** Model was escalated to a bigger-window family member for a large footprint. */
|
|
66
|
+
escalatedForFootprint?: boolean;
|
|
67
|
+
/** Provider was rerouted away from a scarce/blocked pool; original provider recorded here. */
|
|
68
|
+
reroutedFromProvider?: SpawnProvider;
|
|
69
|
+
/** Which target fields were set by an explicit pin. */
|
|
70
|
+
pinnedFields?: string[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** A dependent review Task the caller may create (high criticality / complex work). */
|
|
74
|
+
export interface ReviewPlan {
|
|
75
|
+
/** Work-shape for the review Task. */
|
|
76
|
+
dispatch: TaskDispatch;
|
|
77
|
+
target: DispatchTarget;
|
|
78
|
+
rationale: string;
|
|
79
|
+
/** Why the review was triggered (e.g. "criticality=high"). */
|
|
80
|
+
reason: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface DispatchDecision {
|
|
84
|
+
target: DispatchTarget;
|
|
85
|
+
/** True when any target field came from an explicit pin. */
|
|
86
|
+
pinned: boolean;
|
|
87
|
+
/** Human-readable explanation, e.g. `opus-4.8 high: type=build, complexity=complex; claude band=normal`. */
|
|
88
|
+
rationale: string;
|
|
89
|
+
factors: DispatchFactors;
|
|
90
|
+
/** Non-fatal advisories (e.g. scarce pool, no model meets the footprint). */
|
|
91
|
+
warnings: string[];
|
|
92
|
+
/** Present when the policy's auto-review threshold is met. */
|
|
93
|
+
review?: ReviewPlan;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Public entrypoint
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Map a work-shape + live state onto a concrete spawn. `pin` overrides any field per-case;
|
|
102
|
+
* the rationale always explains the choice (including why a pin or reroute happened).
|
|
103
|
+
*/
|
|
104
|
+
export function dispatchTask(shape: TaskDispatch | undefined, pin: DispatchPin = {}, ctx: DispatchContext = {}): DispatchDecision {
|
|
105
|
+
const policy = ctx.policy ?? getDispatchPolicy();
|
|
106
|
+
const catalog = ctx.catalog ?? effectiveProviderCatalogList();
|
|
107
|
+
const bands = ctx.bands ?? providerQuotaBands();
|
|
108
|
+
const work: TaskDispatch = shape ?? {};
|
|
109
|
+
const warnings: string[] = [];
|
|
110
|
+
|
|
111
|
+
const matched = resolvePolicyTarget(work, policy);
|
|
112
|
+
let target: DispatchTarget = { ...matched.target };
|
|
113
|
+
const factors: DispatchFactors = {
|
|
114
|
+
...(work.complexity ? { complexity: work.complexity } : {}),
|
|
115
|
+
...(work.type ? { type: work.type } : {}),
|
|
116
|
+
...(work.contextFootprint ? { contextFootprint: work.contextFootprint } : {}),
|
|
117
|
+
...(work.criticality ? { criticality: work.criticality } : {}),
|
|
118
|
+
matchedRule: matched.label,
|
|
119
|
+
band: "normal",
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const pinnedFields = applyPin(target, pin);
|
|
123
|
+
const providerPinned = pinnedFields.includes("provider");
|
|
124
|
+
const modelPinned = pinnedFields.includes("model");
|
|
125
|
+
const effortPinned = pinnedFields.includes("effort");
|
|
126
|
+
if (pinnedFields.length) factors.pinnedFields = pinnedFields;
|
|
127
|
+
|
|
128
|
+
// Footprint escalation (skip when the model is explicitly pinned — respect the human choice).
|
|
129
|
+
if (!modelPinned) escalateForFootprint(target, work, policy, catalog, factors, warnings);
|
|
130
|
+
|
|
131
|
+
// Band-aware rerouting (skip when the provider is explicitly pinned). Protects scarce pools
|
|
132
|
+
// and load-shifts large/blocked work onto an abundant one. Re-validates footprint + a pinned
|
|
133
|
+
// effort on the rerouted provider so neither is silently dropped.
|
|
134
|
+
if (!providerPinned) rerouteForBand(target, work, policy, bands, catalog, factors, warnings, { effortPinned });
|
|
135
|
+
|
|
136
|
+
// Record the FINAL provider's band + the chosen model's window for transparency.
|
|
137
|
+
factors.band = bandFor(target.provider, bands);
|
|
138
|
+
const finalWindow = contextWindowOf(catalog, target.provider, target.model);
|
|
139
|
+
if (finalWindow !== undefined) factors.contextWindowTokens = finalWindow;
|
|
140
|
+
collectBandWarnings(target.provider, work, bands, providerPinned, warnings);
|
|
141
|
+
|
|
142
|
+
const review = planAutoReview(work, policy, bands, catalog);
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
target,
|
|
146
|
+
pinned: pinnedFields.length > 0,
|
|
147
|
+
rationale: buildRationale(target, factors, warnings),
|
|
148
|
+
factors,
|
|
149
|
+
warnings,
|
|
150
|
+
...(review ? { review } : {}),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Policy rule matching
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
function resolvePolicyTarget(work: TaskDispatch, policy: DispatchPolicy): { target: DispatchModelTarget; label: string } {
|
|
159
|
+
for (const rule of policy.rules) {
|
|
160
|
+
if (rule.enabled === false) continue;
|
|
161
|
+
if (matchesShape(rule.match, work)) {
|
|
162
|
+
return { target: rule.target, label: rule.label ?? "rule" };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { target: policy.fallback, label: "fallback (no rule matched)" };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function matchesShape(match: DispatchMatch, work: TaskDispatch): boolean {
|
|
169
|
+
return (
|
|
170
|
+
dimensionMatches(match.complexity, work.complexity) &&
|
|
171
|
+
dimensionMatches(match.type, work.type) &&
|
|
172
|
+
dimensionMatches(match.contextFootprint, work.contextFootprint) &&
|
|
173
|
+
dimensionMatches(match.criticality, work.criticality)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// An unset criterion is a wildcard. A set criterion needs a present work value that is one of
|
|
178
|
+
// the (possibly array) allowed values.
|
|
179
|
+
function dimensionMatches(criterion: string | string[] | undefined, value: string | undefined): boolean {
|
|
180
|
+
if (criterion === undefined) return true;
|
|
181
|
+
if (value === undefined) return false;
|
|
182
|
+
const allowed = Array.isArray(criterion) ? criterion : [criterion];
|
|
183
|
+
return allowed.includes(value);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Pin application
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
function applyPin(target: DispatchTarget, pin: DispatchPin): string[] {
|
|
191
|
+
const fields: string[] = [];
|
|
192
|
+
if (pin.provider) {
|
|
193
|
+
// A provider change invalidates a provider-specific policy model/effort unless the pin
|
|
194
|
+
// also restates them; clear them so we fall back to that provider's defaults.
|
|
195
|
+
if (pin.provider !== target.provider) {
|
|
196
|
+
if (!pin.model) target.model = undefined;
|
|
197
|
+
if (!pin.effort) target.effort = undefined;
|
|
198
|
+
}
|
|
199
|
+
target.provider = pin.provider;
|
|
200
|
+
fields.push("provider");
|
|
201
|
+
}
|
|
202
|
+
if (pin.model) {
|
|
203
|
+
target.model = pin.model;
|
|
204
|
+
fields.push("model");
|
|
205
|
+
}
|
|
206
|
+
if (pin.effort) {
|
|
207
|
+
target.effort = pin.effort;
|
|
208
|
+
fields.push("effort");
|
|
209
|
+
}
|
|
210
|
+
return fields;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Footprint → context-window escalation
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
|
|
217
|
+
function escalateForFootprint(
|
|
218
|
+
target: DispatchTarget,
|
|
219
|
+
work: TaskDispatch,
|
|
220
|
+
policy: DispatchPolicy,
|
|
221
|
+
catalog: ProviderCatalogEntry[],
|
|
222
|
+
factors: DispatchFactors,
|
|
223
|
+
warnings: string[],
|
|
224
|
+
): void {
|
|
225
|
+
const footprint = work.contextFootprint;
|
|
226
|
+
if (!footprint) return;
|
|
227
|
+
const minTokens = policy.footprintMinContextTokens?.[footprint];
|
|
228
|
+
if (!minTokens) return;
|
|
229
|
+
const entry = catalogEntry(catalog, target.provider);
|
|
230
|
+
if (!entry) return;
|
|
231
|
+
const alias = target.model ?? entry.defaultModel;
|
|
232
|
+
const current = alias ? contextWindowFromEntry(entry, alias) : undefined;
|
|
233
|
+
if (current !== undefined && current >= minTokens) return; // already big enough
|
|
234
|
+
|
|
235
|
+
// Prefer widening the SAME model family (opus-4.8 → opus-4.8[1m]); fall back to any other
|
|
236
|
+
// sufficient model on this provider before giving up (e.g. after a reroute reset us to a small
|
|
237
|
+
// default). Smallest sufficient window wins so we don't over-allocate.
|
|
238
|
+
const pick = biggestSufficient(entry, minTokens, alias);
|
|
239
|
+
if (pick && pick.alias !== alias) {
|
|
240
|
+
target.model = pick.alias;
|
|
241
|
+
factors.escalatedForFootprint = true;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (!pick && current === undefined) return; // unknown window AND no sufficient alternative — can't assert a gap
|
|
245
|
+
// Nothing on this provider satisfies the footprint — surface it rather than silently downgrade.
|
|
246
|
+
warnings.push(
|
|
247
|
+
`contextFootprint=${footprint} wants ≥${minTokens} tokens but ${target.provider}/${alias ?? "default"} offers ${current ?? "unknown"}; no model on ${target.provider} meets it — review the pick.`,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// The smallest-window model on this provider whose window meets the requirement. Prefers the
|
|
252
|
+
// same model family as `alias` (e.g. opus-4.8 → opus-4.8[1m]) when one qualifies, else any family.
|
|
253
|
+
function biggestSufficient(
|
|
254
|
+
entry: ProviderCatalogEntry,
|
|
255
|
+
minTokens: number,
|
|
256
|
+
alias: string | undefined,
|
|
257
|
+
): ProviderModelCatalogEntry | undefined {
|
|
258
|
+
const sufficient = entry.models
|
|
259
|
+
.filter((m) => !m.disabled && !m.unavailable)
|
|
260
|
+
.map((m) => ({ model: m, window: m.limits?.contextWindowTokens?.value }))
|
|
261
|
+
.filter((c): c is { model: ProviderModelCatalogEntry; window: number } => typeof c.window === "number" && c.window >= minTokens)
|
|
262
|
+
.sort((a, b) => a.window - b.window);
|
|
263
|
+
const base = alias ? familyBase(alias) : undefined;
|
|
264
|
+
const sameFamily = base ? sufficient.find((c) => familyBase(c.model.alias) === base) : undefined;
|
|
265
|
+
return (sameFamily ?? sufficient[0])?.model;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function familyBase(alias: string): string {
|
|
269
|
+
return alias.trim().toLowerCase().replace(/\[[^\]]+\]$/, "");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
// Quota-band aware rerouting
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
|
|
276
|
+
function rerouteForBand(
|
|
277
|
+
target: DispatchTarget,
|
|
278
|
+
work: TaskDispatch,
|
|
279
|
+
policy: DispatchPolicy,
|
|
280
|
+
bands: ProviderQuotaBand[],
|
|
281
|
+
catalog: ProviderCatalogEntry[],
|
|
282
|
+
factors: DispatchFactors,
|
|
283
|
+
warnings: string[],
|
|
284
|
+
opts: { effortPinned: boolean },
|
|
285
|
+
): void {
|
|
286
|
+
const band = bandFor(target.provider, bands);
|
|
287
|
+
const blocked = isBlocked(target.provider, bands);
|
|
288
|
+
const isLarge = work.contextFootprint === "large";
|
|
289
|
+
// Reroute when the pool is at capacity / hard-avoid, or a large job lands on an avoid-large pool.
|
|
290
|
+
const mustMove = blocked || band === "hard-avoid" || (isLarge && band === "avoid-large");
|
|
291
|
+
if (!mustMove) return;
|
|
292
|
+
|
|
293
|
+
const alt = healthiestAlternative(target.provider, bands, catalog);
|
|
294
|
+
if (!alt) {
|
|
295
|
+
warnings.push(`${target.provider} band=${band}${blocked ? " (at capacity)" : ""} and no healthier provider is available — keeping it; expect contention.`);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const altEntry = catalogEntry(catalog, alt.provider)!;
|
|
299
|
+
factors.reroutedFromProvider = target.provider;
|
|
300
|
+
warnings.push(`Rerouted ${target.provider} (band=${band}${blocked ? ", at capacity" : ""}) → ${alt.provider} (band=${alt.band}) to ${alt.band === "prefer" ? "use abundant quota" : "avoid the scarce pool"}.`);
|
|
301
|
+
const prevEffort = target.effort;
|
|
302
|
+
target.provider = alt.provider;
|
|
303
|
+
// Provider changed → model is provider-specific; reset to the new provider's default, then
|
|
304
|
+
// RE-VALIDATE the footprint on the new provider (it may widen to a 1M model, or warn if it
|
|
305
|
+
// cannot meet the footprint) so a large job is never silently downgraded onto a small window.
|
|
306
|
+
target.model = altEntry.defaultModel;
|
|
307
|
+
// Re-derive escalation against the NEW provider — the prior provider's escalation flag is stale.
|
|
308
|
+
delete factors.escalatedForFootprint;
|
|
309
|
+
escalateForFootprint(target, work, policy, catalog, factors, warnings);
|
|
310
|
+
// Effort: a pinned effort is authoritative and survives the reroute (warn if the rerouted model
|
|
311
|
+
// doesn't list it, rather than silently dropping it). An unpinned effort is kept only if supported.
|
|
312
|
+
if (opts.effortPinned) {
|
|
313
|
+
target.effort = prevEffort;
|
|
314
|
+
if (prevEffort && effortIfSupported(altEntry, target.model, prevEffort) === undefined) {
|
|
315
|
+
warnings.push(`Pinned effort '${prevEffort}' isn't listed for ${alt.provider}/${target.model ?? "default"}; honoring the pin anyway.`);
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
target.effort = effortIfSupported(altEntry, target.model, prevEffort);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Best healthy provider other than `avoid`, considering EVERY spawnable provider in the live
|
|
323
|
+
// catalog — not only those with a quota advisory. A provider with no quota record defaults to the
|
|
324
|
+
// "normal" band (via bandFor), so a healthy catalog provider is never skipped just because it has
|
|
325
|
+
// no burn data yet. Prefer "prefer" band, then "normal"; never a blocked one.
|
|
326
|
+
function healthiestAlternative(
|
|
327
|
+
avoid: SpawnProvider,
|
|
328
|
+
bands: ProviderQuotaBand[],
|
|
329
|
+
catalog: ProviderCatalogEntry[],
|
|
330
|
+
): { provider: SpawnProvider; band: QuotaBand } | undefined {
|
|
331
|
+
const ranked = catalog
|
|
332
|
+
.map((c) => c.provider)
|
|
333
|
+
.filter((provider) => provider !== avoid)
|
|
334
|
+
.map((provider) => ({ provider, band: bandFor(provider, bands), blockedNow: isBlocked(provider, bands) }))
|
|
335
|
+
.filter((c) => !c.blockedNow && (c.band === "prefer" || c.band === "normal"))
|
|
336
|
+
.sort((a, b) => bandRank(a.band) - bandRank(b.band));
|
|
337
|
+
return ranked[0];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function collectBandWarnings(provider: SpawnProvider, work: TaskDispatch, bands: ProviderQuotaBand[], providerPinned: boolean, warnings: string[]): void {
|
|
341
|
+
if (!providerPinned) return; // non-pinned scarce pools were already handled by reroute
|
|
342
|
+
const band = bandFor(provider, bands);
|
|
343
|
+
if (band === "hard-avoid" || isBlocked(provider, bands)) {
|
|
344
|
+
warnings.push(`Pinned provider ${provider} is band=${band}${isBlocked(provider, bands) ? " (at capacity)" : ""}; honoring the pin but it may be slow or blocked.`);
|
|
345
|
+
} else if (band === "avoid-large" && work.contextFootprint === "large") {
|
|
346
|
+
warnings.push(`Pinned provider ${provider} is band=avoid-large for a large job; honoring the pin.`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ---------------------------------------------------------------------------
|
|
351
|
+
// Auto-review planning
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
function planAutoReview(
|
|
355
|
+
work: TaskDispatch,
|
|
356
|
+
policy: DispatchPolicy,
|
|
357
|
+
bands: ProviderQuotaBand[],
|
|
358
|
+
catalog: ProviderCatalogEntry[],
|
|
359
|
+
): ReviewPlan | undefined {
|
|
360
|
+
const cfg = policy.autoReview;
|
|
361
|
+
if (!cfg) return undefined;
|
|
362
|
+
const reason = autoReviewReason(work, cfg);
|
|
363
|
+
if (!reason) return undefined;
|
|
364
|
+
// The review Task's own work-shape: a review, inheriting the parent's criticality. Its target
|
|
365
|
+
// is resolved through the SAME policy (so review routing stays single-source) — either the
|
|
366
|
+
// explicit autoReview.target or whatever the review-type rules pick. No pin, no recursion into
|
|
367
|
+
// auto-review (a review of a review isn't wanted).
|
|
368
|
+
const reviewShape: TaskDispatch = {
|
|
369
|
+
type: "review",
|
|
370
|
+
...(work.criticality ? { criticality: work.criticality } : {}),
|
|
371
|
+
...(work.complexity ? { complexity: work.complexity } : {}),
|
|
372
|
+
};
|
|
373
|
+
const reviewPolicy: DispatchPolicy = cfg.target
|
|
374
|
+
? { ...policy, rules: [{ label: "auto-review target", match: { type: "review" }, target: cfg.target }, ...policy.rules], autoReview: undefined }
|
|
375
|
+
: { ...policy, autoReview: undefined };
|
|
376
|
+
const decision = dispatchTask(reviewShape, {}, { policy: reviewPolicy, bands, catalog });
|
|
377
|
+
return {
|
|
378
|
+
dispatch: reviewShape,
|
|
379
|
+
target: decision.target,
|
|
380
|
+
rationale: decision.rationale,
|
|
381
|
+
reason,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function autoReviewReason(work: TaskDispatch, cfg: DispatchAutoReview): string | undefined {
|
|
386
|
+
if (work.criticality && cfg.whenCriticality?.includes(work.criticality)) return `criticality=${work.criticality}`;
|
|
387
|
+
if (work.complexity && cfg.whenComplexity?.includes(work.complexity)) return `complexity=${work.complexity}`;
|
|
388
|
+
return undefined;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ---------------------------------------------------------------------------
|
|
392
|
+
// Rationale rendering
|
|
393
|
+
// ---------------------------------------------------------------------------
|
|
394
|
+
|
|
395
|
+
function buildRationale(target: DispatchTarget, factors: DispatchFactors, warnings: string[]): string {
|
|
396
|
+
const head = `${target.model ?? `${target.provider} default`}${target.effort ? ` ${target.effort}` : ""}`;
|
|
397
|
+
const shape = [
|
|
398
|
+
factors.type ? `type=${factors.type}` : undefined,
|
|
399
|
+
factors.complexity ? `complexity=${factors.complexity}` : undefined,
|
|
400
|
+
factors.contextFootprint ? `contextFootprint=${factors.contextFootprint}` : undefined,
|
|
401
|
+
factors.criticality ? `criticality=${factors.criticality}` : undefined,
|
|
402
|
+
].filter(Boolean).join(", ");
|
|
403
|
+
const parts = [`${head}:`];
|
|
404
|
+
if (shape) parts.push(shape + ";");
|
|
405
|
+
parts.push(`matched ${factors.matchedRule};`);
|
|
406
|
+
parts.push(`${capitalize(target.provider)} band=${factors.band}`);
|
|
407
|
+
if (factors.escalatedForFootprint) parts.push(`(escalated to ${target.model} for footprint)`);
|
|
408
|
+
if (factors.reroutedFromProvider) parts.push(`(rerouted from ${factors.reroutedFromProvider})`);
|
|
409
|
+
if (factors.pinnedFields?.length) parts.push(`(pinned: ${factors.pinnedFields.join(", ")})`);
|
|
410
|
+
return parts.join(" ");
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function capitalize(value: string): string {
|
|
414
|
+
return value ? value[0]!.toUpperCase() + value.slice(1) : value;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// ---------------------------------------------------------------------------
|
|
418
|
+
// Catalog / band helpers
|
|
419
|
+
// ---------------------------------------------------------------------------
|
|
420
|
+
|
|
421
|
+
function catalogEntry(catalog: ProviderCatalogEntry[], provider: SpawnProvider): ProviderCatalogEntry | undefined {
|
|
422
|
+
return catalog.find((c) => c.provider === provider);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function contextWindowOf(catalog: ProviderCatalogEntry[], provider: SpawnProvider, model: string | undefined): number | undefined {
|
|
426
|
+
const entry = catalogEntry(catalog, provider);
|
|
427
|
+
if (!entry) return undefined;
|
|
428
|
+
const alias = model ?? entry.defaultModel;
|
|
429
|
+
return alias ? contextWindowFromEntry(entry, alias) : undefined;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function contextWindowFromEntry(entry: ProviderCatalogEntry, alias: string): number | undefined {
|
|
433
|
+
const model = entry.models.find((m) => m.alias === alias) ?? entry.models.find((m) => m.providerModel === alias);
|
|
434
|
+
return model?.limits?.contextWindowTokens?.value;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function effortIfSupported(entry: ProviderCatalogEntry, alias: string | undefined, effort: string | undefined): string | undefined {
|
|
438
|
+
if (!effort || !alias) return undefined;
|
|
439
|
+
const model = entry.models.find((m) => m.alias === alias);
|
|
440
|
+
return model && model.efforts.includes(effort) ? effort : undefined;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function bandFor(provider: SpawnProvider, bands: ProviderQuotaBand[]): QuotaBand {
|
|
444
|
+
return bands.find((b) => b.provider === provider)?.band ?? "normal";
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function isBlocked(provider: SpawnProvider, bands: ProviderQuotaBand[]): boolean {
|
|
448
|
+
return bands.find((b) => b.provider === provider)?.blockedNow ?? false;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Lower = healthier. Mirrors the bandRank ordering used elsewhere (prefer is the best state).
|
|
452
|
+
function bandRank(band: QuotaBand): number {
|
|
453
|
+
switch (band) {
|
|
454
|
+
case "prefer": return 0;
|
|
455
|
+
case "normal": return 1;
|
|
456
|
+
case "caution": return 2;
|
|
457
|
+
case "avoid-large": return 3;
|
|
458
|
+
case "hard-avoid": return 4;
|
|
459
|
+
default: return 1;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { chmodSync, existsSync, readFileSync, rmSync } from "node:fs";
|
|
1
|
+
import { chmodSync, existsSync, readFileSync, realpathSync, rmSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -143,10 +143,29 @@ export const defaultInstallIo: InstallIo = {
|
|
|
143
143
|
: bin && typeof bin === "object"
|
|
144
144
|
? Object.values(bin as Record<string, unknown>).filter((v): v is string => typeof v === "string")
|
|
145
145
|
: [];
|
|
146
|
+
// Resolve the real node_modules path once so we can guard against workspace
|
|
147
|
+
// symlinks that point back into the repo working tree (#825).
|
|
148
|
+
let realNodeModules: string;
|
|
149
|
+
try {
|
|
150
|
+
realNodeModules = realpathSync(join(prefix, "node_modules"));
|
|
151
|
+
} catch {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
146
154
|
const restored: string[] = [];
|
|
147
155
|
for (const rel of targets) {
|
|
148
156
|
const file = join(pkgDir, rel);
|
|
149
157
|
if (!existsSync(file)) continue;
|
|
158
|
+
// Skip if the realpath resolves outside node_modules (e.g. a workspace symlink
|
|
159
|
+
// node_modules/pkg → ../pkg points into the tracked source tree). Chmodding
|
|
160
|
+
// through such a symlink flips the source file's mode and makes the working
|
|
161
|
+
// tree appear dirty, mis-routing the landed path into the WIP-preserve path.
|
|
162
|
+
let realFile: string;
|
|
163
|
+
try {
|
|
164
|
+
realFile = realpathSync(file);
|
|
165
|
+
} catch {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (!realFile.startsWith(realNodeModules + "/")) continue;
|
|
150
169
|
try {
|
|
151
170
|
chmodSync(file, 0o755);
|
|
152
171
|
restored.push(file);
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,$t as n,An as r,B as i,Cn as a,Dt as o,Fn as s,Hn as c,L as l,Ot as u,Qt as d,Sn as f,Un as p,V as m,Vt as h,Yn as g,Zn as _,_n as v,a as y,b,c as ee,ft as x,g as S,hn as C,i as te,ln as ne,lt as w,m as T,on as E,r as D,un as re,ur as O,vn as k,x as A,xn as ie,yn as j}from"./lucide-react-C4eXYCwx.js";import{r as M,t as N,y as P}from"./store-DUfrGvOE.js";import{t as F}from"./types-DorDDvEb.js";import{E as I,H as ae,N as L,P as R,R as oe,S as se,V as ce,_ as le,d as ue,f as de,k as z,q as B,rt as V,v as fe}from"./display-BWi8DQCp.js";import{D as H,a as pe,i as me,l as he,t as U}from"./index-3ydeNO0c.js";import{t as ge}from"./user-avatar-CfAUS3PZ.js";var W=e(O(),1),_e={online:`came online`,offline:`went offline`,shutdown:`shut down`,restarted:`restarted`,"compaction-requested":`compaction requested`,compacting:`compaction started`,compacted:`context compacted`,"compaction-stalled":`compaction stalled — may need manual intervention`,"clear-requested":`clear requested`,"clearing-context":`clear started`,"context-cleared":`context cleared`,"clear-stalled":`context clear stalled — may need manual intervention`,"shutting-down":`shutting down`},ve=new Set(Object.keys(_e)),ye=3e3;function G(e){return new Date(e.occurredAt??e.createdAt).getTime()}function be(e){if(e.kind!==`session`)return null;let t=e.payload?.session;return!t||t.type!==`narration`&&t.type!==`reasoning`&&t.type!==`tool`?null:{id:e.id,kind:t.type,label:typeof t.label==`string`?t.label:void 0,text:e.body,ts:G(e),turnId:typeof t.turnId==`string`?t.turnId:void 0}}function xe(e){if(e.kind!==`session`)return null;let t=e.payload?.session;if(t?.type!==`notice`)return null;let n=typeof t.label==`string`&&t.label?t.label:`compacted`;return{id:`notice-${e.id}`,status:n,timestamp:G(e)}}function Se(e){if(e.kind!==`session`)return null;let t=e.payload?.session;if(t?.type!==`relay-injection`)return null;let n=t.relayInjection&&typeof t.relayInjection==`object`&&!Array.isArray(t.relayInjection)?t.relayInjection:{},r=typeof n.category==`string`&&[`memory`,`instructions`,`tools`,`comms`,`knowledge`,`context`].includes(n.category)?n.category:`context`,i=typeof n.timestamp==`number`&&Number.isFinite(n.timestamp)?n.timestamp:G(e),a=n.detail&&typeof n.detail==`object`&&!Array.isArray(n.detail)?n.detail:{};return{id:e.id,category:r,summary:typeof n.summary==`string`&&n.summary.trim()?n.summary:e.body,detail:a,agentId:typeof n.agentId==`string`&&n.agentId?n.agentId:e.from,timestamp:i}}function Ce(e){if(e.kind!==`session`)return null;let t=e.payload?.session;if(t?.type!==`prompt-resolution`)return null;let n=t.promptResolution&&typeof t.promptResolution==`object`&&!Array.isArray(t.promptResolution)?t.promptResolution:{},r=n.kind===`questions`||n.kind===`plan`||n.kind===`command`||n.kind===`tool`?n.kind:`tool`,i=typeof n.title==`string`&&n.title.trim()?n.title:`Prompt resolved`,a=typeof n.decisionLabel==`string`&&n.decisionLabel.trim()?n.decisionLabel:typeof t.label==`string`&&t.label.trim()?t.label:`Resolved`,o=n.answers&&typeof n.answers==`object`&&!Array.isArray(n.answers)?n.answers:{};return{id:e.id,title:i,kind:r,body:typeof n.promptBody==`string`?n.promptBody:typeof n.body==`string`?n.body:e.body,toolName:typeof n.toolName==`string`&&n.toolName.trim()?n.toolName:i,decisionLabel:a,questions:we(n.questions,o,a),timestamp:G(e)}}function we(e,t,n){let r=(Array.isArray(e)?e:[]).map((e,r)=>{let i=e&&typeof e==`object`&&!Array.isArray(e)?e:{},a=typeof i.question==`string`&&i.question.trim()?i.question.trim():typeof i.header==`string`&&i.header.trim()?i.header.trim():`Question ${r+1}`,o=t[a]??t[String(i.question??``)]??t[String(i.header??``)];return{question:a,answer:typeof o==`string`&&o.trim()?o.trim():n}});return r.length?r:Object.entries(t).map(([e,t])=>({question:e,answer:t}))}function Te(e,t){let n=e.trim();for(let e of t){let t=e.trim();if(t){if(n===t)break;n.startsWith(`${t}\n\n`)&&(n=n.slice(t.length+2).trimStart())}}return n.trim()||e.trim()}function Ee(e){return e.kind===`system`&&e.from===`system`}var De=new Set([`agent.ready`,`agent.exited`,`agent.spawn_failed`]);function K(e){let t=new Date(e);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,`0`)}-${String(t.getDate()).padStart(2,`0`)}`}function Oe(e){let t=e.filter(e=>ve.has(e.status)).slice().sort((e,t)=>e.timestamp-t.timestamp),n=[];for(let e of t)n.some(t=>t.id===e.id)||n.some(t=>t.status===e.status&&Math.abs(t.timestamp-e.timestamp)<=ye)||n.push(e);return n}function ke(e,t,n,r=[],i){let a=[];for(let e of r){let t=e.entries.reduce((e,t)=>Math.min(e,B(t.originalCreatedAt)),1/0),n=Number.isFinite(t)?t-1:e.importedAt;a.push({ts:n,entry:{type:`import-boundary`,history:e,timestamp:n}});for(let t of e.entries)a.push({ts:B(t.originalCreatedAt),entry:{type:`imported-message`,history:e,entry:t}})}if(n){let e=new Date(n).getTime();Number.isFinite(e)&&a.push({ts:e,entry:{type:`created`,timestamp:e}})}if(i?.spawnedBy){let e=n?new Date(n).getTime():0,t=Number.isFinite(e)?e:0;a.push({ts:t,entry:{type:`agent-action`,direction:`spawned-by`,agentId:i.spawnedBy.agentId,provider:i.spawnedBy.provider,status:`ready`,timestamp:t}})}let o=i?.spawnedBy?.agentId,s=null,c=1/0;for(let t of e){if(t.kind===`session`||Ee(t)||I(t)||!(t.from===`user`||o!==void 0&&t.from===o)||!z(t).trim())continue;let e=G(t);e<c&&(c=e,s=t.id)}let l=new Map,u=new Map,d=new Map;for(let t of e){if(t.kind!==`session`)continue;let e=t.payload?.session;if(e?.type===`narration`&&typeof e.turnId==`string`){let n=u.get(e.turnId)??[];n.push({id:t.id,body:t.body.trim()}),u.set(e.turnId,n)}else if(e?.type===`response`&&typeof e.turnId==`string`){let n=l.get(e.turnId)??[];n.push(t.body.trim()),l.set(e.turnId,n)}}let f=new Map;for(let[e,t]of l){let n=(u.get(e)??[]).map(e=>e.body);f.set(e,t.map(e=>Te(e,n)))}for(let t of e){if(t.kind!==`session`)continue;let e=t.payload?.session;if(e?.type!==`response`||typeof e.turnId!=`string`)continue;let n=Te(t.body,(u.get(e.turnId)??[]).map(e=>e.body));n&&n!==t.body&&d.set(t.id,n)}let p=new Set;for(let[e,t]of f){let n=u.get(e)??[];for(let e of t)for(let t=n.length-1;t>=0;t--){let r=n[t];if(!p.has(r.id)&&ae(e,r.body)){p.add(r.id);break}}}let m=new Map,h=[];for(let t of e){if(Ee(t)){let e=typeof t.payload?.kind==`string`?t.payload.kind:``;if(De.has(e)){let n=t.payload,r=typeof n.agentId==`string`?n.agentId:``,i=G(t);if(!r){a.push({ts:i,entry:{type:`notice`,msg:t}});continue}let o=e===`agent.ready`?`ready`:e===`agent.exited`?`exited`:`failed`,s=m.get(r);if(s)s.entry.status=o,typeof n.reason==`string`&&(s.entry.reason=n.reason),s.entry.timestamp=i,s.ts=i;else{let e={ts:i,entry:{type:`agent-action`,direction:`spawned-child`,agentId:r,provider:typeof n.provider==`string`?n.provider:void 0,status:o,reason:typeof n.reason==`string`?n.reason:void 0,timestamp:i}};m.set(r,e),a.push(e)}continue}a.push({ts:G(t),entry:{type:`notice`,msg:t}});continue}let e=xe(t);if(e){h.push(e);continue}let n=be(t);if(n){if(n.kind===`narration`&&p.has(n.id))continue;a.push({ts:n.ts,entry:{type:`activity`,steps:[n],timestamp:n.ts}});continue}let r=Se(t);if(r){a.push({ts:r.timestamp,entry:{type:`relay-injection`,event:r}});continue}let i=Ce(t);if(i){a.push({ts:i.timestamp,entry:{type:`prompt-resolution`,event:i}});continue}if(t.kind===`session`){let e=t.payload?.session;if(e?.type===`response`&&typeof e.turnId==`string`){let e=d.get(t.id);if(e&&e!==t.body){a.push({ts:G(t),entry:{type:`message`,msg:{...t,body:e}}});continue}}}let o=t.id===s?`initial-prompt`:`message`;a.push({ts:G(t),entry:{type:o,msg:t}})}for(let e of Oe([...t,...h]))a.push({ts:e.timestamp,entry:{type:`status`,event:e}});let g={created:0,date:1,"import-boundary":2,"imported-message":3,"initial-prompt":4,message:4,activity:4,notice:4,"agent-action":4,"relay-injection":4,"prompt-resolution":4,status:5};a.sort((e,t)=>{let n=e.ts-t.ts;return Math.abs(n)<3e3&&g[e.entry.type]-g[t.entry.type]||n});let _=[],v=``;for(let{ts:e,entry:t}of a){if(t.type===`created`){_.push(t);continue}let n=K(e);if(n!==v&&(_.push({type:`date`,date:n,timestamp:e}),v=n),t.type===`activity`){let e=_[_.length-1];if(e&&e.type===`activity`&&Me(e,t)){e.steps.push(...t.steps);continue}}_.push(t)}return _}function Ae(e){return e.type===`message`?`msg-${e.msg.id}`:e.type===`initial-prompt`?`initprompt-${e.msg.id}`:e.type===`notice`?`notice-${e.msg.id}`:e.type===`relay-injection`?`relay-injection-${e.event.id}`:e.type===`prompt-resolution`?`prompt-resolution-${e.event.id}`:e.type===`agent-action`?`agent-action-${e.direction}-${e.agentId}`:e.type===`activity`?`act-${e.steps[0]?.id??e.timestamp}`:e.type===`import-boundary`?`import-${e.history.id}`:e.type===`imported-message`?`import-msg-${e.history.id}-${e.entry.originalMessageId}-${e.entry.position}`:e.type===`status`?`status-${e.event.id}`:e.type===`date`?`date-${e.date}`:`created-${e.timestamp}`}function je(e){return e.type===`message`||e.type===`initial-prompt`||e.type===`notice`?(e.msg.subject?`${e.msg.subject} `:``)+z(e.msg):e.type===`imported-message`?z(e.entry.message):e.type===`activity`?e.steps.map(e=>[e.label,e.text].filter(Boolean).join(` `)).join(`
|
|
2
|
-
`):e.type===`relay-injection`?`${e.event.category} ${e.event.summary}\n${JSON.stringify(e.event.detail)}`:e.type===`prompt-resolution`?[e.event.title,e.event.decisionLabel,e.event.body,...e.event.questions.map(e=>`${e.question} ${e.answer}`)].filter(Boolean).join(`
|
|
3
|
-
`):``}function Me(e,t){let n=e.steps[e.steps.length-1]?.turnId,r=t.steps[0]?.turnId;return n&&r?n===r:!n&&!r}function Ne(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function Pe(e,t){if(t.startsWith(`/`))return t;let n=`${e.replace(/\/+$/,``)}/${t}`.split(`/`),r=[];for(let e of n)!e||e===`.`||(e===`..`?r.pop():r.push(e));return`/`+r.join(`/`)}function Fe(e){let t=e.replace(/\/+$/,``),n=t.lastIndexOf(`/`);return n>0?t.slice(0,n):`/`}function Ie(e,t){return e.filter(e=>e.status===`online`&&oe(t,e.baseDir)).sort((e,t)=>L(t.baseDir).length-L(e.baseDir).length)[0]||e.find(e=>e.status===`online`)}function Le(){return typeof window<`u`&&window.matchMedia(`(min-width: 1280px)`).matches}function Re(){return typeof window<`u`&&!!window.getSelection()?.toString()}function ze(e){let t=e.payload?.attachments;return Array.isArray(t)?t.filter(e=>!!(e&&typeof e==`object`&&typeof e.artifactId==`string`)):[]}var Be=[`👍`,`❤️`,`✅`,`👀`];function Ve(e){let t=new Map;for(let n of e.reactions||[]){let e=R(n.emoji),r=t.get(e)??{emoji:e,count:0,mine:!1,actors:[]};r.count+=1,r.mine=r.mine||n.actorId===`user`,r.actors.push(n.actorId),t.set(e,r)}return[...t.values()].sort((e,t)=>t.count-e.count||e.emoji.localeCompare(t.emoji))}function q(e){return I(e)}function He(e,t){let n=e.readBy||[],r=e.resolvedToAgent||t||e.to,i=r?n.includes(r):!1,o=n.some(e=>e!==V);if(i||o){let e=i?r:n.find(e=>e!==V);return{label:`read`,title:e?`Read by ${e}`:`Read by agent`,tone:`ok`,icon:a}}if(e.deliveryStatus===`delivered`)return{label:`delivered`,title:`Delivered to agent inbox`,tone:`ok`,icon:a};if(e.deliveryStatus===`queued`)return{label:`queued`,title:`Queued until the target agent is available`,tone:`warn`,icon:E};if(e.deliveryStatus===`failed`||e.deliveryStatus===`dead`){let t=e.deliveryPoisonReason||e.deliveryLastError||e.deliveryStatus;return{label:e.deliveryStatus,title:t,tone:`danger`,icon:v}}return{label:`sent`,title:`Accepted by Relay`,tone:`muted`,icon:f}}function Ue(e){let t=B(e.createdAt);return(e.reactions||[]).reduce((e,t)=>Math.max(e,B(t.updatedAt||t.createdAt)),t)}function We(e){return e?e.messages.reduce((e,t)=>Math.max(e,Ue(t)),0):0}function Ge(e,t,n){return(e-t)*n}function Ke(e){if(!e)return 0;let t=0;for(let n of e.messages)se(n)&&(t=Math.max(t,B(n.createdAt)));return t}function J(e){return new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`})}function qe(e){for(let t of e)t.previewUrl&&URL.revokeObjectURL(t.previewUrl)}function Je(e,t,n,r){if(e?.teamId)return{teamId:e.teamId};let i=[...t];n&&!i.some(e=>e.id===n.id)&&i.push(n);let a=i.filter(e=>e.threadId).reverse(),o=a.find(e=>!!r[M(e.threadId,e.channel)])??a[0];return o?.threadId?{threadId:o.threadId,...o.channel?{channel:o.channel}:{}}:null}var Y=_(),Ye={online:`text-emerald-400`,offline:`text-zinc-400`,shutdown:`text-zinc-400`,restarted:`text-blue-400`,"compaction-requested":`text-zinc-400`,compacting:`text-amber-400`,compacted:`text-amber-400`,"compaction-stalled":`text-red-400`,"clear-requested":`text-zinc-400`,"clearing-context":`text-amber-400`,"context-cleared":`text-amber-400`,"clear-stalled":`text-red-400`,"shutting-down":`text-zinc-400`};function Xe(e){let t=new Date,[n,r,i]=e.split(`-`).map(Number),a=new Date(n,r-1,i);if(e===K(t.getTime()))return`Today`;let o=new Date(t);return o.setDate(o.getDate()-1),e===K(o.getTime())?`Yesterday`:a.toLocaleDateString(void 0,{weekday:`short`,month:`short`,day:`numeric`,year:a.getFullYear()===t.getFullYear()?void 0:`numeric`})}function Ze({event:e}){return(0,Y.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,Y.jsx)(ne,{className:g(`w-2 h-2 fill-current`,Ye[e.status]||`text-zinc-400`)}),(0,Y.jsx)(`span`,{children:_e[e.status]||e.status}),(0,Y.jsx)(`span`,{className:`text-muted-foreground/60`,children:J(e.timestamp)})]}),(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}var Qe={"branch.landed":o,"context.warning":T,"agent.context_threshold":T,"agent.resume_budget_exhausted":T,"agent.rate_limit_resume":m},$e={"branch.landed":`branch landed`,"context.warning":`context warning`,"agent.context_threshold":`context threshold reached`};function et(e){return e&&(e.includes(`.`)?e.slice(e.indexOf(`.`)+1):e).replace(/[._-]+/g,` `).trim()||`system signal`}function X({agentId:e,fallbackLabel:t,className:n,noIcon:r}){let i=N(t=>t.agentsById[e])||null,a=N(e=>e.openInboxThread),o=N(e=>e.switchView),s=i?ue(i):t||e;return(0,Y.jsxs)(`button`,{type:`button`,className:g(`inline-flex max-w-full items-center gap-1 rounded px-1 text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground`,n),onClick:t=>{t.stopPropagation(),a(e),o(`chat`)},title:`Open chat for ${s}`,children:[!r&&(0,Y.jsx)(H,{agent:i,className:`w-4 h-4 text-[10px]`}),(0,Y.jsx)(`span`,{className:`max-w-[160px] truncate`,children:s})]})}function tt({msg:e}){let t=e.payload??{},n=rt(e),r=typeof t.sha==`string`?t.sha:``,i=r?r.slice(0,7):``,a=typeof t.author==`string`?t.author:``,s=typeof t.branch==`string`?t.branch:``,c=typeof t.base==`string`?t.base:``,l=t.pushed;return(0,Y.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Y.jsxs)(`div`,{className:`flex max-w-full flex-wrap items-center justify-center gap-x-1.5 gap-y-0.5 rounded-full border border-emerald-600/35 bg-emerald-500/10 px-2.5 py-1 text-xs text-emerald-700 dark:border-emerald-500/25 dark:text-emerald-300/90`,children:[(0,Y.jsx)(o,{className:`h-3 w-3 shrink-0 text-emerald-600 dark:text-emerald-400`}),(0,Y.jsx)(`span`,{className:`text-emerald-700 dark:text-emerald-300`,children:`branch landed`}),s&&c&&(0,Y.jsxs)(`span`,{className:`font-mono text-emerald-700/80 dark:text-emerald-200/70`,title:`${s} → ${c}`,children:[s,(0,Y.jsx)(`span`,{className:`opacity-50`,children:` → `}),c]}),i&&(0,Y.jsx)(`span`,{className:`rounded bg-emerald-500/15 px-1 font-mono text-emerald-800 dark:text-emerald-200`,title:r,children:i}),a&&(0,Y.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-emerald-700/80 dark:text-emerald-300/80`,children:[(0,Y.jsx)(`span`,{className:`opacity-70`,children:`by`}),(0,Y.jsx)(X,{agentId:a,className:`text-emerald-700 hover:text-emerald-900 dark:text-emerald-300/90 dark:hover:text-emerald-100`})]}),l===!1&&(0,Y.jsx)(`span`,{className:`text-amber-600 dark:text-amber-300/80`,title:`Local-only land — not pushed to origin`,children:`· local only`}),n&&(0,Y.jsxs)(`span`,{className:`max-w-[220px] truncate text-emerald-700/70 dark:text-emerald-300/70`,title:n,children:[`· because `,n]}),(0,Y.jsx)(`span`,{className:`text-emerald-700/60 dark:text-emerald-300/50`,children:J(e.occurredAt??e.createdAt)})]}),(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function nt({msg:e}){let t=typeof e.payload?.kind==`string`?e.payload.kind:``;if(t===`branch.landed`)return(0,Y.jsx)(tt,{msg:e});let n=Qe[t]??l,r=$e[t]??et(t),i=rt(e);return(0,Y.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-1.5 rounded-full border border-border bg-muted/30 px-2.5 py-1 text-xs text-muted-foreground`,children:[(0,Y.jsx)(n,{className:`h-3 w-3`}),(0,Y.jsx)(`span`,{children:r}),i&&(0,Y.jsxs)(`span`,{className:`max-w-[220px] truncate text-muted-foreground/80`,title:i,children:[`· because `,i]}),(0,Y.jsx)(`span`,{className:`text-muted-foreground/60`,children:J(e.occurredAt??e.createdAt)})]}),(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function rt(e){let t=e.payload?.routing;if(!t||typeof t!=`object`||Array.isArray(t))return``;let n=t.reason;return typeof n==`string`?n:``}var it={"spawned-child":{ready:`spawned`,exited:`spawned · exited`,failed:`spawn failed`},"spawned-by":{ready:`spawned by`,exited:`spawned by`,failed:`spawned by`}},at={"spawned-child-ready":i,"spawned-child-exited":w,"spawned-child-failed":v,"spawned-by-ready":p,"spawned-by-exited":p,"spawned-by-failed":p},ot={"spawned-child-ready":`text-emerald-400`,"spawned-child-exited":`text-zinc-400`,"spawned-child-failed":`text-red-400`,"spawned-by-ready":`text-blue-400`,"spawned-by-exited":`text-blue-400`,"spawned-by-failed":`text-blue-400`};function st({entry:e}){let t=`${e.direction}-${e.status}`,n=it[e.direction]?.[e.status]??e.direction,r=at[t]??l,i=ot[t]??`text-muted-foreground`,a=e.status===`failed`;return(0,Y.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Y.jsxs)(`div`,{className:g(`flex items-center gap-1.5 rounded-full border bg-muted/30 px-2.5 py-1 text-xs`,a?`border-red-500/30`:`border-border`),children:[(0,Y.jsx)(r,{className:g(`h-3 w-3 shrink-0`,i)}),(0,Y.jsx)(`span`,{className:`text-muted-foreground`,children:n}),(0,Y.jsx)(X,{agentId:e.agentId}),e.reason&&a&&(0,Y.jsxs)(`span`,{className:`text-red-400/80 max-w-[120px] truncate`,title:e.reason,children:[`— `,e.reason]}),(0,Y.jsx)(`span`,{className:`text-muted-foreground/60 shrink-0`,children:J(e.timestamp)})]}),(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}var ct={memory:r,instructions:h,tools:y,comms:l,knowledge:s,context:n},lt={memory:`border-emerald-500/25 bg-emerald-500/10 text-emerald-300`,instructions:`border-sky-500/25 bg-sky-500/10 text-sky-300`,tools:`border-amber-500/25 bg-amber-500/10 text-amber-300`,comms:`border-violet-500/25 bg-violet-500/10 text-violet-300`,knowledge:`border-cyan-500/25 bg-cyan-500/10 text-cyan-300`,context:`border-zinc-500/25 bg-zinc-500/10 text-zinc-300`};function ut(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function dt({entry:e}){let[t,n]=(0,W.useState)(!1),r=e.event,i=ct[r.category]??b;return(0,Y.jsx)(`div`,{className:`flex justify-center py-2 my-1`,children:(0,Y.jsxs)(`div`,{className:g(`w-full max-w-[85%] md:max-w-[75%] rounded-lg border px-2.5 py-1.5 text-xs shadow-sm`,lt[r.category]??lt.context),children:[(0,Y.jsxs)(`button`,{type:`button`,className:`flex w-full min-w-0 items-center gap-1.5 text-left`,onClick:()=>n(e=>!e),children:[(0,Y.jsx)(i,{className:`h-3.5 w-3.5 shrink-0`}),(0,Y.jsx)(`span`,{className:`shrink-0 font-medium`,children:r.category}),(0,Y.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-foreground/80`,children:r.summary}),(0,Y.jsx)(`span`,{className:`shrink-0 text-muted-foreground/60`,children:J(r.timestamp)}),(0,Y.jsx)(j,{className:g(`h-3.5 w-3.5 shrink-0 transition-transform`,t&&`rotate-90`)})]}),t&&(0,Y.jsx)(`pre`,{className:`mt-2 max-h-72 overflow-auto rounded-md border border-border/60 bg-background/75 p-2 font-mono text-[11px] leading-relaxed text-muted-foreground whitespace-pre-wrap break-words`,children:ut(r.detail)})]})})}function ft({blockedLabel:e,onInterrupt:t}){return e?(0,Y.jsx)(`div`,{className:`flex justify-start mb-3 animate-in fade-in slide-in-from-bottom-1 duration-150`,children:(0,Y.jsxs)(`div`,{className:`flex h-9 items-center gap-2 rounded-2xl rounded-bl-sm bg-card ring-1 ring-red-500/30 px-4`,children:[(0,Y.jsx)(v,{className:`w-3.5 h-3.5 text-red-400`}),(0,Y.jsxs)(`span`,{className:`text-xs text-red-300`,children:[`blocked: `,e]})]})}):(0,Y.jsx)(`div`,{className:`flex justify-start mb-3 animate-in fade-in slide-in-from-bottom-1 duration-150`,children:(0,Y.jsxs)(`div`,{className:`flex h-9 items-center gap-2 rounded-2xl rounded-bl-sm bg-card ring-1 ring-foreground/10 px-4`,children:[(0,Y.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,Y.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-yellow-400 animate-[pulse_1.4s_ease-in-out_infinite]`}),(0,Y.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-yellow-400 animate-[pulse_1.4s_ease-in-out_0.2s_infinite]`}),(0,Y.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-yellow-400 animate-[pulse_1.4s_ease-in-out_0.4s_infinite]`})]}),(0,Y.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`working`}),t&&(0,Y.jsxs)(`button`,{onClick:t,title:`Interrupt`,className:`ml-1 flex items-center gap-1 rounded-full px-1.5 py-0.5 text-xs text-muted-foreground hover:text-red-300 hover:bg-red-500/10 transition-colors`,children:[(0,Y.jsx)(re,{className:`w-3.5 h-3.5`}),`Stop`]})]})})}var Z=`agent-relay:chat-hide-tools`,Q=(()=>{let e=new Set,t=(()=>{try{return window.localStorage.getItem(Z)===`on`}catch{return!1}})(),n=()=>e.forEach(e=>e());return typeof window<`u`&&window.addEventListener(`storage`,e=>{e.key===Z&&(t=e.newValue===`on`,n())}),{subscribe(t){return e.add(t),()=>e.delete(t)},get:()=>t,toggle(){t=!t;try{window.localStorage.setItem(Z,t?`on`:`off`)}catch{}n()}}})();function pt(){return[(0,W.useSyncExternalStore)(Q.subscribe,Q.get,()=>!1),Q.toggle]}function mt({steps:e,showReasoning:t,issueRepo:n}){let[i,a]=pt(),o=t?e:e.filter(e=>e.kind!==`reasoning`);if(!o.length)return null;let s=o.filter(e=>e.kind===`tool`).length;return(0,Y.jsx)(`div`,{className:`flex justify-start mb-2`,children:(0,Y.jsxs)(`div`,{className:`max-w-[85%] md:max-w-[75%] min-w-0 space-y-1.5`,children:[o.map(e=>e.kind===`narration`?(0,Y.jsx)(U,{text:e.text,issueRepo:n,className:`text-sm leading-relaxed break-words text-foreground/90 min-w-0`},e.id):e.kind===`reasoning`?(0,Y.jsxs)(`div`,{className:`flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground/80`,children:[(0,Y.jsx)(r,{className:`w-3.5 h-3.5 mt-0.5 shrink-0 opacity-70`}),(0,Y.jsx)(U,{text:e.text,issueRepo:n,className:`italic break-words min-w-0`})]},e.id):i?null:(0,Y.jsxs)(`div`,{className:`flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground`,children:[(0,Y.jsx)(S,{className:`w-3 h-3 mt-0.5 shrink-0 opacity-70`}),(0,Y.jsxs)(`span`,{className:`min-w-0 break-words`,children:[(0,Y.jsx)(`span`,{className:`font-medium`,children:e.label||`tool`}),e.text&&e.text.trim()&&e.text.trim()!==(e.label??``).trim()?(0,Y.jsxs)(`span`,{className:`opacity-70`,children:[` — `,e.text]}):null]})]},e.id)),s>0&&(0,Y.jsxs)(`button`,{onClick:a,className:`flex items-center gap-1 text-[11px] text-muted-foreground/50 hover:text-muted-foreground transition-colors text-left`,children:[(0,Y.jsx)(j,{className:g(`w-3 h-3 shrink-0 transition-transform`,!i&&`rotate-90`)}),(0,Y.jsx)(`span`,{children:i?`show ${s} tool step${s===1?``:`s`}`:`hide tool steps`})]})]})})}function ht({entry:e}){let{event:t}=e,n=t.kind===`questions`,r=n?t.title:t.kind===`plan`?`Plan prompt`:`${t.toolName} permission`;return(0,Y.jsx)(`div`,{className:`flex justify-center py-1.5`,children:(0,Y.jsxs)(`div`,{className:`w-full max-w-2xl rounded-md border border-border bg-muted/20 px-3 py-2 text-sm`,children:[(0,Y.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[(0,Y.jsx)(C,{className:`h-3.5 w-3.5 text-emerald-500`}),(0,Y.jsx)(`span`,{className:`font-medium text-foreground`,children:r}),(0,Y.jsx)(`span`,{children:t.decisionLabel}),(0,Y.jsx)(`span`,{className:`ml-auto shrink-0 text-muted-foreground/60`,children:J(t.timestamp)})]}),n&&t.questions.length>0?(0,Y.jsx)(`div`,{className:`mt-2 space-y-1.5`,children:t.questions.map((e,t)=>(0,Y.jsxs)(`div`,{className:`grid gap-0.5`,children:[(0,Y.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:e.question}),(0,Y.jsx)(`div`,{className:`text-sm text-foreground`,children:e.answer})]},`${e.question}-${t}`))}):t.body.trim()?(0,Y.jsx)(`div`,{className:`mt-2 max-h-48 overflow-auto rounded border border-border/70 bg-background/40 px-2 py-1.5 text-sm`,children:(0,Y.jsx)(U,{text:t.body})}):null]})})}function gt({date:e}){return(0,Y.jsxs)(`div`,{className:`flex items-center justify-center gap-3 py-3 my-1`,children:[(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Y.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground`,children:Xe(e)}),(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function _t({timestamp:e}){let t=new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,year:`numeric`,hour:`2-digit`,minute:`2-digit`});return(0,Y.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Y.jsxs)(`span`,{className:`text-xs text-muted-foreground/60`,children:[`created `,t]}),(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function vt({history:e}){let t=e.sourceAgentLabel||e.sourcePeerId,n=e.entries.length;return(0,Y.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-1.5 rounded-full border border-dashed border-border bg-muted/30 px-2 py-1 text-[11px] text-muted-foreground`,children:[(0,Y.jsx)(u,{className:`h-3 w-3`}),(0,Y.jsxs)(`span`,{children:[`forked history from `,t]}),(0,Y.jsxs)(`span`,{className:`text-muted-foreground/60`,children:[n,` `,n===1?`entry`:`entries`]})]}),(0,Y.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function yt({entry:e,sourceLabel:t,issueRepo:n}){let r=e.message,i=z(r),a=e.originalFrom===V;return(0,Y.jsx)(`div`,{className:g(`flex mb-3 opacity-80`,a?`justify-end`:`justify-start`),children:(0,Y.jsx)(`div`,{className:`max-w-[85%] md:max-w-[75%]`,children:(0,Y.jsxs)(`div`,{className:g(`rounded-2xl border border-dashed px-3.5 py-2 text-sm select-text`,a?`border-primary/25 bg-primary/10 text-foreground rounded-br-sm`:`border-border bg-card/70 rounded-bl-sm`),children:[(0,Y.jsxs)(`div`,{className:g(`mb-1 text-[10px] uppercase tracking-normal`,a?`text-primary/70`:`text-muted-foreground`),children:[`forked history · `,a?`you`:t||e.originalFrom]}),(0,Y.jsx)(U,{text:i,rawBody:r.body,issueRepo:n,className:`leading-relaxed`}),(0,Y.jsxs)(`p`,{className:g(`mt-1 flex items-center justify-end gap-1.5 text-xs`,a?`text-primary/60`:`text-muted-foreground`),children:[(0,Y.jsxs)(`span`,{className:`opacity-40`,children:[`#`,e.originalMessageId]}),(0,Y.jsx)(`span`,{children:J(e.originalCreatedAt)})]})]})})})}function $({msg:e,issueRepo:t}){let n=z(e),r=J(e.occurredAt??e.createdAt);return(0,Y.jsx)(`div`,{"data-msg-id":e.id,className:`mb-3`,children:(0,Y.jsxs)(`div`,{className:`rounded-xl border border-primary/30 bg-primary/[0.06] px-3.5 py-2.5 shadow-sm`,children:[(0,Y.jsxs)(`div`,{className:`mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-primary/80`,children:[(0,Y.jsx)(b,{className:`h-3.5 w-3.5`}),(0,Y.jsx)(`span`,{children:`Initial prompt`}),(0,Y.jsx)(`span`,{className:`ml-auto text-[10px] font-normal normal-case text-muted-foreground/60`,children:r})]}),(0,Y.jsx)(U,{text:n,rawBody:e.body,issueRepo:t,className:`text-sm leading-relaxed text-foreground`})]})})}function bt({scrollEl:e,timeline:t}){let[n,r]=(0,W.useState)(!0),[i,a]=(0,W.useState)(null),[o,s]=(0,W.useState)(null),[c,l]=(0,W.useState)(!1),u=(0,W.useMemo)(()=>{for(let e=t.length-1;e>=0;e--){let n=t[e];if(!(!n||n.type!==`message`&&n.type!==`initial-prompt`)&&n.msg.from===`user`)return{id:n.msg.id,body:z(n.msg)}}return null},[t]);if((0,W.useEffect)(()=>{if(!u||!e){r(!0);return}let t=null,n=null,i=()=>{let i=e.querySelector(`[data-msg-id="${u.id}"]`);if(!i){t?.disconnect(),t=null,n=null,r(!1);return}let a=i.getBoundingClientRect(),o=e.getBoundingClientRect();l(a.top<o.top),i!==n&&(t?.disconnect(),n=i,t=new IntersectionObserver(([e])=>{e&&r(e.isIntersecting)},{root:e,threshold:0}),t.observe(i))};return i(),e.addEventListener(`scroll`,i,{passive:!0}),()=>{t?.disconnect(),e.removeEventListener(`scroll`,i)}},[u?.id,e]),n||!u||!u.body.trim())return null;let d=i?.id===u.id?i.value:!1,f=o?.id===u.id?o.value:!1;function p(){!e||!u||e.querySelector(`[data-msg-id="${u.id}"]`)?.scrollIntoView({behavior:`smooth`,block:`center`})}let m=c?`↑`:`↓`;return f?(0,Y.jsx)(`div`,{className:`flex shrink-0 bg-card/45 border-b border-border`,children:(0,Y.jsxs)(`button`,{type:`button`,className:`w-full flex items-center justify-center gap-1.5 py-1 text-[11px] text-primary/60 hover:text-primary transition-colors`,onClick:()=>s({id:u.id,value:!1}),children:[(0,Y.jsx)(`span`,{children:`Your prompt`}),(0,Y.jsx)(ie,{className:`w-3 h-3`})]})}):(0,Y.jsxs)(`section`,{className:`flex shrink-0 flex-col border-b border-border bg-card/45 px-3 py-2`,children:[(0,Y.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px] text-muted-foreground mb-0.5`,children:[(0,Y.jsx)(`span`,{className:`font-medium text-primary/70`,children:`Your prompt`}),(0,Y.jsxs)(`button`,{type:`button`,className:`ml-auto hover:text-foreground transition-colors`,onClick:p,children:[m,` scroll to original`]}),(0,Y.jsx)(`button`,{type:`button`,className:`hover:text-foreground transition-colors`,onClick:()=>s({id:u.id,value:!0}),title:`Minimize`,children:(0,Y.jsx)(k,{className:`w-3 h-3`})})]}),(0,Y.jsx)(`p`,{className:g(`text-sm text-foreground leading-snug cursor-pointer`,!d&&`line-clamp-2`),onClick:()=>a({id:u.id,value:!d}),children:u.body})]})}function xt(){return(0,W.useSyncExternalStore)(e=>P.subscribe(e),()=>P.getPlayingKey(),()=>null)}function St({msg:e,peer:t}){return(0,Y.jsx)($,{msg:e,issueRepo:N(e=>e.agentsById[t]?.issueRepo)})}function Ct({agent:e,onClick:t}){let n=!!(t&&e);return(0,Y.jsx)(`button`,{type:`button`,title:e?e.label||e.name||e.id:void 0,onClick:t,disabled:!n,className:g(`shrink-0 self-end transition-opacity`,n?`cursor-pointer hover:opacity-80`:`cursor-default opacity-60`),children:(0,Y.jsx)(H,{agent:e})})}function wt({agentId:e,onOpen:t}){let n=N(t=>t.agentsById[e]??null);return(0,Y.jsx)(Ct,{agent:n,onClick:n?()=>t(n):void 0})}function Tt({attachment:e,outbound:n}){let r=e.kind===`image`,i=e.title||e.artifactId,[a,o]=(0,W.useState)(null),[s,c]=(0,W.useState)(null),[l,u]=(0,W.useState)(!1),[f,p]=(0,W.useState)(!1);(0,W.useEffect)(()=>{let n=!1,r=null;async function i(){u(!0),c(null),o(null);try{let i=await t(`/artifacts/${encodeURIComponent(e.artifactId)}/content`);if(n)return;r=URL.createObjectURL(i),o(r)}catch(e){n||c(e.message)}finally{n||u(!1)}}return i(),()=>{n=!0,r&&URL.revokeObjectURL(r)}},[e.artifactId]);function m(){if(!a)return;let e=document.createElement(`a`);e.href=a,e.download=i,document.body.appendChild(e),e.click(),e.remove()}return r?(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(`button`,{type:`button`,onClick:()=>a&&p(!0),disabled:!a,className:`group/img mt-2 block overflow-hidden rounded-md border border-foreground/10 bg-black/10 text-left disabled:cursor-default relative`,children:a?(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(`img`,{src:a,alt:i,loading:`lazy`,className:`block max-h-72 max-w-full object-contain`}),(0,Y.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-black/0 group-hover/img:bg-black/30 transition-colors`,children:(0,Y.jsx)(D,{className:`w-6 h-6 text-white opacity-0 group-hover/img:opacity-100 transition-opacity drop-shadow-md`})})]}):(0,Y.jsxs)(`span`,{className:g(`flex min-h-20 items-center gap-2 px-3 py-2 text-xs`,s?`text-red-400`:`text-muted-foreground`),children:[l?(0,Y.jsx)(x,{className:`h-4 w-4 animate-spin`}):(0,Y.jsx)(v,{className:`h-4 w-4`}),s||`Loading image`]})}),a&&(0,Y.jsx)(me,{open:f,onOpenChange:p,children:(0,Y.jsxs)(pe,{className:`max-w-[95vw] max-h-[95vh] w-auto p-0 bg-black/95 border-zinc-800 gap-0 overflow-hidden`,showCloseButton:!1,children:[(0,Y.jsx)(he,{className:`sr-only`,children:i}),(0,Y.jsxs)(`div`,{className:`relative flex items-center justify-center min-h-[200px]`,children:[(0,Y.jsx)(`img`,{src:a,alt:i,className:`max-w-[93vw] max-h-[90vh] object-contain`}),(0,Y.jsxs)(`div`,{className:`absolute top-2 right-2 flex gap-1`,children:[(0,Y.jsx)(`button`,{type:`button`,onClick:m,className:`rounded-md bg-black/60 hover:bg-black/80 p-2 text-white transition-colors`,title:`Download`,children:(0,Y.jsx)(d,{className:`w-4 h-4`})}),(0,Y.jsx)(`button`,{type:`button`,onClick:()=>p(!1),className:`rounded-md bg-black/60 hover:bg-black/80 p-2 text-white transition-colors`,title:`Close`,children:(0,Y.jsx)(te,{className:`w-4 h-4`})})]})]})]})})]}):(0,Y.jsxs)(`button`,{type:`button`,onClick:m,disabled:!a,className:g(`mt-2 flex w-full items-center gap-2 rounded-md border px-2.5 py-2 text-left text-xs transition-colors disabled:cursor-default disabled:opacity-70`,n?`border-primary-foreground/20 bg-primary-foreground/10 hover:bg-primary-foreground/15`:`border-border bg-background hover:bg-muted`),children:[l?(0,Y.jsx)(x,{className:`h-4 w-4 shrink-0 animate-spin`}):s?(0,Y.jsx)(v,{className:`h-4 w-4 shrink-0 text-red-400`}):(0,Y.jsx)(h,{className:`h-4 w-4 shrink-0`}),(0,Y.jsx)(`span`,{className:g(`min-w-0 flex-1 truncate`,s&&`text-red-400`),children:s||i}),(0,Y.jsx)(d,{className:`h-3.5 w-3.5 shrink-0`})]})}function Et({open:e,onToggle:t,onReact:n}){return(0,Y.jsxs)(`div`,{className:`relative shrink-0`,children:[(0,Y.jsx)(`button`,{type:`button`,title:`Add reaction`,onClick:t,className:g(`inline-flex h-5 w-6 items-center justify-center rounded-full border border-border bg-popover text-muted-foreground shadow-sm transition hover:bg-muted hover:text-foreground`,e?`opacity-100`:`opacity-0 pointer-events-none md:group-hover/msg:opacity-100 md:group-hover/msg:pointer-events-auto`),children:(0,Y.jsx)(A,{className:`h-3 w-3`})}),e&&(0,Y.jsx)(`div`,{className:`absolute bottom-full left-0 z-30 mb-1 flex gap-0.5 rounded-full border border-border bg-popover p-0.5 shadow-md`,children:Be.map(e=>(0,Y.jsx)(`button`,{type:`button`,title:`React ${e}`,onClick:()=>n(e),className:`inline-flex h-6 w-7 items-center justify-center rounded-full text-xs transition-colors hover:bg-muted`,children:e},e))})]})}function Dt({msg:e,peer:t}){let[n,r]=(0,W.useState)(!1),i=N(e=>e.agentsById),a=N(e=>e.openAgentDetail),o=e.from===t,s=(o?e.to:e.from)||``,l=i[o?t:s]?.issueRepo??i[t]?.issueRepo,u=!s||s===`broadcast`||s.includes(`:`),d=z(e),f=J(e.occurredAt??e.createdAt),m=o?c:p,h=i[e.from??``]??null;function _(e){e.stopPropagation(),h&&a(h)}return(0,Y.jsx)(`div`,{"data-msg-id":e.id,className:`flex justify-center mb-1.5`,children:(0,Y.jsxs)(`div`,{className:`w-full max-w-[94%] rounded-md border border-border/50 bg-muted/15 px-2.5 py-1`,children:[(0,Y.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs cursor-pointer select-none`,onClick:()=>r(e=>!e),children:[(0,Y.jsx)(j,{className:g(`h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform`,n&&`rotate-90`)}),(0,Y.jsx)(`button`,{type:`button`,title:h?h.label||h.name||h.id:void 0,disabled:!h,onClick:_,className:g(`shrink-0 transition-opacity`,h?`cursor-pointer hover:opacity-80`:`cursor-default opacity-60`),children:(0,Y.jsx)(H,{agent:h,className:`!w-4 !h-4 !rounded-sm opacity-70`})}),(0,Y.jsx)(m,{className:`h-3 w-3 shrink-0 text-muted-foreground/70`}),(0,Y.jsxs)(`span`,{className:`shrink-0 text-muted-foreground`,children:[`Message `,o?`to`:`from`]}),u?(0,Y.jsx)(`span`,{className:`shrink-0 font-medium text-muted-foreground`,children:de(s,i)}):(0,Y.jsx)(X,{agentId:s,className:`shrink-0 px-0.5 text-foreground/80`,noIcon:!0}),!n&&(0,Y.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-muted-foreground/50`,children:d}),(0,Y.jsx)(`span`,{className:`ml-auto shrink-0 text-muted-foreground/40`,children:f})]}),n&&(0,Y.jsx)(`div`,{className:`mt-1.5 pl-5`,children:(0,Y.jsx)(U,{text:d,rawBody:e.body,issueRepo:l,className:`text-sm leading-relaxed text-foreground/90`})})]})})}var Ot=(0,W.memo)(function({msg:e,peer:t,showAvatar:n=!1,onOpenReferencedPath:r,onPreviewReferencedPath:i,onPreviewReferencedPathEnd:a}){if(!F(e.from)&&!F(e.to))return(0,Y.jsx)(Dt,{msg:e,peer:t});let o=e.kind===`session`?e.payload?.session:void 0;if(o?.type===`prompt`&&o?.origin===`provider`)return(0,Y.jsx)(St,{msg:e,peer:t});let s=F(e.from),c=N(e=>e.reactToMessage),l=N(e=>e.voiceTtsEnabled),u=xt(),d=N(e=>{let n=e.agentsById[t]?.meta?.cwd;return typeof n==`string`?n:``}),f=N(e=>e.agentsById[t]?.issueRepo),p=N(e=>e.usersById),m=N(e=>e.users.length>1),h=s?ce(e.from,p):void 0,_=N(e=>e.openAgentDetail),[v,y]=(0,W.useState)(!1),b=(0,W.useRef)(null),x=(0,W.useRef)(null),S=(0,W.useRef)(!1),C=z(e),te=J(e.occurredAt??e.createdAt),ne=ze(e),w=Ve(e),T=s?He(e,t):null,E=T?.icon,D=u===String(e.id),O=l&&!s&&!q(e)&&C.trim().length>0;function k(t){t.stopPropagation(),D?P.bargeIn():P.speak(e.body,String(e.id))}(0,W.useEffect)(()=>{if(!v)return;function e(e){Re()||b.current&&!b.current.contains(e.target)&&y(!1)}return document.addEventListener(`mousedown`,e),document.addEventListener(`touchstart`,e),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`touchstart`,e)}},[v]);function A(e){return Pe(d||`/`,e)}function ie(e,t){let n=A(e);r?.(n,t)}function j(e,t,n){let r=A(e);i?.(r,t,n)}function M(t){c(e,t),y(!1)}function I(e){e.button===0&&(x.current={x:e.clientX,y:e.clientY},S.current=!1)}function ae(e){let t=x.current;t&&(Math.abs(e.clientX-t.x)>3||Math.abs(e.clientY-t.y)>3)&&(S.current=!0)}function L(t){if(!(q(e)||s)&&!t.target.closest(`a,button,input,textarea,select,[role="button"]`)){if(S.current||Re()){S.current=!1;return}y(e=>!e)}}let R=n&&!q(e);return(0,Y.jsxs)(`div`,{"data-msg-id":e.id,className:g(`group/msg flex mb-3 items-end`,s?`justify-end`:`justify-start`,R&&`gap-1.5`),children:[!s&&R&&(0,Y.jsx)(wt,{agentId:t,onOpen:_}),(0,Y.jsxs)(`div`,{ref:b,className:g(`relative`,R?`max-w-[calc(85%-2rem)] md:max-w-[calc(75%-2rem)]`:`max-w-[85%] md:max-w-[75%]`),children:[O&&(0,Y.jsx)(`button`,{type:`button`,title:D?`Stop playback`:`Play aloud`,onClick:k,className:g(`absolute -top-2 -right-2 z-20 inline-flex h-6 w-6 items-center justify-center rounded-full border bg-popover shadow-sm transition`,D?`border-primary/50 text-primary opacity-100`:`border-border text-muted-foreground opacity-70 hover:bg-muted hover:text-foreground hover:opacity-100 [@media(hover:hover)]:md:opacity-0 [@media(hover:hover)]:md:group-hover/msg:opacity-100`),children:D?(0,Y.jsx)(re,{className:`h-3.5 w-3.5 animate-pulse`}):(0,Y.jsx)(ee,{className:`h-3.5 w-3.5`})}),(0,Y.jsxs)(`div`,{className:g(`rounded-2xl px-3.5 py-2 text-sm select-text`,!s&&!q(e)&&`cursor-pointer`,s?`bg-primary text-primary-foreground rounded-br-sm`:`bg-card ring-1 ring-foreground/10 rounded-bl-sm`),onPointerDown:I,onPointerMove:ae,onClick:L,children:[s&&m&&(0,Y.jsx)(`p`,{className:g(`text-[11px] font-semibold mb-0.5 text-right`,le(e.from)),children:fe(e.from,p)}),e.subject&&(0,Y.jsx)(`p`,{className:g(`text-xs font-semibold mb-1`,s?`text-primary-foreground/70`:`text-muted-foreground`),children:e.subject}),(0,Y.jsx)(U,{text:C,rawBody:e.body,issueRepo:f,className:`leading-relaxed`,onPrimary:s,onOpenPath:ie,onPreviewPath:j,onPreviewPathEnd:a,resolvePathTitle:(e,t)=>`${A(e)}${t?`:${t}`:``}`}),ne.map(t=>(0,Y.jsx)(Tt,{attachment:t,outbound:s},`${e.id}-${t.artifactId}-${t.role||``}`)),(0,Y.jsxs)(`p`,{className:g(`text-xs mt-1 flex items-center gap-1.5`,s?`justify-end text-primary-foreground/60`:`justify-end text-muted-foreground`),children:[(0,Y.jsxs)(`span`,{className:`opacity-40`,children:[`#`,e.id]}),(0,Y.jsx)(`span`,{children:te}),T&&E&&(0,Y.jsxs)(`span`,{className:g(`inline-flex items-center gap-1`,T.tone===`ok`&&`text-emerald-300`,T.tone===`warn`&&`text-amber-200`,T.tone===`danger`&&`text-red-200`),title:T.title,children:[(0,Y.jsx)(E,{className:`h-3 w-3`}),T.label]})]})]}),!q(e)&&w.length>0&&(0,Y.jsxs)(`div`,{className:g(`flex flex-wrap items-center gap-0.5 -mt-1 relative z-10`,s?`justify-end pr-2`:`justify-start pl-2`),children:[!s&&(0,Y.jsx)(Et,{open:v,onToggle:()=>y(e=>!e),onReact:M}),w.map(e=>(0,Y.jsxs)(`button`,{type:`button`,title:e.actors.join(`, `),onClick:()=>M(e.emoji),className:g(`inline-flex h-5 items-center gap-0.5 rounded-full border px-1.5 text-[11px] shadow-sm transition-colors`,e.mine?`border-primary/40 bg-primary/10 text-primary`:`border-border bg-background hover:bg-muted text-foreground`),children:[(0,Y.jsx)(`span`,{children:e.emoji}),e.count>1&&(0,Y.jsx)(`span`,{children:e.count})]},e.emoji))]}),!q(e)&&!s&&w.length===0&&(0,Y.jsx)(`div`,{className:`absolute -bottom-2.5 left-1 z-20`,children:(0,Y.jsx)(Et,{open:v,onToggle:()=>y(e=>!e),onReact:M})})]}),s&&R&&(0,Y.jsx)(`span`,{className:`shrink-0 self-end opacity-60`,children:(0,Y.jsx)(ge,{user:h,address:e.from,distinct:m})})]})});export{We as C,je as E,Le as S,Ae as T,Ke as _,_t as a,Je as b,yt as c,ht as d,dt as f,Ne as g,Ge as h,ft as i,$ as l,bt as m,mt as n,gt as o,Ze as p,st as r,vt as s,Ot as t,nt as u,Ie as v,ke as w,qe as x,Fe as y};
|
|
4
|
-
//# sourceMappingURL=MessageBubble-PEdvVh_m.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{At as t,Yn as n,Zn as r,ur as i,vn as a,xn as o}from"./lucide-react-C4eXYCwx.js";import{i as s,r as c,t as l}from"./store-DUfrGvOE.js";import{h as u}from"./index-3ydeNO0c.js";var d=e(i(),1),f=`(max-width: 767px)`;function p(e){if(typeof window>`u`)return()=>{};let t=window.matchMedia(f);return t.addEventListener(`change`,e),()=>t.removeEventListener(`change`,e)}function m(){return(0,d.useSyncExternalStore)(p,()=>typeof window<`u`?window.matchMedia(f).matches:!1,()=>!1)}var h=r(),g=196,_=84,v=52,y=16,b=14,x=[`landed`,`in-progress`,`pending`,`blocked`],S={landed:{label:`landed`,dot:`bg-emerald-400`,accent:`border-l-emerald-400`,text:`text-emerald-300`,wire:`#34d399`},"in-progress":{label:`in progress`,dot:`bg-sky-400`,accent:`border-l-sky-400`,text:`text-sky-300`,wire:`#38bdf8`},pending:{label:`pending`,dot:`bg-amber-400`,accent:`border-l-amber-400`,text:`text-amber-300`,wire:`#fbbf24`},blocked:{label:`blocked`,dot:`bg-red-400`,accent:`border-l-red-400`,text:`text-red-300`,wire:`#f87171`}};function C(e){return e?e.label||(e.policyName?`policy:${e.policyName}`:e.agentId||``):``}function w(e){let t=new Map(e.nodes.map(e=>[e.id,e])),n=new Map(e.nodes.map((e,t)=>[e.id,t])),r=new Map,i=new Map(e.nodes.map(e=>[e.id,0]));for(let n of e.edges)!t.has(n.from)||!t.has(n.to)||(r.set(n.from,[...r.get(n.from)??[],n.to]),i.set(n.to,(i.get(n.to)??0)+1));let a=new Map(e.nodes.map(e=>[e.id,0])),o=e.nodes.filter(e=>(i.get(e.id)??0)===0).map(e=>e.id),s=new Set;for(;o.length;){let e=o.shift();s.add(e);let t=a.get(e)??0;for(let n of r.get(e)??[])a.set(n,Math.max(a.get(n)??0,t+1)),i.set(n,(i.get(n)??0)-1),(i.get(n)??0)===0&&o.push(n)}let c=Math.max(0,...Array.from(a.values()))+1;for(let t of e.nodes)s.has(t.id)||a.set(t.id,c++);let l=new Map;for(let t of e.nodes){let e=a.get(t.id)??0;l.set(e,[...l.get(e)??[],t])}let u=[...l.entries()].sort(([e],[t])=>e-t),d=Math.max(1,...u.map(([,e])=>e.length)),f=_+y,p=[];u.forEach(([e,t],r)=>{let i=[...t].sort((e,t)=>(e.lane||``).localeCompare(t.lane||``)||(n.get(e.id)??0)-(n.get(t.id)??0)),a=(d-i.length)*f/2;i.forEach((t,n)=>{p.push({node:t,layer:e,x:b+r*(g+v),y:b+a+n*f})})});let m=u.length;return{nodes:p,width:Math.max(320,b*2+m*g+Math.max(0,m-1)*v),height:Math.max(_+b*2,b*2+d*_+Math.max(0,d-1)*y)}}function T(e,t){let n=e.x+g,r=e.y+_/2,i=t.x,a=t.y+_/2,o=n+Math.max(20,(i-n)/2);return`M ${n} ${r} C ${o} ${r}, ${o} ${a}, ${i} ${a}`}function E({threadId:e,teamId:r,channel:i}){let f=r?s(r,i):e?c(e,i):``,p=l(e=>r?e.plansByTeam[f]:f?e.plansByThread[f]:null),v=l(e=>e.fetchPlan),y=l(e=>e.planCollapsed),b=l(e=>e.setPlanCollapsed),E=l(e=>e.issueRefsById),D=m(),O=y??D;(0,d.useEffect)(()=>{if(r){v({teamId:r,channel:i});return}e&&v({threadId:e,channel:i})},[i,v,r,e]);let k=(0,d.useMemo)(()=>p?w(p):null,[p]),A=(0,d.useMemo)(()=>new Map(k?.nodes.map(e=>[e.node.id,e])??[]),[k]),j=(0,d.useMemo)(()=>{if(!p)return[];let e=new Map;for(let t of p.nodes)e.set(t.status,(e.get(t.status)??0)+1);return x.filter(t=>e.has(t)).map(t=>({status:t,count:e.get(t)??0}))},[p]);if(!p||!k)return null;let M=p.nodes.length,N=j.find(e=>e.status===`landed`)?.count??0,P=`${M} node${M===1?``:`s`}${N>0?` · ${N} landed`:``}`;return(0,h.jsxs)(`section`,{className:`shrink-0 border-b border-border bg-card/45 px-3 py-2`,children:[(0,h.jsxs)(`button`,{type:`button`,onClick:()=>b(!O),"aria-expanded":!O,"aria-label":O?`Expand plan graph`:`Collapse plan graph`,className:n(`flex w-full min-w-0 items-center gap-2 text-left`,!O&&`mb-2`),children:[(0,h.jsx)(`span`,{className:`flex h-5 w-5 shrink-0 items-center justify-center rounded bg-muted/60`,children:(0,h.jsx)(t,{className:`h-3 w-3 text-muted-foreground`})}),(0,h.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,h.jsx)(`div`,{className:`truncate text-[13px] font-semibold leading-tight text-foreground`,children:p.title||`Plan`}),(0,h.jsx)(`div`,{className:`truncate text-[11px] leading-tight text-muted-foreground`,children:O?P:p.objective||P})]}),j.length>0&&(0,h.jsx)(`div`,{className:`hidden shrink-0 items-center gap-2.5 sm:flex`,children:j.map(({status:e,count:t})=>(0,h.jsxs)(`span`,{className:`flex items-center gap-1 text-[10px] text-muted-foreground`,children:[(0,h.jsx)(`span`,{className:n(`h-1.5 w-1.5 rounded-full`,S[e].dot)}),(0,h.jsx)(`span`,{className:n(`font-medium tabular-nums`,S[e].text),children:t}),(0,h.jsx)(`span`,{children:S[e].label})]},e))}),(0,h.jsxs)(`span`,{className:`shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-muted-foreground`,children:[`v`,p.version]}),(0,h.jsx)(`span`,{className:`flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted/60 hover:text-foreground`,children:O?(0,h.jsx)(o,{className:`h-3.5 w-3.5`}):(0,h.jsx)(a,{className:`h-3.5 w-3.5`})})]}),O?null:p.nodes.length===0?(0,h.jsx)(`div`,{className:`rounded-md border border-dashed border-border px-3 py-3 text-center text-xs text-muted-foreground`,children:`No nodes yet — the plan graph fills in as the team is composed.`}):(0,h.jsx)(`div`,{className:`max-h-[min(46vh,360px)] overflow-auto`,children:(0,h.jsxs)(`div`,{className:`relative`,style:{width:k.width,height:k.height},children:[(0,h.jsxs)(`svg`,{className:`pointer-events-none absolute inset-0`,width:k.width,height:k.height,"aria-hidden":`true`,children:[(0,h.jsx)(`defs`,{children:x.map(e=>(0,h.jsx)(`marker`,{id:`plan-arrow-${e}`,viewBox:`0 0 8 8`,refX:`6.5`,refY:`4`,markerWidth:`6`,markerHeight:`6`,orient:`auto-start-reverse`,children:(0,h.jsx)(`path`,{d:`M0 0 L8 4 L0 8 z`,fill:S[e].wire})},e))}),p.edges.map(e=>{let t=A.get(e.from),n=A.get(e.to);if(!t||!n)return null;let r=S[t.node.status];return(0,h.jsx)(`path`,{d:T(t,n),stroke:r.wire,strokeOpacity:.7,strokeWidth:2,fill:`none`,strokeLinecap:`round`,markerEnd:`url(#plan-arrow-${t.node.status})`},`${e.from}->${e.to}`)})]}),k.nodes.map(({node:e,x:t,y:r})=>{let i=S[e.status],a=C(e.ownerRef),o=e.refs?.issueId?E[e.refs.issueId]:null;return(0,h.jsxs)(`article`,{className:n(`group absolute flex flex-col justify-between rounded-md border border-l-[3px] bg-background/95 p-2`,`shadow-sm transition-all hover:-translate-y-px hover:border-border hover:shadow-md hover:bg-background`,i.accent),style:{left:t,top:r,width:g,height:_},title:e.scopeBlurb||e.label,children:[(0,h.jsx)(`div`,{className:`truncate text-xs font-semibold leading-tight text-foreground`,children:e.label}),(e.scopeBlurb||e.id)&&(0,h.jsx)(`div`,{className:`truncate text-[10px] leading-tight text-muted-foreground`,children:e.scopeBlurb||e.id}),o&&(0,h.jsx)(`div`,{className:`min-w-0`,children:(0,h.jsx)(u,{issueRef:o,compact:!0,className:`max-w-full`})}),(0,h.jsxs)(`div`,{className:`flex min-w-0 items-center justify-between gap-1.5`,children:[(0,h.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5`,children:[(0,h.jsx)(`span`,{className:n(`h-1.5 w-1.5 shrink-0 rounded-full`,i.dot)}),(0,h.jsx)(`span`,{className:n(`text-[10px] font-medium`,i.text),children:i.label})]}),(0,h.jsxs)(`div`,{className:`flex min-w-0 items-center gap-1.5`,children:[a&&(0,h.jsx)(`span`,{className:`truncate text-[10px] text-muted-foreground`,children:a}),e.lane&&(0,h.jsx)(`span`,{className:`shrink-0 rounded-sm bg-muted/70 px-1 py-px text-[9px] font-medium uppercase tracking-wide text-muted-foreground`,children:e.lane})]})]})]},e.id)})]})})]})}export{E as t};
|
|
2
|
-
//# sourceMappingURL=PlanGraphPanel-DSts7Rtq.js.map
|