agent-relay-server 0.104.5 → 0.105.1

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.
Files changed (168) hide show
  1. package/docs/openapi.json +141 -1
  2. package/package.json +3 -2
  3. package/public/assets/MessageBubble-CHor4Sxp.js +4 -0
  4. package/public/assets/{MessageBubble-BpiTbbnp.js.map → MessageBubble-CHor4Sxp.js.map} +1 -1
  5. package/public/assets/{PlanGraphPanel-k8Aa98g5.js → PlanGraphPanel-jHfkQBX6.js} +2 -2
  6. package/public/assets/{PlanGraphPanel-k8Aa98g5.js.map → PlanGraphPanel-jHfkQBX6.js.map} +1 -1
  7. package/public/assets/{activity-CxKi5Erb.js → activity-DDXS6LsX.js} +2 -2
  8. package/public/assets/{activity-CxKi5Erb.js.map → activity-DDXS6LsX.js.map} +1 -1
  9. package/public/assets/{agent-profiles-DMZXdN6K.js → agent-profiles-Cn8lCTkg.js} +2 -2
  10. package/public/assets/{agent-profiles-DMZXdN6K.js.map → agent-profiles-Cn8lCTkg.js.map} +1 -1
  11. package/public/assets/agents-DBTdcFFz.js +2 -0
  12. package/public/assets/{agents-BrvpH3gn.js.map → agents-DBTdcFFz.js.map} +1 -1
  13. package/public/assets/{analytics-1fvh-9ok.js → analytics-VximqXQ9.js} +3 -3
  14. package/public/assets/{analytics-1fvh-9ok.js.map → analytics-VximqXQ9.js.map} +1 -1
  15. package/public/assets/{automation-BCgX5WOH.js → automation-L9wq4y5F.js} +2 -2
  16. package/public/assets/{automation-BCgX5WOH.js.map → automation-L9wq4y5F.js.map} +1 -1
  17. package/public/assets/{badge-BLar6FjP.js → badge-D8fABzMs.js} +2 -2
  18. package/public/assets/{badge-BLar6FjP.js.map → badge-D8fABzMs.js.map} +1 -1
  19. package/public/assets/{branch-state-badge-DYA7bU0i.js → branch-state-badge-CcLZ_u86.js} +2 -2
  20. package/public/assets/{branch-state-badge-DYA7bU0i.js.map → branch-state-badge-CcLZ_u86.js.map} +1 -1
  21. package/public/assets/{button-BrIB69qd.js → button-KASZcscA.js} +2 -2
  22. package/public/assets/{button-BrIB69qd.js.map → button-KASZcscA.js.map} +1 -1
  23. package/public/assets/card-Cds0MWME.js +2 -0
  24. package/public/assets/{card-lhnFnBoz.js.map → card-Cds0MWME.js.map} +1 -1
  25. package/public/assets/{channels-CK80oJYG.js → channels-CcSnLzCG.js} +2 -2
  26. package/public/assets/{channels-CK80oJYG.js.map → channels-CcSnLzCG.js.map} +1 -1
  27. package/public/assets/{chat-D_2PEz06.js → chat-BzMj_PO6.js} +2 -2
  28. package/public/assets/{chat-D_2PEz06.js.map → chat-BzMj_PO6.js.map} +1 -1
  29. package/public/assets/{connectors-ChGyht5m.js → connectors-DbPOlQhL.js} +2 -2
  30. package/public/assets/{connectors-ChGyht5m.js.map → connectors-DbPOlQhL.js.map} +1 -1
  31. package/public/assets/copy-button-d9DFNX9v.js +2 -0
  32. package/public/assets/{copy-button-Cd-LbSbg.js.map → copy-button-d9DFNX9v.js.map} +1 -1
  33. package/public/assets/{display-D1xB8NJZ.js → display-BWi8DQCp.js} +2 -2
  34. package/public/assets/display-BWi8DQCp.js.map +1 -0
  35. package/public/assets/{dist-BnbGIUmi.js → dist-BbUJ1Vht.js} +2 -2
  36. package/public/assets/{dist-BnbGIUmi.js.map → dist-BbUJ1Vht.js.map} +1 -1
  37. package/public/assets/{dist-Bp10H3oR.js → dist-BlZvUZZB.js} +2 -2
  38. package/public/assets/{dist-Bp10H3oR.js.map → dist-BlZvUZZB.js.map} +1 -1
  39. package/public/assets/{dist-DDUGmmoi.js → dist-BwwlmyBq.js} +2 -2
  40. package/public/assets/{dist-DDUGmmoi.js.map → dist-BwwlmyBq.js.map} +1 -1
  41. package/public/assets/dist-CBVZk9U8.js +2 -0
  42. package/public/assets/{dist-BEzpMqLy.js.map → dist-CBVZk9U8.js.map} +1 -1
  43. package/public/assets/{dist-B5VvlkhI.js → dist-CgqfdHSt.js} +2 -2
  44. package/public/assets/{dist-B5VvlkhI.js.map → dist-CgqfdHSt.js.map} +1 -1
  45. package/public/assets/dist-DC-TqTz2.js +2 -0
  46. package/public/assets/{dist-30weaXto.js.map → dist-DC-TqTz2.js.map} +1 -1
  47. package/public/assets/{dist-DZ97OosY.js → dist-DOAjFOS4.js} +2 -2
  48. package/public/assets/{dist-DZ97OosY.js.map → dist-DOAjFOS4.js.map} +1 -1
  49. package/public/assets/{dist-BjOBkHHY.js → dist-DTXKbk2K.js} +2 -2
  50. package/public/assets/{dist-BjOBkHHY.js.map → dist-DTXKbk2K.js.map} +1 -1
  51. package/public/assets/dist-DreO5AcZ.js +2 -0
  52. package/public/assets/{dist-Cgy0FmP-.js.map → dist-DreO5AcZ.js.map} +1 -1
  53. package/public/assets/{dist-CQF3Jiqg.js → dist-DybScJmm.js} +2 -2
  54. package/public/assets/{dist-CQF3Jiqg.js.map → dist-DybScJmm.js.map} +1 -1
  55. package/public/assets/{dist-DAl28ejX.js → dist-UhEAFdvZ.js} +2 -2
  56. package/public/assets/{dist-DAl28ejX.js.map → dist-UhEAFdvZ.js.map} +1 -1
  57. package/public/assets/{es2015-B8Z9p8oQ.js → es2015-DUjFyjDp.js} +2 -2
  58. package/public/assets/{es2015-B8Z9p8oQ.js.map → es2015-DUjFyjDp.js.map} +1 -1
  59. package/public/assets/{formatted-body-impl-BJ4WCF5J.js → formatted-body-impl-CFWHLkCY.js} +2 -2
  60. package/public/assets/{formatted-body-impl-BJ4WCF5J.js.map → formatted-body-impl-CFWHLkCY.js.map} +1 -1
  61. package/public/assets/index-BjjzI2LT.css +2 -0
  62. package/public/assets/{index-CN7QZlMb.js → index-aCfZQ7LY.js} +13 -13
  63. package/public/assets/index-aCfZQ7LY.js.map +1 -0
  64. package/public/assets/{input-B_fUHtLD.js → input-CtHfLn1i.js} +2 -2
  65. package/public/assets/{input-B_fUHtLD.js.map → input-CtHfLn1i.js.map} +1 -1
  66. package/public/assets/{insights-BCZRV0hX.js → insights-BuPFE0tf.js} +2 -2
  67. package/public/assets/{insights-BCZRV0hX.js.map → insights-BuPFE0tf.js.map} +1 -1
  68. package/public/assets/{integrations-C7UGs00U.js → integrations-hkSW8CzM.js} +2 -2
  69. package/public/assets/{integrations-C7UGs00U.js.map → integrations-hkSW8CzM.js.map} +1 -1
  70. package/public/assets/{lib-ng6WZYjE.js → lib-l-JkMVR9.js} +2 -2
  71. package/public/assets/{lib-ng6WZYjE.js.map → lib-l-JkMVR9.js.map} +1 -1
  72. package/public/assets/{lucide-react-BYZuAhQs.js → lucide-react-C4eXYCwx.js} +2 -2
  73. package/public/assets/{lucide-react-BYZuAhQs.js.map → lucide-react-C4eXYCwx.js.map} +1 -1
  74. package/public/assets/{maintenance-ChYno3Fm.js → maintenance-wYwJ7w6h.js} +2 -2
  75. package/public/assets/{maintenance-ChYno3Fm.js.map → maintenance-wYwJ7w6h.js.map} +1 -1
  76. package/public/assets/{managed-agents-DjxZQNIR.js → managed-agents-CKaYD93I.js} +4 -4
  77. package/public/assets/{managed-agents-DjxZQNIR.js.map → managed-agents-CKaYD93I.js.map} +1 -1
  78. package/public/assets/{markdown-preview-impl-DFa5HF1H.js → markdown-preview-impl-bf4eDQUM.js} +2 -2
  79. package/public/assets/{markdown-preview-impl-DFa5HF1H.js.map → markdown-preview-impl-bf4eDQUM.js.map} +1 -1
  80. package/public/assets/memory-DIneEza9.js +2 -0
  81. package/public/assets/{memory-CTw6kadT.js.map → memory-DIneEza9.js.map} +1 -1
  82. package/public/assets/{messages-Cjr816D_.js → messages-DP9Vv_wh.js} +2 -2
  83. package/public/assets/{messages-Cjr816D_.js.map → messages-DP9Vv_wh.js.map} +1 -1
  84. package/public/assets/{orchestrators-CdmFKA7K.js → orchestrators-CAnKjxdO.js} +2 -2
  85. package/public/assets/{orchestrators-CdmFKA7K.js.map → orchestrators-CAnKjxdO.js.map} +1 -1
  86. package/public/assets/{overview-DBOnjfpP.js → overview-B98U3C-y.js} +2 -2
  87. package/public/assets/{overview-DBOnjfpP.js.map → overview-B98U3C-y.js.map} +1 -1
  88. package/public/assets/{pairs-BkcdKdF7.js → pairs-DVeeuxhY.js} +2 -2
  89. package/public/assets/{pairs-BkcdKdF7.js.map → pairs-DVeeuxhY.js.map} +1 -1
  90. package/public/assets/{projects-ClKbDQB1.js → projects-vt63bwHN.js} +2 -2
  91. package/public/assets/{projects-ClKbDQB1.js.map → projects-vt63bwHN.js.map} +1 -1
  92. package/public/assets/prompt-settings-Df-0ZMJ5.js +2 -0
  93. package/public/assets/prompt-settings-Df-0ZMJ5.js.map +1 -0
  94. package/public/assets/{react-dom-Dbhs84ug.js → react-dom-BMF4hNzG.js} +2 -2
  95. package/public/assets/{react-dom-Dbhs84ug.js.map → react-dom-BMF4hNzG.js.map} +1 -1
  96. package/public/assets/{registry-Bsf3RtOO.js → registry-DlLZyW7_.js} +2 -2
  97. package/public/assets/{registry-Bsf3RtOO.js.map → registry-DlLZyW7_.js.map} +1 -1
  98. package/public/assets/{security-Iyu5bhJw.js → security-Bo4Ty3lz.js} +2 -2
  99. package/public/assets/{security-Iyu5bhJw.js.map → security-Bo4Ty3lz.js.map} +1 -1
  100. package/public/assets/{select-Bi6tNJDx.js → select-BguZ80M8.js} +2 -2
  101. package/public/assets/{select-Bi6tNJDx.js.map → select-BguZ80M8.js.map} +1 -1
  102. package/public/assets/settings-CpX9Xw2j.js +6 -0
  103. package/public/assets/{settings-CbHp2F9r.js.map → settings-CpX9Xw2j.js.map} +1 -1
  104. package/public/assets/{store-zeyDiSKE.js → store-DUfrGvOE.js} +3 -3
  105. package/public/assets/{store-zeyDiSKE.js.map → store-DUfrGvOE.js.map} +1 -1
  106. package/public/assets/{tasks-CPlf-5Tr.js → tasks-Cg1HXY9l.js} +2 -2
  107. package/public/assets/{tasks-CPlf-5Tr.js.map → tasks-Cg1HXY9l.js.map} +1 -1
  108. package/public/assets/{teams-D2uUNhlY.js → teams-BFcYunxB.js} +2 -2
  109. package/public/assets/{teams-D2uUNhlY.js.map → teams-BFcYunxB.js.map} +1 -1
  110. package/public/assets/{terminal-viewer-impl-uRzbrlXy.js → terminal-viewer-impl-CF2EBa2K.js} +3 -3
  111. package/public/assets/{terminal-viewer-impl-uRzbrlXy.js.map → terminal-viewer-impl-CF2EBa2K.js.map} +1 -1
  112. package/public/assets/types-DorDDvEb.js.map +1 -1
  113. package/public/assets/{use-keyboard-viewport-D8_NYDkh.js → use-keyboard-viewport-RYMALvu1.js} +2 -2
  114. package/public/assets/{use-keyboard-viewport-D8_NYDkh.js.map → use-keyboard-viewport-RYMALvu1.js.map} +1 -1
  115. package/public/assets/user-avatar-D1ffSClz.js +2 -0
  116. package/public/assets/{user-avatar-GFWMuAGK.js.map → user-avatar-D1ffSClz.js.map} +1 -1
  117. package/public/assets/{work-queue-B30SNmuq.js → work-queue-DV36cxjp.js} +2 -2
  118. package/public/assets/{work-queue-B30SNmuq.js.map → work-queue-DV36cxjp.js.map} +1 -1
  119. package/public/assets/workspaces-CIsQqQby.js +3 -0
  120. package/public/assets/workspaces-CIsQqQby.js.map +1 -0
  121. package/public/index.html +22 -22
  122. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  123. package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +114 -23
  124. package/runner/plugins/claude/monitors/relay-monitor.ts +2 -2
  125. package/runner/src/adapter.ts +4 -1
  126. package/src/agent-lifecycle-events.ts +21 -5
  127. package/src/automations/reconcile.ts +4 -1
  128. package/src/branch-landed.ts +22 -4
  129. package/src/config-store.ts +17 -21
  130. package/src/context-advisory.ts +10 -3
  131. package/src/db/index.ts +1 -0
  132. package/src/db/projects.ts +29 -0
  133. package/src/db/prompt-templates-schema.ts +20 -0
  134. package/src/db/prompt-templates.ts +86 -0
  135. package/src/db/schema.ts +5 -4
  136. package/src/db/tasks.ts +2 -1
  137. package/src/db/workspaces.ts +41 -1
  138. package/src/index.ts +3 -0
  139. package/src/project-instructions.ts +7 -14
  140. package/src/prompt-resolver.ts +530 -0
  141. package/src/routes/index.ts +5 -0
  142. package/src/routes/prompt-templates.ts +60 -0
  143. package/src/routes/workspaces.ts +4 -3
  144. package/src/routing-policy-push.ts +4 -1
  145. package/src/security.ts +3 -0
  146. package/src/self-resume.ts +8 -15
  147. package/src/services/prompt-templates.ts +19 -0
  148. package/src/services/register-agent.ts +2 -0
  149. package/src/services/spawn-issue-activity.ts +107 -0
  150. package/src/spawn-targets.ts +3 -11
  151. package/src/steward.ts +5 -23
  152. package/src/workspace-auto-merge.ts +19 -2
  153. package/src/workspace-phase.ts +15 -28
  154. package/public/assets/MessageBubble-BpiTbbnp.js +0 -4
  155. package/public/assets/agents-BrvpH3gn.js +0 -2
  156. package/public/assets/card-lhnFnBoz.js +0 -2
  157. package/public/assets/copy-button-Cd-LbSbg.js +0 -2
  158. package/public/assets/display-D1xB8NJZ.js.map +0 -1
  159. package/public/assets/dist-30weaXto.js +0 -2
  160. package/public/assets/dist-BEzpMqLy.js +0 -2
  161. package/public/assets/dist-Cgy0FmP-.js +0 -2
  162. package/public/assets/index-BMO_Sblt.css +0 -2
  163. package/public/assets/index-CN7QZlMb.js.map +0 -1
  164. package/public/assets/memory-CTw6kadT.js +0 -2
  165. package/public/assets/settings-CbHp2F9r.js +0 -6
  166. package/public/assets/user-avatar-GFWMuAGK.js +0 -2
  167. package/public/assets/workspaces-CSpmgbPT.js +0 -3
  168. package/public/assets/workspaces-CSpmgbPT.js.map +0 -1
@@ -2,7 +2,7 @@
2
2
  import { RELAY_TOKEN_HEADER, isRecord } from "agent-relay-sdk";
3
3
  import { TERMINAL_WORKSPACE_STATUSES, describeWorkspacePhase, landReceipt } from "../workspace-phase";
4
4
  import { VALID_WORKSPACE_STATUSES, cleanMeta, cleanString, optionalEnum } from "../validation";
5
- import { ValidationError, deleteWorkspace, getAgent, getWorkspace, listMergeLeases, listOrchestrators, listRepoStewards, listWorkspaces, updateWorkspaceStatus } from "../db";
5
+ import { ValidationError, deleteWorkspace, getAgent, getWorkspace, listMergeLeases, listOrchestrators, listRepoStewards, listWorkspaces, updateWorkspaceStatus, withResolvedWorkspaceProjects } from "../db";
6
6
  import { WORKSPACE_ACTIONS, applyWorkspaceAction, buildWorkspaceCleanupCommand, waitForWorkspaceStatus } from "../workspace-actions";
7
7
  import { auditEvent, authAuditMetadata, authorizeRoute, emitCommand, error, json, parseBody, type Handler } from "./_shared";
8
8
  import { collectWorkspaceOrphans } from "../workspace-orphans";
@@ -21,8 +21,9 @@ export const getWorkspaces: Handler = (req) => {
21
21
  const url = new URL(req.url);
22
22
  const repoRoot = cleanString(url.searchParams.get("repoRoot") ?? undefined, "repoRoot", { max: 1000 });
23
23
  const ownerAgentId = cleanString(url.searchParams.get("agentId") ?? undefined, "agentId", { max: 240 });
24
+ const projectId = cleanString(url.searchParams.get("projectId") ?? undefined, "projectId", { max: 120 });
24
25
  const status = optionalEnum(url.searchParams.get("status") ?? undefined, "status", VALID_WORKSPACE_STATUSES) as WorkspaceStatus | undefined;
25
- return json(listWorkspaces({ repoRoot, ownerAgentId, status }).map(withOwnerOnline));
26
+ return json(withResolvedWorkspaceProjects(listWorkspaces({ repoRoot, ownerAgentId, status }), { projectId }).map(withOwnerOnline));
26
27
  } catch (e) {
27
28
  if (e instanceof ValidationError) return error(e.message, 400);
28
29
  throw e;
@@ -32,7 +33,7 @@ export const getWorkspaces: Handler = (req) => {
32
33
  export const getWorkspaceById: Handler = (_req, params) => {
33
34
  const workspace = getWorkspace(params.id!);
34
35
  if (!workspace) return error("workspace not found", 404);
35
- return json(withOwnerOnline(workspace));
36
+ return json(withOwnerOnline(withResolvedWorkspaceProjects([workspace])[0]!));
36
37
  };
37
38
 
38
39
  export const getWorkspaceStewards: Handler = () => json({ stewards: listRepoStewards(), mergeLeases: listMergeLeases() });
@@ -14,6 +14,7 @@
14
14
  import { getDb } from "./db";
15
15
  import { emitRelayEvent } from "./events";
16
16
  import { routeNotification } from "./notification-router";
17
+ import { renderTemplate } from "./prompt-resolver";
17
18
  import { parseJson } from "./utils";
18
19
  import { isRecord } from "agent-relay-sdk";
19
20
  import type { RoutingPolicy } from "agent-relay-sdk";
@@ -43,7 +44,9 @@ export function notifyRoutingPolicyChanged(policy: RoutingPolicy, opts: { update
43
44
  ttlMs: PUSH_TTL_MS,
44
45
  message: {
45
46
  subject: "Routing policy updated",
46
- body: `🗺 Routing policy updated${opts.updatedBy ? ` by ${opts.updatedBy}` : ""}. Ingest this delta now — spawn routing decisions take effect immediately without respawn. Re-read relay_spawn_targets for live provider/model options.`,
47
+ body: renderTemplate("notify.routing.policy-changed", {
48
+ updatedBy: opts.updatedBy ? ` by ${opts.updatedBy}` : "",
49
+ }),
47
50
  payload: { kind: "routing.policy.changed", policy: policy as unknown as Record<string, unknown>, updatedBy: opts.updatedBy ?? null },
48
51
  replyExpected: false,
49
52
  },
package/src/security.ts CHANGED
@@ -202,6 +202,7 @@ export function requiredScopeFor(method: string, pathname: string): string | nul
202
202
  if (pathname === "/api/provider-quotas") return method === "GET" ? "agent:read" : "quota:write";
203
203
  if (pathname === "/api/routing-policy") return method === "GET" ? "agent:read" : "settings:write:routing";
204
204
  if (pathname === "/api/teams/config") return method === "GET" ? "teams:read" : "settings:write:teams";
205
+ if (pathname === "/api/settings/prompts" || pathname.startsWith("/api/settings/prompts/")) return method === "GET" ? "agent:read" : "system:admin";
205
206
  if (pathname.startsWith("/api/teams")) return method === "GET" ? "teams:read" : "teams:write";
206
207
  if (pathname.startsWith("/api/blackboard")) return method === "GET" ? "blackboard:read" : "blackboard:write";
207
208
  if (pathname.startsWith("/api/issue-associations")) return method === "GET" ? "issue:read" : "issue:write";
@@ -297,6 +298,7 @@ export function requiredComponentScopeFor(method: string, pathname: string): str
297
298
  return method === "GET" ? "agent:read" : "settings:write:routing";
298
299
  }
299
300
  if (pathname === "/api/teams/config") return method === "GET" ? "teams:read" : "settings:write:teams";
301
+ if (pathname === "/api/settings/prompts" || pathname.startsWith("/api/settings/prompts/")) return method === "GET" ? "agent:read" : "system:admin";
300
302
  if (pathname.startsWith("/api/messages") || pathname.startsWith("/api/inbox")) return method === "GET" ? "message:read" : "message:send";
301
303
  if (pathname.startsWith("/api/agent-profiles")) return method === "GET" ? "agent:read" : "agent:write";
302
304
  if (pathname.startsWith("/api/provisioning")) return method === "GET" ? "provisioning:read" : "provisioning:write";
@@ -326,6 +328,7 @@ const CONFIG_SETTINGS_NAMESPACES = new Set(["steward", "insights", "notification
326
328
 
327
329
  function requiredSettingsScopeFor(method: string, pathname: string): string | null | undefined {
328
330
  if (pathname === "/api/settings") return method === "GET" ? "settings:read" : null;
331
+ if (pathname === "/api/settings/prompts" || pathname.startsWith("/api/settings/prompts/")) return undefined;
329
332
  const settingsMatch = pathname.match(/^\/api\/settings\/([^/]+)(?:\/[^/]+)?$/);
330
333
  if (settingsMatch) return settingsScope(method, decodeURIComponent(settingsMatch[1]!));
331
334
  if (pathname === "/api/steward-config") return settingsScope(method, "steward");
@@ -13,6 +13,7 @@ import {
13
13
  } from "./db";
14
14
  import { emitRelayEvent } from "./events";
15
15
  import { routeNotification } from "./notification-router";
16
+ import { renderTemplate } from "./prompt-resolver";
16
17
  import type { AgentCard, Command, ContinuationEnvelope, ContinuationLedgerEntry, SelfResumeMode } from "./types";
17
18
 
18
19
  interface CompactAndResumeInput {
@@ -149,21 +150,13 @@ function renderContinuation(envelope: ContinuationEnvelope): string {
149
150
  const ledger = envelope.ledger.length
150
151
  ? envelope.ledger.map((entry) => `- gen ${entry.gen} @ ${new Date(entry.at).toISOString()}: ${entry.ruledOut}${entry.why ? `; why: ${entry.why}` : ""}`).join("\n")
151
152
  : "- none";
152
- return [
153
- `You have been resumed by Agent Relay — generation ${envelope.generation}.`,
154
- "",
155
- "Objective (verbatim, relay-owned):",
156
- envelope.objective,
157
- "",
158
- "Ruled-out ledger (append-only):",
159
- ledger,
160
- "",
161
- "Working state:",
162
- envelope.workingState,
163
- "",
164
- "Archive refs:",
165
- envelope.archiveRefs.length ? envelope.archiveRefs.join("\n") : "- none",
166
- ].join("\n");
153
+ return renderTemplate("continuation.envelope", {
154
+ generation: String(envelope.generation),
155
+ objective: envelope.objective,
156
+ ruledOut: ledger,
157
+ workingState: envelope.workingState,
158
+ archiveRefs: envelope.archiveRefs.length ? envelope.archiveRefs.join("\n") : "- none",
159
+ });
167
160
  }
168
161
 
169
162
  function assertResumeSupported(agent: AgentCard, mode: SelfResumeMode): void {
@@ -0,0 +1,19 @@
1
+ import { getTemplate, listTemplates, resetTemplate, upsertTemplate, type PromptTemplateRecord } from "../db";
2
+
3
+ export function listPromptTemplates(category?: string): PromptTemplateRecord[] {
4
+ return listTemplates(category);
5
+ }
6
+
7
+ export function getPromptTemplate(slug: string): PromptTemplateRecord | null {
8
+ return getTemplate(slug);
9
+ }
10
+
11
+ export function updatePromptTemplate(slug: string, template: string): PromptTemplateRecord | null {
12
+ upsertTemplate(slug, template);
13
+ return getTemplate(slug);
14
+ }
15
+
16
+ export function resetPromptTemplate(slug: string): PromptTemplateRecord | null {
17
+ resetTemplate(slug);
18
+ return getTemplate(slug);
19
+ }
@@ -18,6 +18,7 @@ import { notifyAgentReady } from "../agent-lifecycle-events";
18
18
  import { resolveSpawnLineage, resolveTeamLineage } from "../security";
19
19
  import { flushQueuedDirectMessages, markManagedAgentRunning } from "./managed-running";
20
20
  import { isAgentUnavailable } from "../db/agent-predicates";
21
+ import { recordSpawnPromptIssueActivity } from "./spawn-issue-activity";
21
22
  import type { AuthContext } from "./auth-context";
22
23
  import type { AgentCard, RegisterAgentInput } from "../types";
23
24
 
@@ -86,6 +87,7 @@ export function registerAgent(input: RegisterAgentInput, ctx: AuthContext): Agen
86
87
  const promptMirror = seedSpawnPromptMirror(agent.id, spawnRequestId);
87
88
  if (promptMirror?.created || promptMirror?.updated) emitNewMessage(promptMirror.message);
88
89
  seedSpawnReplyObligation(agent.id, agent.spawnedBy, spawnRequestId);
90
+ recordSpawnPromptIssueActivity(agent, spawnRequestId);
89
91
  createActivityEvent({
90
92
  clientId: `server-agent-${agent.id}-registered`,
91
93
  kind: "state",
@@ -0,0 +1,107 @@
1
+ import { isRecord } from "agent-relay-sdk";
2
+ import { getDb, resolveProjectForCwd } from "../db";
3
+ import { resolveIssueRefFromString } from "../db/issue-refs";
4
+ import { defaultIssueRepo } from "../config";
5
+ import { parseJson } from "../utils";
6
+ import { recordAndEmitIssueActivity } from "./issue-activity";
7
+ import type { AgentCard, WorkspaceRecord } from "../types";
8
+
9
+ const BARE_ISSUE_REF_RE = /#([0-9]+)/g;
10
+
11
+ /**
12
+ * Parse spawn prompt for bare #NNN refs and record "edit" activity for the
13
+ * newly registered agent. Called once on first registration. Silently ignores
14
+ * prompts with no refs or refs that can't be resolved (no issueRepo configured).
15
+ * Uses a stable clientId so repeated registration never double-records.
16
+ */
17
+ export function recordSpawnPromptIssueActivity(agent: AgentCard, spawnRequestId: string | undefined): void {
18
+ if (!spawnRequestId) return;
19
+ try {
20
+ const row = getDb().query(`
21
+ SELECT params FROM commands
22
+ WHERE type = 'agent.spawn' AND correlation_id = ?
23
+ ORDER BY created_at DESC
24
+ LIMIT 1
25
+ `).get(spawnRequestId) as { params: string } | undefined;
26
+ const params = row ? parseJson<unknown>(row.params, {}) : {};
27
+ if (!isRecord(params) || typeof params.prompt !== "string") return;
28
+ const prompt = params.prompt;
29
+ if (!prompt.trim()) return;
30
+
31
+ const cwd = typeof agent.meta?.cwd === "string" ? agent.meta.cwd : undefined;
32
+ const issueRepo = (cwd ? resolveProjectForCwd(cwd)?.issueRepo : undefined) ?? defaultIssueRepo();
33
+
34
+ const seen = new Set<string>();
35
+ for (const match of prompt.matchAll(BARE_ISSUE_REF_RE)) {
36
+ const num = match[1];
37
+ if (!num || seen.has(num)) continue;
38
+ seen.add(num);
39
+ try {
40
+ const issueRef = resolveIssueRefFromString({ ref: `#${num}`, defaultRepo: issueRepo });
41
+ recordAndEmitIssueActivity({
42
+ agentId: agent.id,
43
+ action: "edit",
44
+ issueRefId: issueRef.id,
45
+ clientId: `spawn-issue:${agent.id}:${issueRef.id}`,
46
+ title: "Issue referenced in spawn prompt",
47
+ metadata: { source: "spawn-prompt", spawnRequestId },
48
+ });
49
+ } catch {
50
+ // Unresolvable ref (no issueRepo configured) — skip silently.
51
+ }
52
+ }
53
+ } catch {
54
+ // Must never break registration.
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Inspect a newly created isolated workspace for issue refs from:
60
+ * 1. metadata.issueNumber (set by some spawn flows)
61
+ * 2. branch name (e.g. "agent/build-389-p1-..." → 389)
62
+ * Records "edit" activity for the owning agent. Uses the same stable clientId
63
+ * as recordSpawnPromptIssueActivity so prompt + branch refs for the same issue
64
+ * are deduplicated at the DB layer.
65
+ */
66
+ export function recordWorkspaceIssueActivity(workspace: WorkspaceRecord): void {
67
+ const agentId = workspace.ownerAgentId;
68
+ if (!agentId || workspace.mode !== "isolated") return;
69
+
70
+ const seen = new Set<string>();
71
+
72
+ const issueNumber = workspace.metadata?.issueNumber;
73
+ if (typeof issueNumber === "number") {
74
+ seen.add(String(Math.trunc(issueNumber)));
75
+ } else if (typeof issueNumber === "string") {
76
+ const t = issueNumber.trim();
77
+ if (/^[0-9]+$/.test(t)) seen.add(t);
78
+ }
79
+
80
+ if (workspace.branch) {
81
+ // Match the first 3+-digit number surrounded by separators in the branch name
82
+ // (e.g. agent/build-389-p1-foo → "389"). Skip 1–2-digit numbers to avoid
83
+ // partition or sequence suffixes (e.g. issue-activity-auto-01 → skip "01").
84
+ const match = workspace.branch.match(/(?:^|[-/])([0-9]{3,})(?:[-/]|$)/);
85
+ if (match?.[1]) seen.add(match[1]);
86
+ }
87
+
88
+ if (seen.size === 0) return;
89
+
90
+ const issueRepo = resolveProjectForCwd(workspace.repoRoot)?.issueRepo ?? defaultIssueRepo();
91
+
92
+ for (const num of seen) {
93
+ try {
94
+ const issueRef = resolveIssueRefFromString({ ref: `#${num}`, defaultRepo: issueRepo });
95
+ recordAndEmitIssueActivity({
96
+ agentId,
97
+ action: "edit",
98
+ issueRefId: issueRef.id,
99
+ clientId: `spawn-issue:${agentId}:${issueRef.id}`,
100
+ title: "Issue referenced in workspace",
101
+ metadata: { source: "workspace", workspaceId: workspace.id, branch: workspace.branch },
102
+ });
103
+ } catch {
104
+ // Unresolvable ref — skip silently.
105
+ }
106
+ }
107
+ }
@@ -1,6 +1,7 @@
1
1
  import { countLiveSpawnedAgents, getAgent, getOrchestrator, listOrchestrators, listProviderQuotas, ValidationError } from "./db";
2
2
  import { DEFAULT_SPAWN_PROFILE_NAME, listAgentProfiles } from "./config-store";
3
3
  import { effectiveProviderCatalogList } from "./provider-catalog-store";
4
+ import { renderTemplate } from "./prompt-resolver";
4
5
  import { getRoutingPolicy } from "./routing-policy-store";
5
6
  import { isPathWithinBase } from "./utils";
6
7
  import { McpNotFoundError } from "./mcp-errors";
@@ -436,17 +437,8 @@ function spawnAlternatives(provider?: SpawnProvider): string {
436
437
  // stays lazy — fetched only when the agent actually decides to spawn. Returns "" for non-spawn agents.
437
438
  export function spawnCapablePrimer(input: { canSpawn: boolean; quota?: number }): string {
438
439
  if (!input.canSpawn) return "";
439
- const quotaLabel = typeof input.quota === "number" && input.quota > 0 ? ` (live-children quota: ${input.quota})` : "";
440
- return [
441
- `You can spawn long-living child agents${quotaLabel}. Shut your own down with relay_shutdown_agent.`,
442
- "- BEFORE spawning, call relay_spawn_targets: it returns the LIVE matrix of hosts × providers × models × per-model effort, advisory quota burn/penalty metadata, your remaining quota, and named profiles. Don't guess — that tool is the discovery path.",
443
- "- Default to your OWN host. Only set orchestratorId to spawn onto another host when it runs a provider/model yours doesn't, or the work must run there.",
444
- `- Prefer a named profile (profile: "<name>") over hand-assembling provider+model+effort+approvalMode. Omitting profile applies ${DEFAULT_SPAWN_PROFILE_NAME}; omitting model/effort uses the provider default. Lean to the cheapest provider/model/effort that fits; escalate only for complex work.`,
445
- "- Set spawnRequestId for idempotency so a retried spawn doesn't double-create.",
446
- "- After spawning, use relay_my_agents for your self-scoped child roster + quota and copy a returned spawnRequestId into relay_shutdown_agent when you need to reap.",
447
- "- Spawn is fire-and-forget: pass waitForRegistrationMs:0 and keep working — you'll be PUSHED agent.ready when the child is genuinely ready (past onboarding), or agent.spawn_failed / agent.exited otherwise. Don't block-poll.",
448
- "- Spawned children cannot themselves spawn (no grandchildren).",
449
- ].join("\n");
440
+ const quota = typeof input.quota === "number" && input.quota > 0 ? ` (live-children quota: ${input.quota})` : "";
441
+ return renderTemplate("spawn.primer", { quota, defaultProfile: DEFAULT_SPAWN_PROFILE_NAME });
450
442
  }
451
443
 
452
444
  // === Orchestrator selection ===
package/src/steward.ts CHANGED
@@ -4,6 +4,7 @@ import { stewardFallbackTarget } from "./config";
4
4
  import { getSpawnPolicy, getStewardConfig, setConfig } from "./config-store";
5
5
  import { listOrchestrators } from "./db";
6
6
  import { getLifecycleManager } from "./lifecycle-manager";
7
+ import { renderTemplate } from "./prompt-resolver";
7
8
  import type { Orchestrator, SpawnPolicy, StewardConfig } from "./types";
8
9
  import { isPathWithinBase } from "./utils";
9
10
 
@@ -25,29 +26,10 @@ export function buildStewardPrompt(repoRoot: string): string {
25
26
  // wake/task message via #640), not a static `system` dead-end. The fallback target below is
26
27
  // used ONLY when a wake message names no coordinator.
27
28
  const fallback = stewardFallbackTarget();
28
- const fallbackTarget = fallback ? `\`${fallback}\`` : "the human operator who configured this relay";
29
- return [
30
- `You are the autonomous repository steward for ${repoRoot}.`,
31
- "",
32
- "Multiple agents work this repo in isolated git worktrees. The relay auto-merges any branch that rebases cleanly — including ones whose base moved on; it hands YOU only what it can't land deterministically: real merge conflicts, or an unknown/ambiguous merge state. Your job is to land that work with no human in the loop whenever you safely can.",
33
- "",
34
- "Each workspace belongs to a BRANCH AGENT (the owner who did the work) who in turn has a COORDINATOR (the agent that spawned it and is responsible for the merge landing). Your wake/task message names both — the `ownerAgentId` and the `coordinatorAgentId` — and `agent-relay steward inspect <id>` shows them. When you can't land work yourself, the coordinator is who you escalate to.",
35
- "",
36
- "Use the `agent-relay` CLI for EVERY relay interaction — it wraps the relay API and is the supported toolkit, and it already attaches your session token with the right scopes. Do NOT hand-curl the HTTP API (`/api/workspaces`, …): the CLI exists so you never have to. If you ever truly must call the API directly, authenticate with the `X-Agent-Relay-Token: <your session token>` header — NOT `Authorization: Bearer $AGENT_RELAY_TOKEN`; the admin env token is not present in your environment, so Bearer will 401.",
37
- "Handle ONE workspace at a time — the relay's per-repo merge lease serializes you with any other merger.",
38
- "",
39
- "1. See the queue: `agent-relay steward queue` (workspaces in conflict / review_requested / merge_planned for this repo). The wake message(s) also name a `workspaceId`.",
40
- "2. CLAIM it FIRST: `agent-relay workspace claim --id <id> --purpose steward`. This stops the deterministic auto-merge from racing you while you validate. The claim auto-expires, so a crash never blocks the repo.",
41
- "3. Understand it: `agent-relay steward inspect <id>` — a diagnostics briefing (the branch agent owner + its coordinator, owner liveness, live git state, ahead/behind, recorded-vs-live branch mismatch, and a recommended action). `agent-relay steward checks <id>` suggests check commands from the changed files.",
42
- "4. `cd` into the workspace's `worktreePath` and rebase the branch onto its `baseRef` (`git rebase <baseRef>`). Resolve conflicts faithfully — preserve the intent of EVERY side; never silently drop a change. If a conflict needs product judgment you can't make confidently, stop and escalate to the coordinator.",
43
- "5. Run the repo's checks/tests (the suggested ones, plus the project's documented commands). Fix trivial breakage you caused while rebasing; do not paper over real failures.",
44
- "6. If green, land it: `agent-relay workspace land --id <id> --strategy rebase-ff`. The relay rebases onto the latest base, fast-forwards, and pushes to origin under the lease. The land consumes your claim.",
45
- "7. If you must stop without landing, RELEASE the claim so automation can resume: `agent-relay workspace release --id <id>`, then send a clear, specific summary to the workspace's COORDINATOR (the `coordinatorAgentId` from the wake message) — they own the work and can act on it. Reply to the wake message or message that agent id directly.",
46
- "",
47
- `Escalate (do NOT merge) when: checks fail and you can't fix them, the conflict resolution is genuinely ambiguous, or anything looks risky. ALWAYS escalate to the branch agent's coordinator (the \`coordinatorAgentId\` in the wake message). Only if the wake message names NO coordinator, escalate to ${fallbackTarget}. Never force-merge a red branch, never \`git push --force\` to a shared base, never discard committed work.`,
48
- "",
49
- "Be terminal-efficient and decisive. When the queue is empty, you're done — you'll be woken again when there's more.",
50
- ].join("\n");
29
+ return renderTemplate("steward.prompt", {
30
+ repoRoot,
31
+ escalationTarget: fallback ? `\`${fallback}\`` : "the human operator who configured this relay",
32
+ });
51
33
  }
52
34
 
53
35
  function desiredStewardPolicy(repoRoot: string, owner: Orchestrator, config: StewardConfig): SpawnPolicy {
@@ -31,6 +31,7 @@ import { emitCommandEvent } from "./command-events";
31
31
  import { getLandingConfig, getStewardConfig } from "./config-store";
32
32
  import { getLifecycleManager } from "./lifecycle-manager";
33
33
  import { routeNotification } from "./notification-router";
34
+ import { renderTemplate } from "./prompt-resolver";
34
35
  import { isAwaitingReviewerApproval } from "./reviewer-pipeline";
35
36
  import { ensureRepoSteward } from "./steward";
36
37
  import { requestWorkspaceMerge } from "./workspace-merge";
@@ -115,7 +116,17 @@ export function wakeRepoSteward(ws: WorkspaceRecord, reason: string): string | n
115
116
  recipients: [`policy:${policyName}`],
116
117
  message: {
117
118
  subject: `Steward: ${ws.status} workspace needs attention`,
118
- body: `Workspace \`${ws.branch ?? ws.id}\` (id ${ws.id}) in ${ws.repoRoot} is ${ws.status} and could not auto-land (${reason}).${ownerLine} Claim it first so auto-merge yields: \`agent-relay workspace claim --id ${ws.id} --purpose steward\`. Inspect: \`agent-relay steward inspect ${ws.id}\`. Then cd into ${ws.worktreePath}, rebase onto ${ws.baseRef ?? "base"}, resolve, run checks, and land: \`agent-relay workspace land --id ${ws.id} --strategy rebase-ff\` — or \`agent-relay workspace release --id ${ws.id}\` and escalate if you can't.${coordinatorLine}`,
119
+ body: renderTemplate("steward.wake", {
120
+ branch: ws.branch ?? ws.id,
121
+ wsId: ws.id,
122
+ repoRoot: ws.repoRoot,
123
+ status: ws.status,
124
+ reason,
125
+ ownerLine,
126
+ worktreePath: ws.worktreePath ?? ws.sourceCwd,
127
+ baseRef: ws.baseRef ?? "base",
128
+ coordinatorLine,
129
+ }),
119
130
  payload: { kind: "workspace.steward-task", workspaceId: ws.id, repoRoot: ws.repoRoot, worktreePath: ws.worktreePath, branch: ws.branch, baseRef: ws.baseRef, status: ws.status, reason, ownerAgentId, coordinatorAgentId },
120
131
  },
121
132
  });
@@ -202,7 +213,13 @@ function escalateNoProgressMerge(ws: WorkspaceRecord): void {
202
213
  recipients,
203
214
  message: {
204
215
  subject: "Workspace can't auto-land — needs attention",
205
- body: `Workspace \`${ws.branch ?? ws.id}\` in ${ws.repoRoot} failed to land ${MAX_NO_PROGRESS_MERGE_ATTEMPTS}× without progress (${mergeError}). Auto-merge has backed off to stop a merge-command loop. Sync \`${ws.baseRef ?? "base"}\` and land manually, or release the workspace.`,
216
+ body: renderTemplate("steward.merge-stall", {
217
+ branch: `\`${ws.branch ?? ws.id}\``,
218
+ repoRoot: ws.repoRoot,
219
+ attempts: String(MAX_NO_PROGRESS_MERGE_ATTEMPTS),
220
+ mergeError,
221
+ baseRef: ws.baseRef ?? "base",
222
+ }),
206
223
  payload: { kind: "workspace.auto-merge-stuck", workspaceId: ws.id, repoRoot: ws.repoRoot, branch: ws.branch, baseRef: ws.baseRef, attempts: MAX_NO_PROGRESS_MERGE_ATTEMPTS, reason: mergeError },
207
224
  },
208
225
  });
@@ -15,6 +15,7 @@
15
15
  // anti-panic signal.
16
16
 
17
17
  import { TERMINAL_WORKSPACE_STATUS_VALUES } from "agent-relay-sdk";
18
+ import { renderTemplate } from "./prompt-resolver";
18
19
  import type { BranchState, WorkspaceRecord, WorkspaceStatus } from "./types";
19
20
  import { workspaceActiveClaim } from "./workspace-claim";
20
21
 
@@ -148,8 +149,8 @@ export function describeWorkspacePhase(
148
149
  case "active":
149
150
  return {
150
151
  phase: "working",
151
- headline: "Your isolated branch — work in progress.",
152
- hint: "Commit your work in this worktree, then mark it ready. Relay rebases onto the latest base, lands, and pushes for you — do NOT push, rebase, or merge yourself, and never touch the main checkout.",
152
+ headline: renderTemplate("workspace.phase.active.headline"),
153
+ hint: renderTemplate("workspace.phase.active.hint"),
153
154
  actionNeeded: true,
154
155
  nextActions: [READY_ACTION],
155
156
  blockers: [],
@@ -192,8 +193,8 @@ export function describeWorkspacePhase(
192
193
  }
193
194
  return {
194
195
  phase: "land-pending",
195
- headline: "Handed off — stop this turn and go idle while Relay lands your branch. This is the normal, healthy post-ready state (not an escalation).",
196
- hint: "No action needed. Stop your turn now; do not poll or wait on the steward queue. Relay will wake you with a `landed-success` notification when the merge lands and your branch is refreshed, or `landed-failure` if landing fatally fails. Do NOT merge, push, resolve anything, or touch the main checkout.",
196
+ headline: renderTemplate("workspace.phase.ready.headline"),
197
+ hint: renderTemplate("workspace.phase.ready.hint"),
197
198
  actionNeeded: false,
198
199
  nextActions: [CHECK_STATUS_ACTION],
199
200
  blockers: [],
@@ -202,8 +203,8 @@ export function describeWorkspacePhase(
202
203
  case "merge_planned":
203
204
  return {
204
205
  phase: "landing",
205
- headline: "Merge dispatched — landing your branch on the base now.",
206
- hint: "No action needed. When it completes you'll be moved onto a fresh rebased branch (the name gains a `--N` suffix — expected) to keep working.",
206
+ headline: renderTemplate("workspace.phase.merge-planned.headline"),
207
+ hint: renderTemplate("workspace.phase.merge-planned.hint"),
207
208
  actionNeeded: false,
208
209
  nextActions: [WAIT_ACTION],
209
210
  blockers: [],
@@ -211,8 +212,8 @@ export function describeWorkspacePhase(
211
212
  case "conflict":
212
213
  return {
213
214
  phase: "steward",
214
- headline: "Auto-merge hit a conflict — a steward agent is reconciling it. Resolving it is NOT your job.",
215
- hint: "Do not resolve the conflict, rebase, merge, or push yourself. The steward rebases and lands it, escalating to the human only if it truly can't. You can keep working or wait for it to land.",
215
+ headline: renderTemplate("workspace.phase.conflict.headline"),
216
+ hint: renderTemplate("workspace.phase.conflict.hint"),
216
217
  actionNeeded: false,
217
218
  nextActions: [WAIT_ACTION],
218
219
  blockers: ["rebase/merge conflict against the base — a steward is handling it"],
@@ -220,8 +221,8 @@ export function describeWorkspacePhase(
220
221
  case "merged":
221
222
  return {
222
223
  phase: "landed",
223
- headline: "✅ Landed — your commits are on the base.",
224
- hint: "A fresh rebased branch is being prepared; you'll continue on it (the branch name gains a `--N` suffix — expected, not an error). Keep working.",
224
+ headline: renderTemplate("workspace.phase.merged.headline"),
225
+ hint: renderTemplate("workspace.phase.merged.hint"),
225
226
  actionNeeded: false,
226
227
  nextActions: [],
227
228
  blockers: [],
@@ -231,8 +232,8 @@ export function describeWorkspacePhase(
231
232
  case "cleaned":
232
233
  return {
233
234
  phase: "closed",
234
- headline: "This workspace is being torn down.",
235
- hint: "No further branch work happens here. If you still have work to do, the host will spawn you into a fresh workspace.",
235
+ headline: renderTemplate("workspace.phase.abandoned.headline"),
236
+ hint: renderTemplate("workspace.phase.abandoned.hint"),
236
237
  actionNeeded: false,
237
238
  nextActions: [],
238
239
  blockers: [],
@@ -306,14 +307,7 @@ export function deriveBranchState(
306
307
  // ready, so the whole "what happens next" is stated up front instead of being
307
308
  // decoded from status enums over the following minutes (#235).
308
309
  export function readyContract(workspace: Pick<WorkspaceRecord, "status">): string {
309
- return [
310
- `Marked ready. Status is now \`${workspace.status}\` — this is the normal, healthy hand-off state, not an escalation.`,
311
- "Relay auto-merges clean rebases roughly every 2 minutes. A steward agent is spawned (after a short delay) ONLY if it can't land deterministically — so no steward appearing means it's working, not stuck.",
312
- "STOP this turn now and go idle. Do not call `relay_workspace_status wait:true`, `agent-relay workspace status --wait`, or any polling loop after marking ready.",
313
- "Relay will wake you with `landed-success` when the merge lands and your branch is refreshed, or `landed-failure` if landing fatally fails.",
314
- "On `landed-success` you'll be on a fresh rebased branch (its name gains a `--N` suffix — expected). Keep working there.",
315
- "Do NOT merge, push, rebase, resolve conflicts, or `cd` into the main checkout — Relay (and the steward) own all of that.",
316
- ].join("\n");
310
+ return renderTemplate("workspace.ready.contract", { status: workspace.status });
317
311
  }
318
312
 
319
313
  // Mode-tailored MCP `initialize` instructions primer (#214 §3). The relay's MCP
@@ -325,14 +319,7 @@ export function readyContract(workspace: Pick<WorkspaceRecord, "status">): strin
325
319
  export function worktreeMcpInstructions(workspace: Pick<WorkspaceRecord, "branch" | "baseRef">): string {
326
320
  const branch = workspace.branch ? `\`${workspace.branch}\`` : "an isolated agent branch";
327
321
  const base = workspace.baseRef ? `\`${workspace.baseRef}\`` : "the base branch";
328
- return [
329
- `You are in an isolated git worktree on branch ${branch}, based on ${base} — NOT the main checkout. ${base} moves under you as other agents land in parallel; that's expected.`,
330
- "Your shell's working directory is already this worktree — run commands directly without prefixing `cd`.",
331
- "Changes reach the base via: commit your work, then call `relay_workspace_ready`. Relay rebases onto the latest base, lands, and pushes for you.",
332
- "Do NOT push, rebase, merge, resolve conflicts, or `cd` into the main checkout — Relay (and a steward, spawned only if a clean auto-merge isn't possible) own all of that.",
333
- "After `ready` the status is `ready` (a normal, healthy hand-off state, not a stall). Stop your turn and go idle; Relay wakes you with `landed-success` when your branch lands and refreshes, or `landed-failure` if landing fatally fails.",
334
- "Call `relay_workspace_status` anytime to see where you are and the exact next step.",
335
- ].join("\n");
322
+ return renderTemplate("workspace.mcp.instructions", { branch, baseRef: base });
336
323
  }
337
324
 
338
325
  // Positive land receipt for the wait-result path: when a long-poll observes the
@@ -1,4 +0,0 @@
1
- import{r as e}from"./chunk-CilyBKbf.js";import{$t as t,An as n,B as r,Cn as i,Dt as a,Fn as o,Hn as s,L as c,Ot as l,Qn as u,Qt as d,Sn as f,Un as p,V as m,Vt as h,Xn as g,_n as _,a as v,b as y,c as ee,dr as b,er as x,ft as S,g as C,hn as te,i as ne,ln as w,lt as T,m as E,on as D,r as re,un as O,vn as k,x as A,xn as ie,yn as j}from"./lucide-react-BYZuAhQs.js";import{r as M,t as N,y as P}from"./store-zeyDiSKE.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-D1xB8NJZ.js";import{D as H,a as pe,i as me,l as he,t as U}from"./index-CN7QZlMb.js";import{t as ge}from"./user-avatar-GFWMuAGK.js";var W=e(b(),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,a=r?n.includes(r):!1,o=n.some(e=>e!==V);if(a||o){let e=a?r:n.find(e=>e!==V);return{label:`read`,title:e?`Read by ${e}`:`Read by agent`,tone:`ok`,icon:i}}if(e.deliveryStatus===`delivered`)return{label:`delivered`,title:`Delivered to agent inbox`,tone:`ok`,icon:i};if(e.deliveryStatus===`queued`)return{label:`queued`,title:`Queued until the target agent is available`,tone:`warn`,icon:D};if(e.deliveryStatus===`failed`||e.deliveryStatus===`dead`){let t=e.deliveryPoisonReason||e.deliveryLastError||e.deliveryStatus;return{label:e.deliveryStatus,title:t,tone:`danger`,icon:_}}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=u(),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)(w,{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":a,"context.warning":E,"agent.context_threshold":E,"agent.resume_budget_exhausted":E,"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):``,o=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)(a,{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}),o&&(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:o,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]??c,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":r,"spawned-child-exited":T,"spawned-child-failed":_,"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]??c,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:n,instructions:h,tools:v,comms:c,knowledge:o,context:t},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]??y;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)(_,{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)(O,{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:r}){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:r,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)(n,{className:`w-3.5 h-3.5 mt-0.5 shrink-0 opacity-70`}),(0,Y.jsx)(U,{text:e.text,issueRepo:r,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)(C,{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)(te,{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)(l,{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)(y,{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:t}){let n=e.kind===`image`,r=e.title||e.artifactId,[i,a]=(0,W.useState)(null),[o,s]=(0,W.useState)(null),[c,l]=(0,W.useState)(!1),[u,f]=(0,W.useState)(!1);(0,W.useEffect)(()=>{let t=!1,n=null;async function r(){l(!0),s(null),a(null);try{let r=await x(`/artifacts/${encodeURIComponent(e.artifactId)}/content`);if(t)return;n=URL.createObjectURL(r),a(n)}catch(e){t||s(e.message)}finally{t||l(!1)}}return r(),()=>{t=!0,n&&URL.revokeObjectURL(n)}},[e.artifactId]);function p(){if(!i)return;let e=document.createElement(`a`);e.href=i,e.download=r,document.body.appendChild(e),e.click(),e.remove()}return n?(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(`button`,{type:`button`,onClick:()=>i&&f(!0),disabled:!i,className:`group/img mt-2 block overflow-hidden rounded-md border border-foreground/10 bg-black/10 text-left disabled:cursor-default relative`,children:i?(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(`img`,{src:i,alt:r,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)(re,{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`,o?`text-red-400`:`text-muted-foreground`),children:[c?(0,Y.jsx)(S,{className:`h-4 w-4 animate-spin`}):(0,Y.jsx)(_,{className:`h-4 w-4`}),o||`Loading image`]})}),i&&(0,Y.jsx)(me,{open:u,onOpenChange:f,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:r}),(0,Y.jsxs)(`div`,{className:`relative flex items-center justify-center min-h-[200px]`,children:[(0,Y.jsx)(`img`,{src:i,alt:r,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:p,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:()=>f(!1),className:`rounded-md bg-black/60 hover:bg-black/80 p-2 text-white transition-colors`,title:`Close`,children:(0,Y.jsx)(ne,{className:`w-4 h-4`})})]})]})]})})]}):(0,Y.jsxs)(`button`,{type:`button`,onClick:p,disabled:!i,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`,t?`border-primary-foreground/20 bg-primary-foreground/10 hover:bg-primary-foreground/15`:`border-border bg-background hover:bg-muted`),children:[c?(0,Y.jsx)(S,{className:`h-4 w-4 shrink-0 animate-spin`}):o?(0,Y.jsx)(_,{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`,o&&`text-red-400`),children:o||r}),(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,c=(o?e.to:e.from)||``,l=i[o?t:c]?.issueRepo??i[t]?.issueRepo,u=!c||c===`broadcast`||c.includes(`:`),d=z(e),f=J(e.occurredAt??e.createdAt),m=o?s: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(c,i)}):(0,Y.jsx)(X,{agentId:c,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),re=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:[re&&(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)(O,{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-BpiTbbnp.js.map