agent-relay-server 0.113.0 → 0.115.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.
Files changed (158) hide show
  1. package/docs/openapi.json +39 -1
  2. package/package.json +3 -3
  3. package/public/assets/MessageBubble-Dy37JuVw.js +4 -0
  4. package/public/assets/{MessageBubble-CFujR6_L.js.map → MessageBubble-Dy37JuVw.js.map} +1 -1
  5. package/public/assets/PlanGraphPanel-C17_n4Ff.js +2 -0
  6. package/public/assets/PlanGraphPanel-C17_n4Ff.js.map +1 -0
  7. package/public/assets/{activity-C7-gIF9O.js → activity-G-s2N4eU.js} +2 -2
  8. package/public/assets/{activity-C7-gIF9O.js.map → activity-G-s2N4eU.js.map} +1 -1
  9. package/public/assets/{agent-profiles-BGPa2-BZ.js → agent-profiles-v4CcpJWT.js} +2 -2
  10. package/public/assets/{agent-profiles-BGPa2-BZ.js.map → agent-profiles-v4CcpJWT.js.map} +1 -1
  11. package/public/assets/{agents-CWCbBuq6.js → agents-CuEoaCLs.js} +2 -2
  12. package/public/assets/{agents-CWCbBuq6.js.map → agents-CuEoaCLs.js.map} +1 -1
  13. package/public/assets/{analytics-BhGpT0JR.js → analytics-Dvg0J33b.js} +3 -3
  14. package/public/assets/{analytics-BhGpT0JR.js.map → analytics-Dvg0J33b.js.map} +1 -1
  15. package/public/assets/{automation-DnpahVqs.js → automation-wXSbBEei.js} +2 -2
  16. package/public/assets/{automation-DnpahVqs.js.map → automation-wXSbBEei.js.map} +1 -1
  17. package/public/assets/{badge-kdQDWO6e.js → badge-BhUZ1cAb.js} +2 -2
  18. package/public/assets/{badge-kdQDWO6e.js.map → badge-BhUZ1cAb.js.map} +1 -1
  19. package/public/assets/{branch-state-badge-CcAq2Igv.js → branch-state-badge-YzkNCHyZ.js} +2 -2
  20. package/public/assets/{branch-state-badge-CcAq2Igv.js.map → branch-state-badge-YzkNCHyZ.js.map} +1 -1
  21. package/public/assets/{button-BKFvNXa3.js → button-C-V4oij1.js} +2 -2
  22. package/public/assets/{button-BKFvNXa3.js.map → button-C-V4oij1.js.map} +1 -1
  23. package/public/assets/card-DAkf5Kzw.js +2 -0
  24. package/public/assets/{card-B0y1i_2D.js.map → card-DAkf5Kzw.js.map} +1 -1
  25. package/public/assets/{channels-DBP3-Gg0.js → channels-Vl9YHoGK.js} +2 -2
  26. package/public/assets/{channels-DBP3-Gg0.js.map → channels-Vl9YHoGK.js.map} +1 -1
  27. package/public/assets/chat-yiXwg4kh.js +2 -0
  28. package/public/assets/{chat-Bue-qNx_.js.map → chat-yiXwg4kh.js.map} +1 -1
  29. package/public/assets/{connectors-BJxbuxoU.js → connectors-C33KsouZ.js} +2 -2
  30. package/public/assets/{connectors-BJxbuxoU.js.map → connectors-C33KsouZ.js.map} +1 -1
  31. package/public/assets/copy-button-BStzXgtd.js +2 -0
  32. package/public/assets/{copy-button-aLaiAkv2.js.map → copy-button-BStzXgtd.js.map} +1 -1
  33. package/public/assets/{dist-EO8jbi2F.js → dist-CBMWGhWc.js} +2 -2
  34. package/public/assets/{dist-EO8jbi2F.js.map → dist-CBMWGhWc.js.map} +1 -1
  35. package/public/assets/{dist-avJPT3qF.js → dist-CDZZxxJq.js} +2 -2
  36. package/public/assets/{dist-avJPT3qF.js.map → dist-CDZZxxJq.js.map} +1 -1
  37. package/public/assets/{dist-DnyQI0qt.js → dist-CQ0Z-TDi.js} +2 -2
  38. package/public/assets/{dist-DnyQI0qt.js.map → dist-CQ0Z-TDi.js.map} +1 -1
  39. package/public/assets/{dist-DQPz52Zx.js → dist-ChDX_t12.js} +2 -2
  40. package/public/assets/{dist-DQPz52Zx.js.map → dist-ChDX_t12.js.map} +1 -1
  41. package/public/assets/{dist-D_qcpfbI.js → dist-CmFeEXMe.js} +2 -2
  42. package/public/assets/{dist-D_qcpfbI.js.map → dist-CmFeEXMe.js.map} +1 -1
  43. package/public/assets/{dist-DKoRwEZq.js → dist-Cs8X0P1d.js} +2 -2
  44. package/public/assets/{dist-DKoRwEZq.js.map → dist-Cs8X0P1d.js.map} +1 -1
  45. package/public/assets/dist-D2jvo5oA.js +2 -0
  46. package/public/assets/{dist-CF28Y5wI.js.map → dist-D2jvo5oA.js.map} +1 -1
  47. package/public/assets/{dist-BDYU37NZ.js → dist-DV83j9tm.js} +2 -2
  48. package/public/assets/{dist-BDYU37NZ.js.map → dist-DV83j9tm.js.map} +1 -1
  49. package/public/assets/{dist-DDh8a_SK.js → dist-DyNJNwpi.js} +2 -2
  50. package/public/assets/{dist-DDh8a_SK.js.map → dist-DyNJNwpi.js.map} +1 -1
  51. package/public/assets/dist-mm7c7nBt.js +2 -0
  52. package/public/assets/{dist-cyag2tir.js.map → dist-mm7c7nBt.js.map} +1 -1
  53. package/public/assets/dist-y03IwOrd.js +2 -0
  54. package/public/assets/{dist-BnfqT2cl.js.map → dist-y03IwOrd.js.map} +1 -1
  55. package/public/assets/{es2015-C9FSEGd7.js → es2015-VnZ2kVIz.js} +2 -2
  56. package/public/assets/{es2015-C9FSEGd7.js.map → es2015-VnZ2kVIz.js.map} +1 -1
  57. package/public/assets/formatted-body-impl-CfnhWZAX.js +3 -0
  58. package/public/assets/formatted-body-impl-CfnhWZAX.js.map +1 -0
  59. package/public/assets/index-4XRZ-n_A.js +23 -0
  60. package/public/assets/index-4XRZ-n_A.js.map +1 -0
  61. package/public/assets/index-DYwuv_Na.css +2 -0
  62. package/public/assets/{input-DfN6sUbX.js → input-CtLT7WXi.js} +2 -2
  63. package/public/assets/{input-DfN6sUbX.js.map → input-CtLT7WXi.js.map} +1 -1
  64. package/public/assets/{insights-CZ_JrJ8M.js → insights-C5Ft13cw.js} +2 -2
  65. package/public/assets/{insights-CZ_JrJ8M.js.map → insights-C5Ft13cw.js.map} +1 -1
  66. package/public/assets/{integrations-L75xhZd5.js → integrations-DR3pboEG.js} +2 -2
  67. package/public/assets/{integrations-L75xhZd5.js.map → integrations-DR3pboEG.js.map} +1 -1
  68. package/public/assets/{lib-DRRHEqRZ.js → lib-BLoevhQO.js} +3 -3
  69. package/public/assets/{lib-DRRHEqRZ.js.map → lib-BLoevhQO.js.map} +1 -1
  70. package/public/assets/lucide-react-Dc3ZwCBi.js +9 -0
  71. package/public/assets/{lucide-react-DmbfpRvJ.js.map → lucide-react-Dc3ZwCBi.js.map} +1 -1
  72. package/public/assets/{maintenance-Dpb87NaB.js → maintenance-Ddl6-McO.js} +2 -2
  73. package/public/assets/{maintenance-Dpb87NaB.js.map → maintenance-Ddl6-McO.js.map} +1 -1
  74. package/public/assets/{managed-agents-DyGbrKwJ.js → managed-agents-pLThsagU.js} +4 -4
  75. package/public/assets/{managed-agents-DyGbrKwJ.js.map → managed-agents-pLThsagU.js.map} +1 -1
  76. package/public/assets/{markdown-preview-impl-Bx4AcI8G.js → markdown-preview-impl-CiENso5E.js} +2 -2
  77. package/public/assets/{markdown-preview-impl-Bx4AcI8G.js.map → markdown-preview-impl-CiENso5E.js.map} +1 -1
  78. package/public/assets/memory-CSzdP2o2.js +2 -0
  79. package/public/assets/{memory-2l6G_m1p.js.map → memory-CSzdP2o2.js.map} +1 -1
  80. package/public/assets/messages-1ton_JT5.js +2 -0
  81. package/public/assets/{messages-DC-QXNwz.js.map → messages-1ton_JT5.js.map} +1 -1
  82. package/public/assets/{orchestrators-D_X3a0dm.js → orchestrators-C2kC07Qm.js} +2 -2
  83. package/public/assets/{orchestrators-D_X3a0dm.js.map → orchestrators-C2kC07Qm.js.map} +1 -1
  84. package/public/assets/overview-CXc2vQRQ.js +2 -0
  85. package/public/assets/{overview-76JPEbGZ.js.map → overview-CXc2vQRQ.js.map} +1 -1
  86. package/public/assets/{pairs-IeLXl-Z8.js → pairs-DLfFKNEf.js} +2 -2
  87. package/public/assets/{pairs-IeLXl-Z8.js.map → pairs-DLfFKNEf.js.map} +1 -1
  88. package/public/assets/{projects-D8ClXDUg.js → projects-TM20JuNI.js} +2 -2
  89. package/public/assets/{projects-D8ClXDUg.js.map → projects-TM20JuNI.js.map} +1 -1
  90. package/public/assets/prompt-settings-DWYbD9TA.js +2 -0
  91. package/public/assets/{prompt-settings-BRduaHOj.js.map → prompt-settings-DWYbD9TA.js.map} +1 -1
  92. package/public/assets/{react-dom-jQ4Vs380.js → react-dom-cLkVFBsS.js} +2 -2
  93. package/public/assets/{react-dom-jQ4Vs380.js.map → react-dom-cLkVFBsS.js.map} +1 -1
  94. package/public/assets/registry-BWRVKBhU.js +2 -0
  95. package/public/assets/{registry-CXyaPToV.js.map → registry-BWRVKBhU.js.map} +1 -1
  96. package/public/assets/{security-8n8VEsf5.js → security-DcNNqoA4.js} +2 -2
  97. package/public/assets/{security-8n8VEsf5.js.map → security-DcNNqoA4.js.map} +1 -1
  98. package/public/assets/{select-D-wcg_2U.js → select-DkpcyiTY.js} +2 -2
  99. package/public/assets/{select-D-wcg_2U.js.map → select-DkpcyiTY.js.map} +1 -1
  100. package/public/assets/settings-C9-w25pF.js +6 -0
  101. package/public/assets/{settings-BhnCGXgo.js.map → settings-C9-w25pF.js.map} +1 -1
  102. package/public/assets/{store-Du8k5mLJ.js → store-BZ2N51To.js} +5 -5
  103. package/public/assets/store-BZ2N51To.js.map +1 -0
  104. package/public/assets/{tasks-DEKQqgPB.js → tasks-DuH_JQJM.js} +2 -2
  105. package/public/assets/{tasks-DEKQqgPB.js.map → tasks-DuH_JQJM.js.map} +1 -1
  106. package/public/assets/{teams-DoRSWZRQ.js → teams-CQZ6a8A5.js} +2 -2
  107. package/public/assets/{teams-DoRSWZRQ.js.map → teams-CQZ6a8A5.js.map} +1 -1
  108. package/public/assets/{terminal-viewer-impl-C_o3BOpu.js → terminal-viewer-impl-B1A49Vs2.js} +3 -3
  109. package/public/assets/{terminal-viewer-impl-C_o3BOpu.js.map → terminal-viewer-impl-B1A49Vs2.js.map} +1 -1
  110. package/public/assets/types-DSwhOFcJ.js.map +1 -1
  111. package/public/assets/{use-keyboard-viewport-Dw2CHZ50.js → use-keyboard-viewport-DucYmqmP.js} +2 -2
  112. package/public/assets/{use-keyboard-viewport-Dw2CHZ50.js.map → use-keyboard-viewport-DucYmqmP.js.map} +1 -1
  113. package/public/assets/user-avatar-C3eL_il0.js +2 -0
  114. package/public/assets/{user-avatar-BQoM4jPT.js.map → user-avatar-C3eL_il0.js.map} +1 -1
  115. package/public/assets/{work-queue-CWnf1_iE.js → work-queue-IfxOcGe5.js} +2 -2
  116. package/public/assets/{work-queue-CWnf1_iE.js.map → work-queue-IfxOcGe5.js.map} +1 -1
  117. package/public/assets/workspaces-gPEVu-L5.js +3 -0
  118. package/public/assets/workspaces-gPEVu-L5.js.map +1 -0
  119. package/public/index.html +21 -21
  120. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  121. package/scripts/orchestrator-spawn-smoke.ts +30 -13
  122. package/src/config-store.ts +15 -3
  123. package/src/db/migrations.ts +2 -2
  124. package/src/db/plans.ts +11 -0
  125. package/src/db/provisioning-registry.ts +39 -15
  126. package/src/db/schema.ts +1 -1
  127. package/src/db/task-entity.ts +2 -0
  128. package/src/mcp/index.ts +1 -1
  129. package/src/mcp-plan-tools.ts +3 -0
  130. package/src/routes/index.ts +2 -1
  131. package/src/routes/plans.ts +12 -2
  132. package/src/routes/tasks.ts +1 -0
  133. package/src/services/plan-graph.ts +8 -1
  134. package/public/assets/MessageBubble-CFujR6_L.js +0 -4
  135. package/public/assets/PlanGraphPanel-BfxvqmNS.js +0 -2
  136. package/public/assets/PlanGraphPanel-BfxvqmNS.js.map +0 -1
  137. package/public/assets/card-B0y1i_2D.js +0 -2
  138. package/public/assets/chat-Bue-qNx_.js +0 -2
  139. package/public/assets/copy-button-aLaiAkv2.js +0 -2
  140. package/public/assets/dist-BnfqT2cl.js +0 -2
  141. package/public/assets/dist-CF28Y5wI.js +0 -2
  142. package/public/assets/dist-cyag2tir.js +0 -2
  143. package/public/assets/formatted-body-impl-CTz6wch8.js +0 -3
  144. package/public/assets/formatted-body-impl-CTz6wch8.js.map +0 -1
  145. package/public/assets/index-BMAblAKQ.js +0 -23
  146. package/public/assets/index-BMAblAKQ.js.map +0 -1
  147. package/public/assets/index-D-Ntiy3M.css +0 -2
  148. package/public/assets/lucide-react-DmbfpRvJ.js +0 -9
  149. package/public/assets/memory-2l6G_m1p.js +0 -2
  150. package/public/assets/messages-DC-QXNwz.js +0 -2
  151. package/public/assets/overview-76JPEbGZ.js +0 -2
  152. package/public/assets/prompt-settings-BRduaHOj.js +0 -2
  153. package/public/assets/registry-CXyaPToV.js +0 -2
  154. package/public/assets/settings-BhnCGXgo.js +0 -6
  155. package/public/assets/store-Du8k5mLJ.js.map +0 -1
  156. package/public/assets/user-avatar-BQoM4jPT.js +0 -2
  157. package/public/assets/workspaces-C_fFCoCu.js +0 -3
  158. package/public/assets/workspaces-C_fFCoCu.js.map +0 -1
@@ -444,11 +444,11 @@ export function applyMigrations(): void {
444
444
  created_by TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL
445
445
  )
446
446
  `);
447
- const planCols = getDb().query("PRAGMA table_info(plans)").all() as any[];
448
- const planColNames = planCols.map((c: any) => c.name);
447
+ const planColNames = (getDb().query("PRAGMA table_info(plans)").all() as any[]).map((c: any) => c.name);
449
448
  if (!planColNames.includes("team_id")) {
450
449
  getDb().run("ALTER TABLE plans ADD COLUMN team_id TEXT");
451
450
  }
451
+ if (!planColNames.includes("archived")) getDb().run("ALTER TABLE plans ADD COLUMN archived INTEGER NOT NULL DEFAULT 0");
452
452
  getDb().run("CREATE UNIQUE INDEX IF NOT EXISTS idx_plans_thread_channel ON plans(thread_id, coalesce(channel, ''))");
453
453
  getDb().run("CREATE INDEX IF NOT EXISTS idx_plans_updated ON plans(updated_at)");
454
454
  getDb().run("CREATE INDEX IF NOT EXISTS idx_plans_team ON plans(team_id)");
package/src/db/plans.ts CHANGED
@@ -8,6 +8,7 @@ interface PlanRow {
8
8
  thread_id: number;
9
9
  team_id: string | null;
10
10
  channel: string | null;
11
+ archived: number;
11
12
  version: number;
12
13
  title: string | null;
13
14
  objective: string | null;
@@ -52,6 +53,7 @@ function rowToPlan(row: PlanRow): Plan {
52
53
  threadId: String(row.thread_id),
53
54
  ...(row.team_id ? { teamId: row.team_id } : {}),
54
55
  ...(row.channel ? { channel: row.channel } : {}),
56
+ archived: Boolean(row.archived),
55
57
  version: row.version,
56
58
  ...(row.title ? { title: row.title } : {}),
57
59
  ...(row.objective ? { objective: row.objective } : {}),
@@ -189,6 +191,15 @@ export function replacePlan(input: Plan, changedBy?: string): Plan {
189
191
  return getPlan(input.id)!;
190
192
  }
191
193
 
194
+ export function setPlanArchived(id: string, archived: boolean): Plan {
195
+ const existing = getPlan(id);
196
+ if (!existing) throw new ValidationError(`plan ${id} not found`);
197
+ if (existing.archived === archived) return existing;
198
+ const now = Date.now();
199
+ getDb().query("UPDATE plans SET archived = ?, updated_at = ? WHERE id = ?").run(archived ? 1 : 0, now, id);
200
+ return getPlan(id)!;
201
+ }
202
+
192
203
  export function deletePlan(id: string, changedBy?: string): boolean {
193
204
  const existing = getPlan(id);
194
205
  if (!existing) return false;
@@ -41,6 +41,9 @@ const BUNDLED_SOURCE_TYPE = "bundled";
41
41
  const HOST_CALLMUX_SOURCE_TYPE = "host-callmux";
42
42
  export const SHARED_CALLMUX_SEED_SERVER_NAMES = ["tokenlean", "github", "vent", "reasoning", "scribe", "searxng", "qmd"] as const;
43
43
  export const SHARED_CALLMUX_SOURCE_CONFIG_ENV = "AGENT_RELAY_SHARED_CALLMUX_SOURCE_CONFIG";
44
+ // Servers seeded from the host callmux config but NOT eligible for the shared listener (deno not provisioned, etc.).
45
+ const SHARED_CALLMUX_SEED_NON_LISTENER_NAMES: ReadonlySet<string> = new Set(["scribe"]);
46
+ const SHARED_CALLMUX_CONFIG_ENV_ALLOWLIST: Readonly<Record<string, readonly string[]>> = { vent: ["VENT_REPO"] };
44
47
 
45
48
  type ProviderBundledSkillSetDescriptor = NonNullable<NonNullable<ProviderManifest["provisioning"]>["bundledSkills"]>;
46
49
 
@@ -224,9 +227,9 @@ function assertDefinition(kind: ProvisioningAssetKind, definition: ResolvedAsset
224
227
  if (kind === "mcp") {
225
228
  const def = definition as McpAssetDefinition;
226
229
  if (!isRecord(def.server)) throw new ValidationError("mcp definition requires a server object");
227
- assertMcpSecretPlaceholders(def.server);
230
+ assertMcpSecretPlaceholders(def.server, def.name);
228
231
  const metadata = isRecord(def.metadata) ? def.metadata : {};
229
- if (isRecord(metadata.callmuxServer)) assertMcpSecretPlaceholders(metadata.callmuxServer as ProvisioningMcpServer);
232
+ if (isRecord(metadata.callmuxServer)) assertMcpSecretPlaceholders(metadata.callmuxServer as ProvisioningMcpServer, def.name);
230
233
  }
231
234
  if ((kind === "skill" || kind === "plugin")) {
232
235
  const def = definition as SkillAssetDefinition | PluginAssetDefinition;
@@ -379,11 +382,19 @@ function isEnvPlaceholder(value: string): boolean {
379
382
  return ENV_PLACEHOLDER.test(value);
380
383
  }
381
384
 
382
- function assertMcpSecretPlaceholders(server: ProvisioningMcpServer): void {
385
+ function assertMcpSecretPlaceholders(server: ProvisioningMcpServer, serverName?: string): void {
383
386
  for (const [key, value] of Object.entries(server.env ?? {})) {
384
387
  if (!/^[A-Z_][A-Z0-9_]*$/.test(key)) throw new ValidationError(`mcp env key ${key} is not a valid env name`);
385
388
  if (!isEnvPlaceholder(value)) throw new ValidationError(`mcp env ${key} must reference an env placeholder name`);
386
389
  }
390
+ const configEnv = (server as ProvisioningMcpServer & { configEnv?: unknown }).configEnv;
391
+ if (configEnv !== undefined) {
392
+ if (!isRecord(configEnv)) throw new ValidationError("mcp configEnv must be an object");
393
+ for (const [key, value] of Object.entries(configEnv)) {
394
+ if (typeof value !== "string") throw new ValidationError(`mcp configEnv ${key} must be a string`);
395
+ if (!SHARED_CALLMUX_CONFIG_ENV_ALLOWLIST[serverName ?? ""]?.includes(key)) throw new ValidationError(`mcp configEnv ${key} is not allowlisted for ${serverName ?? "this server"}`);
396
+ }
397
+ }
387
398
  for (const [key, value] of Object.entries(server.headers ?? {})) {
388
399
  if (/authorization|token|secret|key|api/i.test(key) && !/^Bearer \$\{[A-Z_][A-Z0-9_]*\}$/.test(value) && !isEnvPlaceholder(value)) {
389
400
  throw new ValidationError(`mcp header ${key} must reference an env placeholder name`);
@@ -562,14 +573,24 @@ function cloneJsonRecord(value: Record<string, unknown>): Record<string, unknown
562
573
  return JSON.parse(JSON.stringify(value)) as Record<string, unknown>;
563
574
  }
564
575
 
565
- function scrubEnvPlaceholders(value: unknown): Record<string, string> | undefined {
566
- if (!isRecord(value)) return undefined;
576
+ function scrubEnvPlaceholders(serverName: string, value: unknown): { env: Record<string, string> | undefined; configEnv: Record<string, string> | undefined } {
577
+ if (!isRecord(value)) return { env: undefined, configEnv: undefined };
567
578
  const env: Record<string, string> = {};
579
+ const configEnv: Record<string, string> = {};
568
580
  for (const [key, raw] of Object.entries(value)) {
569
581
  if (typeof raw !== "string") continue;
570
- env[key] = isEnvPlaceholder(raw) ? raw : `$${key}`;
582
+ if (isEnvPlaceholder(raw)) {
583
+ env[key] = raw;
584
+ } else if (SHARED_CALLMUX_CONFIG_ENV_ALLOWLIST[serverName]?.includes(key)) {
585
+ configEnv[key] = raw;
586
+ } else {
587
+ env[key] = `$${key}`;
588
+ }
571
589
  }
572
- return Object.keys(env).length ? env : undefined;
590
+ return {
591
+ env: Object.keys(env).length ? env : undefined,
592
+ configEnv: Object.keys(configEnv).length ? configEnv : undefined,
593
+ };
573
594
  }
574
595
 
575
596
  function envPlaceholderForLiteral(value: string, env: Record<string, string | undefined>): string | undefined {
@@ -607,12 +628,14 @@ function scrubHeaderPlaceholders(value: unknown, env: Record<string, string | un
607
628
  return Object.keys(headers).length ? headers : undefined;
608
629
  }
609
630
 
610
- function scrubCallmuxServerSecrets(server: Record<string, unknown>, env: Record<string, string | undefined>): Record<string, unknown> {
631
+ function scrubCallmuxServerSecrets(serverName: string, server: Record<string, unknown>, env: Record<string, string | undefined>): Record<string, unknown> {
611
632
  const scrubbed = cloneJsonRecord(server);
612
- const scrubbedEnv = scrubEnvPlaceholders(scrubbed.env);
633
+ const { env: scrubbedEnv, configEnv } = scrubEnvPlaceholders(serverName, scrubbed.env);
613
634
  const scrubbedHeaders = scrubHeaderPlaceholders(scrubbed.headers, env);
614
- if (scrubbedEnv) scrubbed.env = scrubbedEnv;
635
+ if (scrubbedEnv !== undefined) scrubbed.env = scrubbedEnv;
615
636
  else delete scrubbed.env;
637
+ if (configEnv !== undefined) scrubbed.configEnv = configEnv;
638
+ else delete scrubbed.configEnv;
616
639
  if (scrubbedHeaders) scrubbed.headers = scrubbedHeaders;
617
640
  else delete scrubbed.headers;
618
641
  return scrubbed;
@@ -633,12 +656,12 @@ function mcpServerFromCallmuxServer(server: Record<string, unknown>): Provisioni
633
656
  return projected;
634
657
  }
635
658
 
636
- function updateSharedCallmuxAssetMetadata(asset: ProvisioningAsset, sourceConfigPath: string, callmuxServer: Record<string, unknown>): void {
659
+ function updateSharedCallmuxAssetMetadata(asset: ProvisioningAsset, sourceConfigPath: string, callmuxServer: Record<string, unknown>, sharedListenerEligible = true): void {
637
660
  if (!asset.capabilityId) throw new ValidationError("shared callmux seed missing capability id");
638
661
  const now = Date.now();
639
662
  const provenance = {
640
663
  importedBy: "agent-relay-shared-callmux-seed",
641
- sharedListenerEligible: true,
664
+ sharedListenerEligible,
642
665
  callmux: { sourceConfigPath, serverName: asset.name },
643
666
  };
644
667
  getDb().query(`
@@ -664,9 +687,10 @@ export function seedSharedCallmuxProvisioningAssets(
664
687
  result.skipped.push({ name, reason: "missing" });
665
688
  continue;
666
689
  }
667
- const callmuxServer = scrubCallmuxServerSecrets(rawServer, input.env ?? process.env);
690
+ const callmuxServer = scrubCallmuxServerSecrets(name, rawServer, input.env ?? process.env);
668
691
  const server = mcpServerFromCallmuxServer(callmuxServer);
669
692
  try {
693
+ const sharedListenerEligible = !SHARED_CALLMUX_SEED_NON_LISTENER_NAMES.has(name);
670
694
  const asset = upsertProvisioningAsset({
671
695
  kind: "mcp",
672
696
  name,
@@ -674,10 +698,10 @@ export function seedSharedCallmuxProvisioningAssets(
674
698
  kind: "mcp",
675
699
  name,
676
700
  server,
677
- metadata: { sharedListenerEligible: true, callmuxServer },
701
+ metadata: { sharedListenerEligible, callmuxServer },
678
702
  },
679
703
  });
680
- updateSharedCallmuxAssetMetadata(asset, sourceConfigPath, callmuxServer);
704
+ updateSharedCallmuxAssetMetadata(asset, sourceConfigPath, callmuxServer, sharedListenerEligible);
681
705
  result.seeded.push(name);
682
706
  } catch (err) {
683
707
  result.skipped.push({ name, reason: errMessage(err) });
package/src/db/schema.ts CHANGED
@@ -304,7 +304,7 @@ export function initDb(path: string = "agent-relay.db"): Database {
304
304
  CREATE INDEX IF NOT EXISTS idx_project_edges_to ON project_edges(to_project, kind);
305
305
  CREATE TABLE IF NOT EXISTS plans (
306
306
  id TEXT PRIMARY KEY, thread_id INTEGER NOT NULL, team_id TEXT, channel TEXT, version INTEGER NOT NULL DEFAULT 1,
307
- title TEXT, objective TEXT, nodes TEXT NOT NULL DEFAULT '[]', edges TEXT NOT NULL DEFAULT '[]',
307
+ archived INTEGER NOT NULL DEFAULT 0, title TEXT, objective TEXT, nodes TEXT NOT NULL DEFAULT '[]', edges TEXT NOT NULL DEFAULT '[]',
308
308
  created_by TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL
309
309
  );
310
310
  CREATE UNIQUE INDEX IF NOT EXISTS idx_plans_thread_channel ON plans(thread_id, coalesce(channel, ''));
@@ -618,6 +618,7 @@ export interface ListDeliverableTasksFilter {
618
618
  deliverableStage?: string;
619
619
  teamId?: string;
620
620
  createdBy?: string;
621
+ ownerAgentId?: string;
621
622
  limit?: number;
622
623
  }
623
624
 
@@ -628,6 +629,7 @@ export function listDeliverableTasks(filter: ListDeliverableTasksFilter = {}): T
628
629
  if (filter.deliverableStage) { conditions.push("deliverable_stage = ?"); params.push(filter.deliverableStage); }
629
630
  if (filter.teamId) { conditions.push("team_id = ?"); params.push(filter.teamId); }
630
631
  if (filter.createdBy) { conditions.push("created_by = ?"); params.push(filter.createdBy); }
632
+ if (filter.ownerAgentId) { conditions.push("owner_agent_id = ?"); params.push(filter.ownerAgentId); }
631
633
  const limit = Math.min(Math.max(filter.limit ?? 100, 1), 500);
632
634
  params.push(limit);
633
635
  return (getDb().query(`${TASK_SELECT} WHERE ${conditions.join(" AND ")} ORDER BY updated_at DESC LIMIT ?`).all(...params as any[]) as any[]).map(rowToTask);
package/src/mcp/index.ts CHANGED
@@ -54,7 +54,7 @@ export const RELAY_TOOL_GROUPS: Record<string, readonly string[]> = {
54
54
  artifacts: ["relay_upload_artifact", "relay_attach_artifact"],
55
55
  workspace: ["relay_workspace_status", "relay_workspace_ready", "relay_workspace_deps", "relay_workspace_list", "relay_workspace_claim", "relay_workspace_release", "relay_workspace_land", "relay_merge_pause", "relay_merge_pauses", "relay_merge_renew", "relay_merge_resume"],
56
56
  "spawn-lifecycle": ["relay_spawn_agent", "relay_spawn_targets", "relay_my_agents", "relay_shutdown_agent", "relay_agent_action", "relay_agent_status", "relay_agent_crash_report", "relay_schedule_timer", "relay_list_timers", "relay_cancel_timer"],
57
- plans: ["relay_plan_create", "relay_plan_add_node", "relay_plan_update_node", "relay_plan_add_edge", "relay_plan_remove_node", "relay_plan_remove_edge", "relay_plan_delete", "relay_plan_get"],
57
+ plans: ["relay_plan_create", "relay_plan_add_node", "relay_plan_update_node", "relay_plan_add_edge", "relay_plan_remove_node", "relay_plan_remove_edge", "relay_plan_archive", "relay_plan_delete", "relay_plan_get"],
58
58
  tasks: ["relay_task_create", "relay_task_get", "relay_task_list", "relay_task_update", "relay_task_set_status", "relay_task_set_stage", "relay_task_record_gate", "relay_task_add_dependency", "relay_task_remove_dependency", "relay_task_add_ref", "relay_task_remove_ref", "relay_task_assign_agent", "relay_task_history", "relay_task_memory_read", "relay_task_memory_replace_working_state", "relay_task_memory_append_ruled_out", "relay_task_memory_append_decision", "relay_task_dispatch", "relay_task_comment", "relay_task_close_bridge", "relay_release_readiness"],
59
59
  teams: ["relay_team_get", "relay_team_set_brief", "relay_team_claim", "relay_team_dissolve"],
60
60
  blackboard: ["relay_blackboard_write", "relay_blackboard_get", "relay_blackboard_read", "relay_blackboard_search", "relay_blackboard_retract"],
@@ -4,6 +4,7 @@ import { authContextFromMcp } from "./services/auth-context";
4
4
  import {
5
5
  addPlanEdge,
6
6
  addPlanNode,
7
+ archivePlanGraph,
7
8
  bindPlanNodeToTask,
8
9
  createPlan,
9
10
  deletePlanGraph,
@@ -98,6 +99,7 @@ export const PLAN_TOOLS = [
98
99
  { name: "relay_plan_add_edge", description: "Add a dependency edge to a plan DAG; rejects cycles.", requiredScopes: ["plans:write"], inputSchema: { type: "object", properties: { planId: { type: "string" }, from: { type: "string" }, to: { type: "string" } }, required: ["planId", "from", "to"], additionalProperties: false } },
99
100
  { name: "relay_plan_remove_node", description: "Remove a node and its connected edges from a plan DAG.", requiredScopes: ["plans:write"], inputSchema: { type: "object", properties: { planId: { type: "string" }, nodeId: { type: "string" } }, required: ["planId", "nodeId"], additionalProperties: false } },
100
101
  { name: "relay_plan_remove_edge", description: "Remove a dependency edge from a plan DAG.", requiredScopes: ["plans:write"], inputSchema: { type: "object", properties: { planId: { type: "string" }, from: { type: "string" }, to: { type: "string" } }, required: ["planId", "from", "to"], additionalProperties: false } },
102
+ { name: "relay_plan_archive", description: "Soft-archive or unarchive a persisted plan DAG without deleting its history.", requiredScopes: ["plans:write"], inputSchema: { type: "object", properties: { planId: { type: "string" }, archived: { type: "boolean", default: true } }, required: ["planId"], additionalProperties: false } },
101
103
  { name: "relay_plan_delete", description: "Delete a persisted plan DAG and archive its latest version.", requiredScopes: ["plans:write"], inputSchema: { type: "object", properties: { planId: { type: "string" } }, required: ["planId"], additionalProperties: false } },
102
104
  {
103
105
  name: "relay_plan_bind_node",
@@ -135,6 +137,7 @@ export function relayPlanTool(auth: McpAuthLike, name: string, args: Record<stri
135
137
  if (name === "relay_plan_add_edge") return addPlanEdge(stringArg(args.planId, "planId"), { from: args.from, to: args.to }, ctx) as unknown as Record<string, unknown>;
136
138
  if (name === "relay_plan_remove_node") return removePlanNode(stringArg(args.planId, "planId"), stringArg(args.nodeId, "nodeId"), ctx) as unknown as Record<string, unknown>;
137
139
  if (name === "relay_plan_remove_edge") return removePlanEdge(stringArg(args.planId, "planId"), { from: args.from, to: args.to }, ctx) as unknown as Record<string, unknown>;
140
+ if (name === "relay_plan_archive") return archivePlanGraph(stringArg(args.planId, "planId"), args.archived !== false, ctx) as unknown as Record<string, unknown>;
138
141
  if (name === "relay_plan_delete") return deletePlanGraph(stringArg(args.planId, "planId"), ctx);
139
142
  if (name === "relay_plan_bind_node") {
140
143
  return bindPlanNodeToTask(
@@ -33,7 +33,7 @@ import { getHostDirectories, postAgent, postAgentSpawn, postRouteAdvice } from "
33
33
  import { getInsightsConfigRoute, getInsightsObservationsRoute, postInsightsObservationRoute, putInsightsConfigRoute } from "./insights";
34
34
  import { getOrchestratorDirectories, getOrchestratorFileRead, getOrchestratorFileStat, getOrchestratorFilesList, getOrchestratorLogs, getOrchestratorProviders, getOrchestratorSessions, getOrchestratorTerminal, getOrchestratorVersion, getOrchestratorWorkspaceProbe, postOrchestratorCreateDirectory, postOrchestratorTerminalInput, postOrchestratorTerminalResize } from "./orchestrator-proxy";
35
35
  import { getPairById, getPairs, postAcceptPair, postHangupPair, postPair, postPairMessage, postRejectPair } from "./pairs";
36
- import { getPlanByIdRoute, getPlansRoute } from "./plans";
36
+ import { getPlanByIdRoute, getPlansRoute, patchPlanArchiveRoute } from "./plans";
37
37
  import { getBlackboardEntryRoute, getBlackboardRoute } from "./blackboard";
38
38
  import { deleteIssueAssociationRoute, getIssueAssociationEntityIssuesRoute, getIssueAssociationIssueEntitiesRoute, postIssueAssociationRoute } from "./issue-associations";
39
39
  import { getAgentIssueActivityRoute, getIssueActivityAgentsRoute, postIssueActivityRoute } from "./issue-activity";
@@ -384,6 +384,7 @@ const routes: Route[] = [
384
384
  route("POST", "/api/pairs/:id/messages", postPairMessage),
385
385
  route("GET", "/api/plans", getPlansRoute),
386
386
  route("GET", "/api/plans/:id", getPlanByIdRoute),
387
+ route("PATCH", "/api/plans/:id/archive", patchPlanArchiveRoute),
387
388
  route("GET", "/api/blackboard", getBlackboardRoute),
388
389
  route("GET", "/api/blackboard/:id", getBlackboardEntryRoute),
389
390
  route("POST", "/api/issue-associations", postIssueAssociationRoute),
@@ -1,6 +1,7 @@
1
- import { getPlanGraph } from "../services/plan-graph";
1
+ import { archivePlanGraph, getPlanGraph } from "../services/plan-graph";
2
+ import { authContextFromRequest } from "../services/auth-context";
2
3
  import { cleanString } from "../validation";
3
- import { error, json, parseQueryInt, type Handler } from "./_shared";
4
+ import { error, json, parseBody, parseQueryInt, type Handler } from "./_shared";
4
5
 
5
6
  export const getPlansRoute: Handler = (req) => {
6
7
  const url = new URL(req.url);
@@ -32,3 +33,12 @@ export const getPlanByIdRoute: Handler = (_req, params) => {
32
33
  const plan = getPlanGraph({ planId: id });
33
34
  return plan ? json(plan) : error("plan not found", 404);
34
35
  };
36
+
37
+ export const patchPlanArchiveRoute: Handler = async (req, params) => {
38
+ const id = cleanString(params.id, "id", { required: true, max: 120 })!;
39
+ const parsed = await parseBody<{ archived?: unknown }>(req);
40
+ if (!parsed.ok) return error(parsed.error);
41
+ const archived = parsed.body?.archived;
42
+ if (typeof archived !== "boolean") return error("archived must be a boolean");
43
+ return json(archivePlanGraph(id, archived, authContextFromRequest(req)));
44
+ };
@@ -56,6 +56,7 @@ export const getTasks: Handler = (req) => {
56
56
  status: url.searchParams.get("status") ?? undefined,
57
57
  deliverableStage: url.searchParams.get("deliverableStage") ?? undefined,
58
58
  teamId: url.searchParams.get("teamId") ?? undefined,
59
+ ownerAgentId: url.searchParams.get("ownerAgentId") ?? undefined,
59
60
  limit: limitRaw ?? 100,
60
61
  }));
61
62
  }
@@ -1,5 +1,5 @@
1
1
  import { isRecord } from "agent-relay-sdk";
2
- import { addTaskDependency, createPlanRow, deletePlan, getAgent, getEntry, getPlan, getPlanByTeam, getPlanByThread, getTaskDetail, listPlansWithBoundOwner, planThreadExists, removeTaskDependency, replacePlan, ValidationError } from "../db";
2
+ import { addTaskDependency, createPlanRow, deletePlan, getAgent, getEntry, getPlan, getPlanByTeam, getPlanByThread, getTaskDetail, listPlansWithBoundOwner, planThreadExists, removeTaskDependency, replacePlan, setPlanArchived, ValidationError } from "../db";
3
3
  import { associateIssue, planNodeIssueEntityId, removeAssociation } from "../db/issue-associations";
4
4
  import { resolveIssueRefFromString } from "../db/issue-refs";
5
5
  import { emitRelayEvent } from "../events";
@@ -394,6 +394,13 @@ export function deletePlanGraph(planId: string, ctx: AuthContext): { id: string;
394
394
  return { id: plan.id, deleted: true };
395
395
  }
396
396
 
397
+ export function archivePlanGraph(planId: string, archived: boolean, ctx: AuthContext): Plan {
398
+ const actor = actorId(ctx);
399
+ const plan = setPlanArchived(planId, archived);
400
+ emitPlan("plan.changed", plan, actor);
401
+ return plan;
402
+ }
403
+
397
404
  export function updateBoundPlanNodesForAgent(agentId: string, status: PlanStatus, actor = "server"): Plan[] {
398
405
  const updated: Plan[] = [];
399
406
  for (const plan of listPlansWithBoundOwner(agentId)) {
@@ -1,4 +0,0 @@
1
- import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,$t as n,Cn as r,Gn as i,H as a,Ht as o,Ln as s,Mn as c,Ot as l,R as u,S as d,Tn as f,V as p,Wn as m,Zn as h,_ as g,_n as _,a as v,bn as y,en as b,fn as ee,fr as x,h as S,kt as C,l as te,o as ne,pt as w,r as T,sn as E,tr as D,un as O,ut as re,wn as ie,x as k,xn as A,yn as j}from"./lucide-react-DmbfpRvJ.js";import{r as M,t as N,y as P}from"./store-Du8k5mLJ.js";import{o as F}from"./types-DSwhOFcJ.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-_5kFrHJh.js";import{k as H,n as pe,r as me,s as he,t as U}from"./index-BMAblAKQ.js";import{t as ge}from"./user-avatar-BQoM4jPT.js";var W=e(x(),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,a=n.some(e=>e!==V);if(i||a){let e=i?r:n.find(e=>e!==V);return{label:`read`,title:e?`Read by ${e}`:`Read by agent`,tone:`ok`,icon:f}}if(e.deliveryStatus===`delivered`)return{label:`delivered`,title:`Delivered to agent inbox`,tone:`ok`,icon:f};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:j}}return{label:`sent`,title:`Accepted by Relay`,tone:`muted`,icon:ie}}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=t(),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)(O,{className:h(`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":l,"context.warning":S,"agent.context_threshold":S,"agent.resume_budget_exhausted":S,"agent.rate_limit_resume":a},$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:h(`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:``,o=typeof t.branch==`string`?t.branch:``,s=typeof t.base==`string`?t.base:``,c=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)(l,{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`}),o&&s&&(0,Y.jsxs)(`span`,{className:`font-mono text-emerald-700/80 dark:text-emerald-200/70`,title:`${o} → ${s}`,children:[o,(0,Y.jsx)(`span`,{className:`opacity-50`,children:` → `}),s]}),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`})]}),c===!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]??u,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":p,"spawned-child-exited":re,"spawned-child-failed":j,"spawned-by-ready":i,"spawned-by-exited":i,"spawned-by-failed":i},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]??u,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:h(`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:h(`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:c,instructions:o,tools:ne,comms:u,knowledge:s,context:b},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]??k;return(0,Y.jsx)(`div`,{className:`flex justify-center py-2 my-1`,children:(0,Y.jsxs)(`div`,{className:h(`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)(A,{className:h(`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)(j,{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)(ee,{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[r,i]=pt(),a=t?e:e.filter(e=>e.kind!==`reasoning`);if(!a.length)return null;let o=a.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:[a.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)(c,{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):r?null:(0,Y.jsxs)(`div`,{className:`flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground`,children:[(0,Y.jsx)(g,{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)),o>0&&(0,Y.jsxs)(`button`,{onClick:i,className:`flex items-center gap-1 text-[11px] text-muted-foreground/50 hover:text-muted-foreground transition-colors text-left`,children:[(0,Y.jsx)(A,{className:h(`w-3 h-3 shrink-0 transition-transform`,!r&&`rotate-90`)}),(0,Y.jsx)(`span`,{children:r?`show ${o} tool step${o===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)(_,{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)(C,{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:h(`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:h(`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:h(`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:h(`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)(k,{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,i]=(0,W.useState)(!0),[a,o]=(0,W.useState)(null),[s,c]=(0,W.useState)(null),[l,u]=(0,W.useState)(!1),d=(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(!d||!e){i(!0);return}let t=null,n=null,r=()=>{let r=e.querySelector(`[data-msg-id="${d.id}"]`);if(!r){t?.disconnect(),t=null,n=null,i(!1);return}let a=r.getBoundingClientRect(),o=e.getBoundingClientRect();u(a.top<o.top),r!==n&&(t?.disconnect(),n=r,t=new IntersectionObserver(([e])=>{e&&i(e.isIntersecting)},{root:e,threshold:0}),t.observe(r))};return r(),e.addEventListener(`scroll`,r,{passive:!0}),()=>{t?.disconnect(),e.removeEventListener(`scroll`,r)}},[d?.id,e]),n||!d||!d.body.trim())return null;let f=a?.id===d.id?a.value:!1,p=s?.id===d.id?s.value:!1;function m(){!e||!d||e.querySelector(`[data-msg-id="${d.id}"]`)?.scrollIntoView({behavior:`smooth`,block:`center`})}let g=l?`↑`:`↓`;return p?(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:()=>c({id:d.id,value:!1}),children:[(0,Y.jsx)(`span`,{children:`Your prompt`}),(0,Y.jsx)(r,{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:m,children:[g,` scroll to original`]}),(0,Y.jsx)(`button`,{type:`button`,className:`hover:text-foreground transition-colors`,onClick:()=>c({id:d.id,value:!0}),title:`Minimize`,children:(0,Y.jsx)(y,{className:`w-3 h-3`})})]}),(0,Y.jsx)(`p`,{className:h(`text-sm text-foreground leading-snug cursor-pointer`,!f&&`line-clamp-2`),onClick:()=>o({id:d.id,value:!f}),children:d.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:h(`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 r=e.kind===`image`,i=e.title||e.artifactId,[a,s]=(0,W.useState)(null),[c,l]=(0,W.useState)(null),[u,d]=(0,W.useState)(!1),[f,p]=(0,W.useState)(!1);(0,W.useEffect)(()=>{let t=!1,n=null;async function r(){d(!0),l(null),s(null);try{let r=await D(`/artifacts/${encodeURIComponent(e.artifactId)}/content`);if(t)return;n=URL.createObjectURL(r),s(n)}catch(e){t||l(e.message)}finally{t||d(!1)}}return r(),()=>{t=!0,n&&URL.revokeObjectURL(n)}},[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)(T,{className:`w-6 h-6 text-white opacity-0 group-hover/img:opacity-100 transition-opacity drop-shadow-md`})})]}):(0,Y.jsxs)(`span`,{className:h(`flex min-h-20 items-center gap-2 px-3 py-2 text-xs`,c?`text-red-400`:`text-muted-foreground`),children:[u?(0,Y.jsx)(w,{className:`h-4 w-4 animate-spin`}):(0,Y.jsx)(j,{className:`h-4 w-4`}),c||`Loading image`]})}),a&&(0,Y.jsx)(pe,{open:f,onOpenChange:p,children:(0,Y.jsxs)(me,{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)(n,{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)(v,{className:`w-4 h-4`})})]})]})]})})]}):(0,Y.jsxs)(`button`,{type:`button`,onClick:m,disabled:!a,className:h(`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:[u?(0,Y.jsx)(w,{className:`h-4 w-4 shrink-0 animate-spin`}):c?(0,Y.jsx)(j,{className:`h-4 w-4 shrink-0 text-red-400`}):(0,Y.jsx)(o,{className:`h-4 w-4 shrink-0`}),(0,Y.jsx)(`span`,{className:h(`min-w-0 flex-1 truncate`,c&&`text-red-400`),children:c||i}),(0,Y.jsx)(n,{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:h(`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)(d,{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),a=N(e=>e.agentsById),o=N(e=>e.openAgentDetail),s=e.from===t,c=(s?e.to:e.from)||``,l=a[s?t:c]?.issueRepo??a[t]?.issueRepo,u=!c||c===`broadcast`||c.includes(`:`),d=z(e),f=J(e.occurredAt??e.createdAt),p=s?m:i,g=a[e.from??``]??null;function _(e){e.stopPropagation(),g&&o(g)}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)(A,{className:h(`h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform`,n&&`rotate-90`)}),(0,Y.jsx)(`button`,{type:`button`,title:g?g.label||g.name||g.id:void 0,disabled:!g,onClick:_,className:h(`shrink-0 transition-opacity`,g?`cursor-pointer hover:opacity-80`:`cursor-default opacity-60`),children:(0,Y.jsx)(H,{agent:g,className:`!w-4 !h-4 !rounded-sm opacity-70`})}),(0,Y.jsx)(p,{className:`h-3 w-3 shrink-0 text-muted-foreground/70`}),(0,Y.jsxs)(`span`,{className:`shrink-0 text-muted-foreground`,children:[`Message `,s?`to`:`from`]}),u?(0,Y.jsx)(`span`,{className:`shrink-0 font-medium text-muted-foreground`,children:de(c,a)}):(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),g=s?ce(e.from,p):void 0,_=N(e=>e.openAgentDetail);N(e=>e.openTaskDetailById);let[v,y]=(0,W.useState)(!1),b=(0,W.useRef)(null),x=(0,W.useRef)(null),S=(0,W.useRef)(!1),C=z(e),ne=J(e.occurredAt??e.createdAt),w=ze(e),T=Ve(e),E=s?He(e,t):null,D=E?.icon,O=u===String(e.id),re=l&&!s&&!q(e)&&C.trim().length>0;function ie(t){t.stopPropagation(),O?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 k(e){return Pe(d||`/`,e)}function A(e,t){let n=k(e);r?.(n,t)}function j(e,t,n){let r=k(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:h(`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:h(`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:O?`Stop playback`:`Play aloud`,onClick:ie,className:h(`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`,O?`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:O?(0,Y.jsx)(ee,{className:`h-3.5 w-3.5 animate-pulse`}):(0,Y.jsx)(te,{className:`h-3.5 w-3.5`})}),(0,Y.jsxs)(`div`,{className:h(`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:h(`text-[11px] font-semibold mb-0.5 text-right`,le(e.from)),children:fe(e.from,p)}),e.subject&&(0,Y.jsx)(`p`,{className:h(`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:A,onPreviewPath:j,onPreviewPathEnd:a,resolvePathTitle:(e,t)=>`${k(e)}${t?`:${t}`:``}`}),w.map(t=>(0,Y.jsx)(Tt,{attachment:t,outbound:s},`${e.id}-${t.artifactId}-${t.role||``}`)),(0,Y.jsxs)(`p`,{className:h(`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:ne}),E&&D&&(0,Y.jsxs)(`span`,{className:h(`inline-flex items-center gap-1`,E.tone===`ok`&&`text-emerald-300`,E.tone===`warn`&&`text-amber-200`,E.tone===`danger`&&`text-red-200`),title:E.title,children:[(0,Y.jsx)(D,{className:`h-3 w-3`}),E.label]})]})]}),!q(e)&&T.length>0&&(0,Y.jsxs)(`div`,{className:h(`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}),T.map(e=>(0,Y.jsxs)(`button`,{type:`button`,title:e.actors.join(`, `),onClick:()=>M(e.emoji),className:h(`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&&T.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:g,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-CFujR6_L.js.map
@@ -1,2 +0,0 @@
1
- import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,Cn as n,Zn as r,bn as i,er as a,fr as o,jt as s}from"./lucide-react-DmbfpRvJ.js";import{i as c,r as l,t as u}from"./store-Du8k5mLJ.js";import{_ as d,f}from"./index-BMAblAKQ.js";var p=e(o(),1),m=`(max-width: 767px)`;function h(e){if(typeof window>`u`)return()=>{};let t=window.matchMedia(m);return t.addEventListener(`change`,e),()=>t.removeEventListener(`change`,e)}function g(){return(0,p.useSyncExternalStore)(h,()=>typeof window<`u`?window.matchMedia(m).matches:!1,()=>!1)}var _=t(),v=196,y=84,b=52,x=16,S=14,C=[`landed`,`in-progress`,`pending`,`blocked`],w={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 T(e){return e?e.label||(e.policyName?`policy:${e.policyName}`:e.agentId||``):``}function E(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+x,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:S+r*(v+b),y:S+a+n*f})})});let m=u.length;return{nodes:p,width:Math.max(320,S*2+m*v+Math.max(0,m-1)*b),height:Math.max(y+S*2,S*2+d*y+Math.max(0,d-1)*x)}}function D(e,t){let n=e.x+v,r=e.y+y/2,i=t.x,a=t.y+y/2,o=n+Math.max(20,(i-n)/2);return`M ${n} ${r} C ${o} ${r}, ${o} ${a}, ${i} ${a}`}function O({threadId:e,teamId:t,channel:a}){let o=t?c(t,a):e?l(e,a):``,m=u(e=>t?e.plansByTeam[o]:o?e.plansByThread[o]:null),h=u(e=>e.fetchPlan),b=u(e=>e.planCollapsed),x=u(e=>e.setPlanCollapsed),S=u(e=>e.issueRefsById),O=u(e=>e.deliverableTasks),k=u(e=>e.openTaskDetailById),A=g(),j=b??A;(0,p.useEffect)(()=>{if(t){h({teamId:t,channel:a});return}e&&h({threadId:e,channel:a})},[a,h,t,e]);let M=(0,p.useMemo)(()=>m?E(m):null,[m]),N=(0,p.useMemo)(()=>new Map(M?.nodes.map(e=>[e.node.id,e])??[]),[M]),P=(0,p.useMemo)(()=>{if(!m)return[];let e=new Map;for(let t of m.nodes)e.set(t.status,(e.get(t.status)??0)+1);return C.filter(t=>e.has(t)).map(t=>({status:t,count:e.get(t)??0}))},[m]);if(!m||!M)return null;let F=m.nodes.length,I=P.find(e=>e.status===`landed`)?.count??0,L=`${F} node${F===1?``:`s`}${I>0?` · ${I} landed`:``}`;return(0,_.jsxs)(`section`,{className:`shrink-0 border-b border-border bg-card/45 px-3 py-2`,children:[(0,_.jsxs)(`button`,{type:`button`,onClick:()=>x(!j),"aria-expanded":!j,"aria-label":j?`Expand plan graph`:`Collapse plan graph`,className:r(`flex w-full min-w-0 items-center gap-2 text-left`,!j&&`mb-2`),children:[(0,_.jsx)(`span`,{className:`flex h-5 w-5 shrink-0 items-center justify-center rounded bg-muted/60`,children:(0,_.jsx)(s,{className:`h-3 w-3 text-muted-foreground`})}),(0,_.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,_.jsx)(`div`,{className:`truncate text-[13px] font-semibold leading-tight text-foreground`,children:m.title||`Plan`}),(0,_.jsx)(`div`,{className:`truncate text-[11px] leading-tight text-muted-foreground`,children:j?L:m.objective||L})]}),P.length>0&&(0,_.jsx)(`div`,{className:`hidden shrink-0 items-center gap-2.5 sm:flex`,children:P.map(({status:e,count:t})=>(0,_.jsxs)(`span`,{className:`flex items-center gap-1 text-[10px] text-muted-foreground`,children:[(0,_.jsx)(`span`,{className:r(`h-1.5 w-1.5 rounded-full`,w[e].dot)}),(0,_.jsx)(`span`,{className:r(`font-medium tabular-nums`,w[e].text),children:t}),(0,_.jsx)(`span`,{children:w[e].label})]},e))}),(0,_.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`,m.version]}),(0,_.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:j?(0,_.jsx)(n,{className:`h-3.5 w-3.5`}):(0,_.jsx)(i,{className:`h-3.5 w-3.5`})})]}),j?null:m.nodes.length===0?(0,_.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,_.jsx)(`div`,{className:`max-h-[min(46vh,360px)] overflow-auto`,children:(0,_.jsxs)(`div`,{className:`relative`,style:{width:M.width,height:M.height},children:[(0,_.jsxs)(`svg`,{className:`pointer-events-none absolute inset-0`,width:M.width,height:M.height,"aria-hidden":`true`,children:[(0,_.jsx)(`defs`,{children:C.map(e=>(0,_.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,_.jsx)(`path`,{d:`M0 0 L8 4 L0 8 z`,fill:w[e].wire})},e))}),m.edges.map(e=>{let t=N.get(e.from),n=N.get(e.to);if(!t||!n)return null;let r=w[t.node.status];return(0,_.jsx)(`path`,{d:D(t,n),stroke:r.wire,strokeOpacity:.7,strokeWidth:2,fill:`none`,strokeLinecap:`round`,markerEnd:`url(#plan-arrow-${t.node.status})`},`${e.from}->${e.to}`)})]}),M.nodes.map(({node:e,x:t,y:n})=>{let i=w[e.status],a=T(e.ownerRef),o=e.refs?.issueId?S[e.refs.issueId]:null,s=e.refs?.taskId?parseInt(e.refs.taskId,10):null,c=s==null?void 0:O.find(e=>e.id===s)?.title;return(0,_.jsxs)(`article`,{className:r(`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:n,width:v,height:y},title:e.scopeBlurb||e.label,children:[(0,_.jsx)(`div`,{className:`truncate text-xs font-semibold leading-tight text-foreground`,children:e.label}),(e.scopeBlurb||e.id)&&(0,_.jsx)(`div`,{className:`truncate text-[10px] leading-tight text-muted-foreground`,children:e.scopeBlurb||e.id}),(o||s!=null)&&(0,_.jsxs)(`div`,{className:`flex min-w-0 flex-wrap gap-1`,children:[o&&(0,_.jsx)(d,{issueRef:o,compact:!0,className:`max-w-full`}),s!=null&&(0,_.jsx)(f,{id:s,title:c,onClick:()=>k(s),className:`max-w-full`})]}),(0,_.jsxs)(`div`,{className:`flex min-w-0 items-center justify-between gap-1.5`,children:[(0,_.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5`,children:[(0,_.jsx)(`span`,{className:r(`h-1.5 w-1.5 shrink-0 rounded-full`,i.dot)}),(0,_.jsx)(`span`,{className:r(`text-[10px] font-medium`,i.text),children:i.label})]}),(0,_.jsxs)(`div`,{className:`flex min-w-0 items-center gap-1.5`,children:[a&&(0,_.jsx)(`span`,{className:`truncate text-[10px] text-muted-foreground`,children:a}),e.lane&&(0,_.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)})]})})]})}function k({agentId:e}){let t=u(e=>e.openTaskDetailById),[n,r]=(0,p.useState)([]);return(0,p.useEffect)(()=>{a(`GET`,`/task-entities?createdBy=`+encodeURIComponent(e)).then(e=>r(e)).catch(()=>{})},[e]),n.length===0?null:(0,_.jsxs)(`section`,{className:`shrink-0 border-b border-border bg-card/45 px-3 py-2`,children:[(0,_.jsxs)(`div`,{className:`mb-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground`,children:[`Tasks from this session (`,n.length,`)`]}),(0,_.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:n.map(e=>(0,_.jsx)(f,{id:e.id,title:e.title,status:e.status,onClick:()=>t(e.id)},e.id))})]})}export{k as n,O as t};
2
- //# sourceMappingURL=PlanGraphPanel-BfxvqmNS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PlanGraphPanel-BfxvqmNS.js","names":[],"sources":["../../dashboard/src/components/chat/hooks/useIsMobile.ts","../../dashboard/src/components/chat/PlanGraphPanel.tsx"],"sourcesContent":["import { useSyncExternalStore } from 'react'\n\n// Reactive narrow-viewport flag. Subscribes to the same `max-width: 767px`\n// breakpoint the chat single-pane layout uses, via useSyncExternalStore — an\n// external-store subscription, not effect-driven derived state — so it stays\n// correct across resize/rotate without a useEffect.\nconst QUERY = '(max-width: 767px)'\n\nfunction subscribe(cb: () => void): () => void {\n if (typeof window === 'undefined') return () => {}\n const mql = window.matchMedia(QUERY)\n mql.addEventListener('change', cb)\n return () => mql.removeEventListener('change', cb)\n}\n\nexport function useIsMobile(): boolean {\n return useSyncExternalStore(\n subscribe,\n () => (typeof window !== 'undefined' ? window.matchMedia(QUERY).matches : false),\n () => false,\n )\n}\n","import { useEffect, useMemo, useState } from 'react'\nimport { ChevronDown, ChevronUp, GitBranch } from 'lucide-react'\nimport { useRelayStore } from '@/store'\nimport type { Plan, PlanNode, PlanOwnerRef, PlanStatus, Task } from '@/types'\nimport { cn } from '@/lib/utils'\nimport { planLookupKey, planTeamLookupKey } from '@/store/slices/plans'\nimport { IssueRefChip } from '@/components/shared/issue-ref-chip'\nimport { TaskChip } from '@/components/shared/task-chip'\nimport { useIsMobile } from './hooks/useIsMobile'\nimport { api } from '@/lib/api'\n\n// Left-to-right DAG: dependency depth flows along x (sequential gates), nodes\n// that share a depth stack along y (parallel lanes). This keeps the panel SHORT\n// — it's an operator overlay above the chat, not a full view — and lets the\n// gate-vs-lane structure read at a glance. Height is capped + scrollable below.\nconst NODE_W = 196\nconst NODE_H = 84\nconst COL_GAP = 52\nconst ROW_GAP = 16\nconst PAD = 14\n\nconst STATUS_ORDER: PlanStatus[] = ['landed', 'in-progress', 'pending', 'blocked']\n\nconst STATUS_STYLE: Record<\n PlanStatus,\n { label: string; dot: string; accent: string; text: string; wire: string }\n> = {\n landed: { label: 'landed', dot: 'bg-emerald-400', accent: 'border-l-emerald-400', text: 'text-emerald-300', wire: '#34d399' },\n 'in-progress': { label: 'in progress', dot: 'bg-sky-400', accent: 'border-l-sky-400', text: 'text-sky-300', wire: '#38bdf8' },\n pending: { label: 'pending', dot: 'bg-amber-400', accent: 'border-l-amber-400', text: 'text-amber-300', wire: '#fbbf24' },\n blocked: { label: 'blocked', dot: 'bg-red-400', accent: 'border-l-red-400', text: 'text-red-300', wire: '#f87171' },\n}\n\ninterface LayoutNode {\n node: PlanNode\n x: number\n y: number\n layer: number\n}\n\nfunction ownerLabel(owner?: PlanOwnerRef): string {\n if (!owner) return ''\n return owner.label || (owner.policyName ? `policy:${owner.policyName}` : owner.agentId || '')\n}\n\nfunction layerPlan(plan: Plan): { nodes: LayoutNode[]; width: number; height: number } {\n const nodeById = new Map(plan.nodes.map((node) => [node.id, node]))\n const indexById = new Map(plan.nodes.map((node, index) => [node.id, index]))\n const outgoing = new Map<string, string[]>()\n const indegree = new Map(plan.nodes.map((node) => [node.id, 0]))\n for (const edge of plan.edges) {\n if (!nodeById.has(edge.from) || !nodeById.has(edge.to)) continue\n outgoing.set(edge.from, [...(outgoing.get(edge.from) ?? []), edge.to])\n indegree.set(edge.to, (indegree.get(edge.to) ?? 0) + 1)\n }\n\n const layerById = new Map(plan.nodes.map((node) => [node.id, 0]))\n const queue = plan.nodes\n .filter((node) => (indegree.get(node.id) ?? 0) === 0)\n .map((node) => node.id)\n const visited = new Set<string>()\n\n while (queue.length) {\n const id = queue.shift()!\n visited.add(id)\n const fromLayer = layerById.get(id) ?? 0\n for (const to of outgoing.get(id) ?? []) {\n layerById.set(to, Math.max(layerById.get(to) ?? 0, fromLayer + 1))\n indegree.set(to, (indegree.get(to) ?? 0) - 1)\n if ((indegree.get(to) ?? 0) === 0) queue.push(to)\n }\n }\n\n let fallbackLayer = Math.max(0, ...Array.from(layerById.values())) + 1\n for (const node of plan.nodes) {\n if (visited.has(node.id)) continue\n layerById.set(node.id, fallbackLayer++)\n }\n\n const layers = new Map<number, PlanNode[]>()\n for (const node of plan.nodes) {\n const layer = layerById.get(node.id) ?? 0\n layers.set(layer, [...(layers.get(layer) ?? []), node])\n }\n\n const orderedLayers = [...layers.entries()].sort(([a], [b]) => a - b)\n const maxRows = Math.max(1, ...orderedLayers.map(([, nodes]) => nodes.length))\n const rowPitch = NODE_H + ROW_GAP\n\n const layoutNodes: LayoutNode[] = []\n orderedLayers.forEach(([layer, nodes], col) => {\n const ordered = [...nodes].sort((a, b) => {\n const lane = (a.lane || '').localeCompare(b.lane || '')\n return lane || ((indexById.get(a.id) ?? 0) - (indexById.get(b.id) ?? 0))\n })\n // Center each column vertically against the tallest column so the spine\n // runs through the middle and the parallel fan reads as a fan.\n const offset = ((maxRows - ordered.length) * rowPitch) / 2\n ordered.forEach((node, row) => {\n layoutNodes.push({\n node,\n layer,\n x: PAD + col * (NODE_W + COL_GAP),\n y: PAD + offset + row * rowPitch,\n })\n })\n })\n\n const cols = orderedLayers.length\n return {\n nodes: layoutNodes,\n width: Math.max(320, PAD * 2 + cols * NODE_W + Math.max(0, cols - 1) * COL_GAP),\n height: Math.max(NODE_H + PAD * 2, PAD * 2 + maxRows * NODE_H + Math.max(0, maxRows - 1) * ROW_GAP),\n }\n}\n\nfunction edgePath(from: LayoutNode, to: LayoutNode): string {\n const x1 = from.x + NODE_W\n const y1 = from.y + NODE_H / 2\n const x2 = to.x\n const y2 = to.y + NODE_H / 2\n const midX = x1 + Math.max(20, (x2 - x1) / 2)\n return `M ${x1} ${y1} C ${midX} ${y1}, ${midX} ${y2}, ${x2} ${y2}`\n}\n\nexport function PlanGraphPanel({ threadId, teamId, channel }: { threadId?: string | number | null; teamId?: string | null; channel?: string }) {\n const key = teamId ? planTeamLookupKey(teamId, channel) : threadId ? planLookupKey(threadId, channel) : ''\n const plan = useRelayStore((s) => teamId ? s.plansByTeam[key] : key ? s.plansByThread[key] : null)\n const fetchPlan = useRelayStore((s) => s.fetchPlan)\n const planCollapsed = useRelayStore((s) => s.planCollapsed)\n const setPlanCollapsed = useRelayStore((s) => s.setPlanCollapsed)\n const issueRefsById = useRelayStore((s) => s.issueRefsById)\n const deliverableTasks = useRelayStore((s) => s.deliverableTasks)\n const openTaskDetailById = useRelayStore((s) => s.openTaskDetailById)\n const isMobile = useIsMobile()\n // null = no manual toggle yet → follow the viewport default. The graph\n // dominates a phone screen, so it starts collapsed there and expanded on\n // desktop; an explicit user toggle (persisted) overrides the default.\n const collapsed = planCollapsed ?? isMobile\n\n useEffect(() => {\n if (teamId) {\n void fetchPlan({ teamId, channel })\n return\n }\n if (threadId) void fetchPlan({ threadId, channel })\n }, [channel, fetchPlan, teamId, threadId])\n\n const layout = useMemo(() => plan ? layerPlan(plan) : null, [plan])\n const nodeById = useMemo(() => new Map(layout?.nodes.map((node) => [node.node.id, node]) ?? []), [layout])\n\n const legend = useMemo(() => {\n if (!plan) return []\n const counts = new Map<PlanStatus, number>()\n for (const node of plan.nodes) counts.set(node.status, (counts.get(node.status) ?? 0) + 1)\n return STATUS_ORDER.filter((status) => counts.has(status)).map((status) => ({\n status,\n count: counts.get(status) ?? 0,\n }))\n }, [plan])\n\n if (!plan || !layout) return null\n\n const nodeCount = plan.nodes.length\n const landedCount = legend.find((entry) => entry.status === 'landed')?.count ?? 0\n // Thin summary for the collapsed bar (the legend dots are hidden on mobile),\n // e.g. \"5 nodes · 4 landed\".\n const summary = `${nodeCount} node${nodeCount === 1 ? '' : 's'}${landedCount > 0 ? ` · ${landedCount} landed` : ''}`\n\n return (\n <section className=\"shrink-0 border-b border-border bg-card/45 px-3 py-2\">\n <button\n type=\"button\"\n onClick={() => setPlanCollapsed(!collapsed)}\n aria-expanded={!collapsed}\n aria-label={collapsed ? 'Expand plan graph' : 'Collapse plan graph'}\n className={cn(\n 'flex w-full min-w-0 items-center gap-2 text-left',\n !collapsed && 'mb-2',\n )}\n >\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded bg-muted/60\">\n <GitBranch className=\"h-3 w-3 text-muted-foreground\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-[13px] font-semibold leading-tight text-foreground\">{plan.title || 'Plan'}</div>\n <div className=\"truncate text-[11px] leading-tight text-muted-foreground\">\n {collapsed ? summary : (plan.objective || summary)}\n </div>\n </div>\n {legend.length > 0 && (\n <div className=\"hidden shrink-0 items-center gap-2.5 sm:flex\">\n {legend.map(({ status, count }) => (\n <span key={status} className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <span className={cn('h-1.5 w-1.5 rounded-full', STATUS_STYLE[status].dot)} />\n <span className={cn('font-medium tabular-nums', STATUS_STYLE[status].text)}>{count}</span>\n <span>{STATUS_STYLE[status].label}</span>\n </span>\n ))}\n </div>\n )}\n <span className=\"shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-muted-foreground\">\n v{plan.version}\n </span>\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted/60 hover:text-foreground\">\n {collapsed ? <ChevronDown className=\"h-3.5 w-3.5\" /> : <ChevronUp className=\"h-3.5 w-3.5\" />}\n </span>\n </button>\n {collapsed ? null : plan.nodes.length === 0 ? (\n <div className=\"rounded-md border border-dashed border-border px-3 py-3 text-center text-xs text-muted-foreground\">\n No nodes yet — the plan graph fills in as the team is composed.\n </div>\n ) : (\n <div className=\"max-h-[min(46vh,360px)] overflow-auto\">\n <div className=\"relative\" style={{ width: layout.width, height: layout.height }}>\n <svg className=\"pointer-events-none absolute inset-0\" width={layout.width} height={layout.height} aria-hidden=\"true\">\n <defs>\n {STATUS_ORDER.map((status) => (\n <marker\n key={status}\n id={`plan-arrow-${status}`}\n viewBox=\"0 0 8 8\"\n refX=\"6.5\"\n refY=\"4\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto-start-reverse\"\n >\n <path d=\"M0 0 L8 4 L0 8 z\" fill={STATUS_STYLE[status].wire} />\n </marker>\n ))}\n </defs>\n {plan.edges.map((edge) => {\n const from = nodeById.get(edge.from)\n const to = nodeById.get(edge.to)\n if (!from || !to) return null\n const wire = STATUS_STYLE[from.node.status]\n return (\n <path\n key={`${edge.from}->${edge.to}`}\n d={edgePath(from, to)}\n stroke={wire.wire}\n strokeOpacity={0.7}\n strokeWidth={2}\n fill=\"none\"\n strokeLinecap=\"round\"\n markerEnd={`url(#plan-arrow-${from.node.status})`}\n />\n )\n })}\n </svg>\n {layout.nodes.map(({ node, x, y }) => {\n const status = STATUS_STYLE[node.status]\n const owner = ownerLabel(node.ownerRef)\n const issueRef = node.refs?.issueId ? issueRefsById[node.refs.issueId] : null\n const taskNumId = node.refs?.taskId ? parseInt(node.refs.taskId, 10) : null\n const taskTitle = taskNumId != null ? deliverableTasks.find((t) => t.id === taskNumId)?.title : undefined\n return (\n <article\n key={node.id}\n className={cn(\n 'group absolute flex flex-col justify-between rounded-md border border-l-[3px] bg-background/95 p-2',\n 'shadow-sm transition-all hover:-translate-y-px hover:border-border hover:shadow-md hover:bg-background',\n status.accent,\n )}\n style={{ left: x, top: y, width: NODE_W, height: NODE_H }}\n title={node.scopeBlurb || node.label}\n >\n <div className=\"truncate text-xs font-semibold leading-tight text-foreground\">{node.label}</div>\n {(node.scopeBlurb || node.id) && (\n <div className=\"truncate text-[10px] leading-tight text-muted-foreground\">{node.scopeBlurb || node.id}</div>\n )}\n {(issueRef || taskNumId != null) && (\n <div className=\"flex min-w-0 flex-wrap gap-1\">\n {issueRef && <IssueRefChip issueRef={issueRef} compact className=\"max-w-full\" />}\n {taskNumId != null && (\n <TaskChip id={taskNumId} title={taskTitle} onClick={() => openTaskDetailById(taskNumId)} className=\"max-w-full\" />\n )}\n </div>\n )}\n <div className=\"flex min-w-0 items-center justify-between gap-1.5\">\n <div className=\"flex shrink-0 items-center gap-1.5\">\n <span className={cn('h-1.5 w-1.5 shrink-0 rounded-full', status.dot)} />\n <span className={cn('text-[10px] font-medium', status.text)}>{status.label}</span>\n </div>\n <div className=\"flex min-w-0 items-center gap-1.5\">\n {owner && <span className=\"truncate text-[10px] text-muted-foreground\">{owner}</span>}\n {node.lane && (\n <span className=\"shrink-0 rounded-sm bg-muted/70 px-1 py-px text-[9px] font-medium uppercase tracking-wide text-muted-foreground\">\n {node.lane}\n </span>\n )}\n </div>\n </div>\n </article>\n )\n })}\n </div>\n </div>\n )}\n </section>\n )\n}\n\n// Tasks created/triggered from a session (#856, #860). Fetches server-side via createdBy filter.\nexport function SessionTasksPanel({ agentId }: { agentId: string }) {\n const openTaskDetailById = useRelayStore((s) => s.openTaskDetailById)\n const [sessionTasks, setSessionTasks] = useState<Task[]>([])\n useEffect(() => {\n void api<import('@/types').Task[]>('GET', '/task-entities?createdBy=' + encodeURIComponent(agentId))\n .then((tasks) => setSessionTasks(tasks))\n .catch(() => {})\n }, [agentId])\n if (sessionTasks.length === 0) return null\n return (\n <section className=\"shrink-0 border-b border-border bg-card/45 px-3 py-2\">\n <div className=\"mb-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground\">\n Tasks from this session ({sessionTasks.length})\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {sessionTasks.map((task) => (\n <TaskChip\n key={task.id}\n id={task.id}\n title={task.title}\n status={task.status}\n onClick={() => openTaskDetailById(task.id)}\n />\n ))}\n </div>\n </section>\n )\n}\n"],"mappings":"uPAMM,EAAQ,qBAEd,SAAS,EAAU,EAA4B,CAC7C,GAAI,OAAO,OAAW,IAAa,UAAa,GAChD,IAAM,EAAM,OAAO,WAAW,EAAM,CAEpC,OADA,EAAI,iBAAiB,SAAU,EAAG,KACrB,EAAI,oBAAoB,SAAU,EAAG,CAGpD,SAAgB,GAAuB,CACrC,OAAA,EAAA,EAAA,sBACE,MACO,OAAO,OAAW,IAAc,OAAO,WAAW,EAAM,CAAC,QAAU,OACpE,GACP,WCLG,EAAS,IACT,EAAS,GACT,EAAU,GACV,EAAU,GACV,EAAM,GAEN,EAA6B,CAAC,SAAU,cAAe,UAAW,UAAU,CAE5E,EAGF,CACF,OAAQ,CAAE,MAAO,SAAU,IAAK,iBAAkB,OAAQ,uBAAwB,KAAM,mBAAoB,KAAM,UAAW,CAC7H,cAAe,CAAE,MAAO,cAAe,IAAK,aAAc,OAAQ,mBAAoB,KAAM,eAAgB,KAAM,UAAW,CAC7H,QAAS,CAAE,MAAO,UAAW,IAAK,eAAgB,OAAQ,qBAAsB,KAAM,iBAAkB,KAAM,UAAW,CACzH,QAAS,CAAE,MAAO,UAAW,IAAK,aAAc,OAAQ,mBAAoB,KAAM,eAAgB,KAAM,UAAW,CACpH,CASD,SAAS,EAAW,EAA8B,CAEhD,OADK,EACE,EAAM,QAAU,EAAM,WAAa,UAAU,EAAM,aAAe,EAAM,SAAW,IADvE,GAIrB,SAAS,EAAU,EAAoE,CACrF,IAAM,EAAW,IAAI,IAAI,EAAK,MAAM,IAAK,GAAS,CAAC,EAAK,GAAI,EAAK,CAAC,CAAC,CAC7D,EAAY,IAAI,IAAI,EAAK,MAAM,KAAK,EAAM,IAAU,CAAC,EAAK,GAAI,EAAM,CAAC,CAAC,CACtE,EAAW,IAAI,IACf,EAAW,IAAI,IAAI,EAAK,MAAM,IAAK,GAAS,CAAC,EAAK,GAAI,EAAE,CAAC,CAAC,CAChE,IAAK,IAAM,KAAQ,EAAK,MAClB,CAAC,EAAS,IAAI,EAAK,KAAK,EAAI,CAAC,EAAS,IAAI,EAAK,GAAG,GACtD,EAAS,IAAI,EAAK,KAAM,CAAC,GAAI,EAAS,IAAI,EAAK,KAAK,EAAI,EAAE,CAAG,EAAK,GAAG,CAAC,CACtE,EAAS,IAAI,EAAK,IAAK,EAAS,IAAI,EAAK,GAAG,EAAI,GAAK,EAAE,EAGzD,IAAM,EAAY,IAAI,IAAI,EAAK,MAAM,IAAK,GAAS,CAAC,EAAK,GAAI,EAAE,CAAC,CAAC,CAC3D,EAAQ,EAAK,MAChB,OAAQ,IAAU,EAAS,IAAI,EAAK,GAAG,EAAI,KAAO,EAAE,CACpD,IAAK,GAAS,EAAK,GAAG,CACnB,EAAU,IAAI,IAEpB,KAAO,EAAM,QAAQ,CACnB,IAAM,EAAK,EAAM,OAAO,CACxB,EAAQ,IAAI,EAAG,CACf,IAAM,EAAY,EAAU,IAAI,EAAG,EAAI,EACvC,IAAK,IAAM,KAAM,EAAS,IAAI,EAAG,EAAI,EAAE,CACrC,EAAU,IAAI,EAAI,KAAK,IAAI,EAAU,IAAI,EAAG,EAAI,EAAG,EAAY,EAAE,CAAC,CAClE,EAAS,IAAI,GAAK,EAAS,IAAI,EAAG,EAAI,GAAK,EAAE,EACxC,EAAS,IAAI,EAAG,EAAI,KAAO,GAAG,EAAM,KAAK,EAAG,CAIrD,IAAI,EAAgB,KAAK,IAAI,EAAG,GAAG,MAAM,KAAK,EAAU,QAAQ,CAAC,CAAC,CAAG,EACrE,IAAK,IAAM,KAAQ,EAAK,MAClB,EAAQ,IAAI,EAAK,GAAG,EACxB,EAAU,IAAI,EAAK,GAAI,IAAgB,CAGzC,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAK,MAAO,CAC7B,IAAM,EAAQ,EAAU,IAAI,EAAK,GAAG,EAAI,EACxC,EAAO,IAAI,EAAO,CAAC,GAAI,EAAO,IAAI,EAAM,EAAI,EAAE,CAAG,EAAK,CAAC,CAGzD,IAAM,EAAgB,CAAC,GAAG,EAAO,SAAS,CAAC,CAAC,MAAM,CAAC,GAAI,CAAC,KAAO,EAAI,EAAE,CAC/D,EAAU,KAAK,IAAI,EAAG,GAAG,EAAc,KAAK,EAAG,KAAW,EAAM,OAAO,CAAC,CACxE,EAAW,EAAS,EAEpB,EAA4B,EAAE,CACpC,EAAc,SAAS,CAAC,EAAO,GAAQ,IAAQ,CAC7C,IAAM,EAAU,CAAC,GAAG,EAAM,CAAC,MAAM,EAAG,KACpB,EAAE,MAAQ,IAAI,cAAc,EAAE,MAAQ,GAC7C,GAAU,EAAU,IAAI,EAAE,GAAG,EAAI,IAAM,EAAU,IAAI,EAAE,GAAG,EAAI,GACrE,CAGI,GAAW,EAAU,EAAQ,QAAU,EAAY,EACzD,EAAQ,SAAS,EAAM,IAAQ,CAC7B,EAAY,KAAK,CACf,OACA,QACA,EAAG,EAAM,GAAO,EAAS,GACzB,EAAG,EAAM,EAAS,EAAM,EACzB,CAAC,EACF,EACF,CAEF,IAAM,EAAO,EAAc,OAC3B,MAAO,CACL,MAAO,EACP,MAAO,KAAK,IAAI,IAAK,EAAM,EAAI,EAAO,EAAS,KAAK,IAAI,EAAG,EAAO,EAAE,CAAG,EAAQ,CAC/E,OAAQ,KAAK,IAAI,EAAS,EAAM,EAAG,EAAM,EAAI,EAAU,EAAS,KAAK,IAAI,EAAG,EAAU,EAAE,CAAG,EAAQ,CACpG,CAGH,SAAS,EAAS,EAAkB,EAAwB,CAC1D,IAAM,EAAK,EAAK,EAAI,EACd,EAAK,EAAK,EAAI,EAAS,EACvB,EAAK,EAAG,EACR,EAAK,EAAG,EAAI,EAAS,EACrB,EAAO,EAAK,KAAK,IAAI,IAAK,EAAK,GAAM,EAAE,CAC7C,MAAO,KAAK,EAAG,GAAG,EAAG,KAAK,EAAK,GAAG,EAAG,IAAI,EAAK,GAAG,EAAG,IAAI,EAAG,GAAG,IAGhE,SAAgB,EAAe,CAAE,WAAU,SAAQ,WAA4F,CAC7I,IAAM,EAAM,EAAS,EAAkB,EAAQ,EAAQ,CAAG,EAAW,EAAc,EAAU,EAAQ,CAAG,GAClG,EAAO,EAAe,GAAM,EAAS,EAAE,YAAY,GAAO,EAAM,EAAE,cAAc,GAAO,KAAK,CAC5F,EAAY,EAAe,GAAM,EAAE,UAAU,CAC7C,EAAgB,EAAe,GAAM,EAAE,cAAc,CACrD,EAAmB,EAAe,GAAM,EAAE,iBAAiB,CAC3D,EAAgB,EAAe,GAAM,EAAE,cAAc,CACrD,EAAmB,EAAe,GAAM,EAAE,iBAAiB,CAC3D,EAAqB,EAAe,GAAM,EAAE,mBAAmB,CAC/D,EAAW,GAAa,CAIxB,EAAY,GAAiB,GAEnC,EAAA,EAAA,eAAgB,CACd,GAAI,EAAQ,CACV,EAAe,CAAE,SAAQ,UAAS,CAAC,CACnC,OAEE,GAAU,EAAe,CAAE,WAAU,UAAS,CAAC,EAClD,CAAC,EAAS,EAAW,EAAQ,EAAS,CAAC,CAE1C,IAAM,GAAA,EAAA,EAAA,aAAuB,EAAO,EAAU,EAAK,CAAG,KAAM,CAAC,EAAK,CAAC,CAC7D,GAAA,EAAA,EAAA,aAAyB,IAAI,IAAI,GAAQ,MAAM,IAAK,GAAS,CAAC,EAAK,KAAK,GAAI,EAAK,CAAC,EAAI,EAAE,CAAC,CAAE,CAAC,EAAO,CAAC,CAEpG,GAAA,EAAA,EAAA,aAAuB,CAC3B,GAAI,CAAC,EAAM,MAAO,EAAE,CACpB,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAK,MAAO,EAAO,IAAI,EAAK,QAAS,EAAO,IAAI,EAAK,OAAO,EAAI,GAAK,EAAE,CAC1F,OAAO,EAAa,OAAQ,GAAW,EAAO,IAAI,EAAO,CAAC,CAAC,IAAK,IAAY,CAC1E,SACA,MAAO,EAAO,IAAI,EAAO,EAAI,EAC9B,EAAE,EACF,CAAC,EAAK,CAAC,CAEV,GAAI,CAAC,GAAQ,CAAC,EAAQ,OAAO,KAE7B,IAAM,EAAY,EAAK,MAAM,OACvB,EAAc,EAAO,KAAM,GAAU,EAAM,SAAW,SAAS,EAAE,OAAS,EAG1E,EAAU,GAAG,EAAU,OAAO,IAAc,EAAI,GAAK,MAAM,EAAc,EAAI,MAAM,EAAY,SAAW,KAEhH,OACE,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,gEAAnB,EACE,EAAA,EAAA,MAAC,SAAD,CACE,KAAK,SACL,YAAe,EAAiB,CAAC,EAAU,CAC3C,gBAAe,CAAC,EAChB,aAAY,EAAY,oBAAsB,sBAC9C,UAAW,EACT,mDACA,CAAC,GAAa,OACf,UARH,EAUE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,kFACd,EAAA,EAAA,KAAC,EAAD,CAAW,UAAU,gCAAkC,CAAA,CAClD,CAAA,EACP,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,4EAAoE,EAAK,OAAS,OAAa,CAAA,EAC9G,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,oEACZ,EAAY,EAAW,EAAK,WAAa,EACtC,CAAA,CACF,GACL,EAAO,OAAS,IACf,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wDACZ,EAAO,KAAK,CAAE,SAAQ,YACrB,EAAA,EAAA,MAAC,OAAD,CAAmB,UAAU,qEAA7B,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAG,2BAA4B,EAAa,GAAQ,IAAI,CAAI,CAAA,EAC7E,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAG,2BAA4B,EAAa,GAAQ,KAAK,UAAG,EAAa,CAAA,EAC1F,EAAA,EAAA,KAAC,OAAD,CAAA,SAAO,EAAa,GAAQ,MAAa,CAAA,CACpC,EAJI,EAIJ,CACP,CACE,CAAA,EAER,EAAA,EAAA,MAAC,OAAD,CAAM,UAAU,iHAAhB,CAAwH,IACpH,EAAK,QACF,IACP,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,mIACb,GAAY,EAAA,EAAA,KAAC,EAAD,CAAa,UAAU,cAAgB,CAAA,EAAG,EAAA,EAAA,KAAC,EAAD,CAAW,UAAU,cAAgB,CAAA,CACvF,CAAA,CACA,GACR,EAAY,KAAO,EAAK,MAAM,SAAW,GACxC,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,6GAAoG,kEAE7G,CAAA,EAEN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,kDACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,WAAW,MAAO,CAAE,MAAO,EAAO,MAAO,OAAQ,EAAO,OAAQ,UAA/E,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,uCAAuC,MAAO,EAAO,MAAO,OAAQ,EAAO,OAAQ,cAAY,gBAA9G,EACE,EAAA,EAAA,KAAC,OAAD,CAAA,SACG,EAAa,IAAK,IACjB,EAAA,EAAA,KAAC,SAAD,CAEE,GAAI,cAAc,IAClB,QAAQ,UACR,KAAK,MACL,KAAK,IACL,YAAY,IACZ,aAAa,IACb,OAAO,+BAEP,EAAA,EAAA,KAAC,OAAD,CAAM,EAAE,mBAAmB,KAAM,EAAa,GAAQ,KAAQ,CAAA,CACvD,CAVF,EAUE,CACT,CACG,CAAA,CACN,EAAK,MAAM,IAAK,GAAS,CACxB,IAAM,EAAO,EAAS,IAAI,EAAK,KAAK,CAC9B,EAAK,EAAS,IAAI,EAAK,GAAG,CAChC,GAAI,CAAC,GAAQ,CAAC,EAAI,OAAO,KACzB,IAAM,EAAO,EAAa,EAAK,KAAK,QACpC,OACE,EAAA,EAAA,KAAC,OAAD,CAEE,EAAG,EAAS,EAAM,EAAG,CACrB,OAAQ,EAAK,KACb,cAAe,GACf,YAAa,EACb,KAAK,OACL,cAAc,QACd,UAAW,mBAAmB,EAAK,KAAK,OAAO,GAC/C,CARK,GAAG,EAAK,KAAK,IAAI,EAAK,KAQ3B,EAEJ,CACE,GACL,EAAO,MAAM,KAAK,CAAE,OAAM,IAAG,OAAQ,CACpC,IAAM,EAAS,EAAa,EAAK,QAC3B,EAAQ,EAAW,EAAK,SAAS,CACjC,EAAW,EAAK,MAAM,QAAU,EAAc,EAAK,KAAK,SAAW,KACnE,EAAY,EAAK,MAAM,OAAS,SAAS,EAAK,KAAK,OAAQ,GAAG,CAAG,KACjE,EAAY,GAAa,KAAiE,IAAA,GAA1D,EAAiB,KAAM,GAAM,EAAE,KAAO,EAAU,EAAE,MACxF,OACE,EAAA,EAAA,MAAC,UAAD,CAEE,UAAW,EACT,qGACA,yGACA,EAAO,OACR,CACD,MAAO,CAAE,KAAM,EAAG,IAAK,EAAG,MAAO,EAAQ,OAAQ,EAAQ,CACzD,MAAO,EAAK,YAAc,EAAK,eARjC,EAUE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wEAAgE,EAAK,MAAY,CAAA,EAC9F,EAAK,YAAc,EAAK,MACxB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,oEAA4D,EAAK,YAAc,EAAK,GAAS,CAAA,EAE5G,GAAY,GAAa,QACzB,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,wCAAf,CACG,IAAY,EAAA,EAAA,KAAC,EAAD,CAAwB,WAAU,QAAA,GAAQ,UAAU,aAAe,CAAA,CAC/E,GAAa,OACZ,EAAA,EAAA,KAAC,EAAD,CAAU,GAAI,EAAW,MAAO,EAAW,YAAe,EAAmB,EAAU,CAAE,UAAU,aAAe,CAAA,CAEhH,IAER,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,6DAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,8CAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAG,oCAAqC,EAAO,IAAI,CAAI,CAAA,EACxE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAG,0BAA2B,EAAO,KAAK,UAAG,EAAO,MAAa,CAAA,CAC9E,IACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,6CAAf,CACG,IAAS,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,sDAA8C,EAAa,CAAA,CACpF,EAAK,OACJ,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,2HACb,EAAK,KACD,CAAA,CAEL,GACF,GACE,EAnCH,EAAK,GAmCF,EAEZ,CACE,GACF,CAAA,CAEA,GAKd,SAAgB,EAAkB,CAAE,WAAgC,CAClE,IAAM,EAAqB,EAAe,GAAM,EAAE,mBAAmB,CAC/D,CAAC,EAAc,IAAA,EAAA,EAAA,UAAoC,EAAE,CAAC,CAO5D,OANA,EAAA,EAAA,eAAgB,CACd,EAAmC,MAAO,4BAA8B,mBAAmB,EAAQ,CAAC,CACjG,KAAM,GAAU,EAAgB,EAAM,CAAC,CACvC,UAAY,GAAG,EACjB,CAAC,EAAQ,CAAC,CACT,EAAa,SAAW,EAAU,MAEpC,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,gEAAnB,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,2FAAf,CAAiG,4BACrE,EAAa,OAAO,IAC1C,IACN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,kCACZ,EAAa,IAAK,IACjB,EAAA,EAAA,KAAC,EAAD,CAEE,GAAI,EAAK,GACT,MAAO,EAAK,MACZ,OAAQ,EAAK,OACb,YAAe,EAAmB,EAAK,GAAG,CAC1C,CALK,EAAK,GAKV,CACF,CACE,CAAA,CACE"}
@@ -1,2 +0,0 @@
1
- import"./chunk-CilyBKbf.js";import{$n as e,Zn as t,fr as n}from"./lucide-react-DmbfpRvJ.js";n();var r=e();function i({className:e,size:n=`default`,...i}){return(0,r.jsx)(`div`,{"data-slot":`card`,"data-size":n,className:t(`group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl`,e),...i})}function a({className:e,...n}){return(0,r.jsx)(`div`,{"data-slot":`card-header`,className:t(`group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3`,e),...n})}function o({className:e,...n}){return(0,r.jsx)(`div`,{"data-slot":`card-title`,className:t(`font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm`,e),...n})}function s({className:e,...n}){return(0,r.jsx)(`div`,{"data-slot":`card-description`,className:t(`text-sm text-muted-foreground`,e),...n})}function c({className:e,...n}){return(0,r.jsx)(`div`,{"data-slot":`card-action`,className:t(`col-start-2 row-span-2 row-start-1 self-start justify-self-end`,e),...n})}function l({className:e,...n}){return(0,r.jsx)(`div`,{"data-slot":`card-content`,className:t(`px-4 group-data-[size=sm]/card:px-3`,e),...n})}function u({className:e,...n}){return(0,r.jsx)(`div`,{"data-slot":`card-footer`,className:t(`flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3`,e),...n})}export{u as a,s as i,c as n,a as o,l as r,o as s,i as t};
2
- //# sourceMappingURL=card-B0y1i_2D.js.map