agent-relay-server 0.65.2 → 0.67.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 (110) hide show
  1. package/docs/openapi.json +1 -1
  2. package/package.json +2 -2
  3. package/public/assets/MessageBubble-CG_eCKDI.js +3 -0
  4. package/public/assets/MessageBubble-CG_eCKDI.js.map +1 -0
  5. package/public/assets/{PlanGraphPanel-DrHNFbg6.js → PlanGraphPanel-Ba9qh-if.js} +2 -2
  6. package/public/assets/{PlanGraphPanel-DrHNFbg6.js.map → PlanGraphPanel-Ba9qh-if.js.map} +1 -1
  7. package/public/assets/{activity-CECdsDpd.js → activity-8eZ4FhxO.js} +2 -2
  8. package/public/assets/{activity-CECdsDpd.js.map → activity-8eZ4FhxO.js.map} +1 -1
  9. package/public/assets/{agent-profiles-CHitqihm.js → agent-profiles-1Nx8ROA_.js} +2 -2
  10. package/public/assets/{agent-profiles-CHitqihm.js.map → agent-profiles-1Nx8ROA_.js.map} +1 -1
  11. package/public/assets/{agents-GG-aJj6Z.js → agents-C8fM2VwM.js} +2 -2
  12. package/public/assets/{agents-GG-aJj6Z.js.map → agents-C8fM2VwM.js.map} +1 -1
  13. package/public/assets/{analytics-y0Yf26cD.js → analytics-D6ffu1ji.js} +2 -2
  14. package/public/assets/{analytics-y0Yf26cD.js.map → analytics-D6ffu1ji.js.map} +1 -1
  15. package/public/assets/{automation-CmzftGBn.js → automation-BVmzNi6H.js} +2 -2
  16. package/public/assets/{automation-CmzftGBn.js.map → automation-BVmzNi6H.js.map} +1 -1
  17. package/public/assets/{branch-state-badge-Biam17QK.js → branch-state-badge-DrwCnoKR.js} +2 -2
  18. package/public/assets/{branch-state-badge-Biam17QK.js.map → branch-state-badge-DrwCnoKR.js.map} +1 -1
  19. package/public/assets/{channels-CmAXppQu.js → channels-BuqbbyaO.js} +2 -2
  20. package/public/assets/{channels-CmAXppQu.js.map → channels-BuqbbyaO.js.map} +1 -1
  21. package/public/assets/chat-DCnEGe-x.js +2 -0
  22. package/public/assets/chat-DCnEGe-x.js.map +1 -0
  23. package/public/assets/{connectors-bZ0YsSqg.js → connectors-_LpoKQNb.js} +2 -2
  24. package/public/assets/{connectors-bZ0YsSqg.js.map → connectors-_LpoKQNb.js.map} +1 -1
  25. package/public/assets/formatted-body-impl-C7ftpr0y.js +3 -0
  26. package/public/assets/formatted-body-impl-C7ftpr0y.js.map +1 -0
  27. package/public/assets/index-eCpWfoCA.css +2 -0
  28. package/public/assets/{index-BSWui_-2.js → index-ksV0Snw6.js} +10 -10
  29. package/public/assets/index-ksV0Snw6.js.map +1 -0
  30. package/public/assets/{insights-cC2lVGUs.js → insights-BjRehGVP.js} +2 -2
  31. package/public/assets/{insights-cC2lVGUs.js.map → insights-BjRehGVP.js.map} +1 -1
  32. package/public/assets/{integrations--k7_eYP2.js → integrations-DCyxAv8c.js} +2 -2
  33. package/public/assets/{integrations--k7_eYP2.js.map → integrations-DCyxAv8c.js.map} +1 -1
  34. package/public/assets/{maintenance-B6wOij_l.js → maintenance-CKiNcUMS.js} +2 -2
  35. package/public/assets/{maintenance-B6wOij_l.js.map → maintenance-CKiNcUMS.js.map} +1 -1
  36. package/public/assets/{managed-agents-CDzLSKp1.js → managed-agents-Os_T-7w7.js} +2 -2
  37. package/public/assets/{managed-agents-CDzLSKp1.js.map → managed-agents-Os_T-7w7.js.map} +1 -1
  38. package/public/assets/{markdown-preview-impl-D3Y4uUgk.js → markdown-preview-impl-grkpBldu.js} +2 -2
  39. package/public/assets/{markdown-preview-impl-D3Y4uUgk.js.map → markdown-preview-impl-grkpBldu.js.map} +1 -1
  40. package/public/assets/{memory-DYzw5EXn.js → memory-YiYlqWUZ.js} +2 -2
  41. package/public/assets/{memory-DYzw5EXn.js.map → memory-YiYlqWUZ.js.map} +1 -1
  42. package/public/assets/{messages-ATbJw7jy.js → messages-CVDtrrub.js} +2 -2
  43. package/public/assets/messages-CVDtrrub.js.map +1 -0
  44. package/public/assets/orchestrators-Dzup-DDB.js +2 -0
  45. package/public/assets/{orchestrators-Dtr4zNWI.js.map → orchestrators-Dzup-DDB.js.map} +1 -1
  46. package/public/assets/{overview-B071A7FM.js → overview-DZltfAFn.js} +2 -2
  47. package/public/assets/{overview-B071A7FM.js.map → overview-DZltfAFn.js.map} +1 -1
  48. package/public/assets/{pairs-DgiNK9mA.js → pairs-Q2CmriBh.js} +2 -2
  49. package/public/assets/{pairs-DgiNK9mA.js.map → pairs-Q2CmriBh.js.map} +1 -1
  50. package/public/assets/{projects-DhQUdwcb.js → projects-DtJmrhI0.js} +2 -2
  51. package/public/assets/projects-DtJmrhI0.js.map +1 -0
  52. package/public/assets/{security-COHkbWIm.js → security-Bur19Sp4.js} +2 -2
  53. package/public/assets/{security-COHkbWIm.js.map → security-Bur19Sp4.js.map} +1 -1
  54. package/public/assets/{select-CKPIes_u.js → select-CuzWJuBz.js} +2 -2
  55. package/public/assets/{select-CKPIes_u.js.map → select-CuzWJuBz.js.map} +1 -1
  56. package/public/assets/settings-CEMCJ31_.js +4 -0
  57. package/public/assets/settings-CEMCJ31_.js.map +1 -0
  58. package/public/assets/store-BeKcuJ2q.js +9 -0
  59. package/public/assets/store-BeKcuJ2q.js.map +1 -0
  60. package/public/assets/{tasks-DdVsKCUN.js → tasks-DjwAusKz.js} +2 -2
  61. package/public/assets/{tasks-DdVsKCUN.js.map → tasks-DjwAusKz.js.map} +1 -1
  62. package/public/assets/{teams-BLQeR-qJ.js → teams-CFCnB12u.js} +2 -2
  63. package/public/assets/{teams-BLQeR-qJ.js.map → teams-CFCnB12u.js.map} +1 -1
  64. package/public/assets/{terminal-viewer-impl-eFq9PBWV.js → terminal-viewer-impl-CWu5RTp2.js} +2 -2
  65. package/public/assets/{terminal-viewer-impl-eFq9PBWV.js.map → terminal-viewer-impl-CWu5RTp2.js.map} +1 -1
  66. package/public/assets/{work-queue-OFw-Hwir.js → work-queue-TZQ5Gz0t.js} +2 -2
  67. package/public/assets/{work-queue-OFw-Hwir.js.map → work-queue-TZQ5Gz0t.js.map} +1 -1
  68. package/public/assets/{workspaces-zum4lO_O.js → workspaces-Bu4uVUcu.js} +2 -2
  69. package/public/assets/{workspaces-zum4lO_O.js.map → workspaces-Bu4uVUcu.js.map} +1 -1
  70. package/public/index.html +3 -3
  71. package/src/agent-issue-repo.ts +29 -0
  72. package/src/branch-landed.ts +69 -2
  73. package/src/cli/index.ts +6 -4
  74. package/src/config.ts +1 -0
  75. package/src/context-advisory.ts +93 -15
  76. package/src/context-threshold-config.ts +14 -2
  77. package/src/db/migrations.ts +24 -0
  78. package/src/db/projects.ts +34 -6
  79. package/src/db/schema.ts +1 -0
  80. package/src/mcp/tools-workspace.ts +3 -3
  81. package/src/mcp-project-tools.ts +2 -0
  82. package/src/notification-router.ts +2 -0
  83. package/src/provider-catalog-store.ts +35 -0
  84. package/src/routes/agents.ts +3 -2
  85. package/src/routes/commands.ts +6 -1
  86. package/src/routes/provider-config.ts +27 -0
  87. package/src/services/git-remote.ts +46 -0
  88. package/src/services/issue-lifecycle.ts +5 -36
  89. package/src/services/project.ts +23 -3
  90. package/src/services/register-agent.ts +7 -1
  91. package/src/services/spawn-agent.ts +7 -9
  92. package/src/services/spawn-registration-watchdog.ts +34 -12
  93. package/src/settings/registry.ts +2 -0
  94. package/src/sse.ts +9 -4
  95. package/src/workspace-phase.ts +17 -9
  96. package/public/assets/MessageBubble-DLF9fJLb.js +0 -2
  97. package/public/assets/MessageBubble-DLF9fJLb.js.map +0 -1
  98. package/public/assets/chat-C-FI9bLO.js +0 -2
  99. package/public/assets/chat-C-FI9bLO.js.map +0 -1
  100. package/public/assets/formatted-body-impl-D--5zVSd.js +0 -3
  101. package/public/assets/formatted-body-impl-D--5zVSd.js.map +0 -1
  102. package/public/assets/index-BSWui_-2.js.map +0 -1
  103. package/public/assets/index-B_On3Osd.css +0 -2
  104. package/public/assets/messages-ATbJw7jy.js.map +0 -1
  105. package/public/assets/orchestrators-Dtr4zNWI.js +0 -2
  106. package/public/assets/projects-DhQUdwcb.js.map +0 -1
  107. package/public/assets/settings-B4SN1TpB.js +0 -4
  108. package/public/assets/settings-B4SN1TpB.js.map +0 -1
  109. package/public/assets/store-DnHOGovN.js +0 -9
  110. package/public/assets/store-DnHOGovN.js.map +0 -1
@@ -10,6 +10,11 @@ import { getIssueRef, resolveIssueRefByExternalKey, resolveIssueRefFromString, u
10
10
  import { associateIssue } from "../db/issue-associations";
11
11
  import { resolveIssueTrackerAdapter } from "../issue-tracker";
12
12
  import { defaultIssueRepo } from "../config";
13
+ // `repoFromGitRemote` / `parseOwnerRepoFromRemote` live in the shared ./git-remote module
14
+ // (#533) so project auto-seed reuses the exact same logic. Re-exported so this module's
15
+ // existing importers and tests keep their entry point.
16
+ import { parseOwnerRepoFromRemote, repoFromGitRemote, __resetRemoteRepoCacheForTests } from "./git-remote";
17
+ export { parseOwnerRepoFromRemote, repoFromGitRemote, __resetRemoteRepoCacheForTests };
13
18
  import type { IssueTrackerAdapter } from "../issue-tracker";
14
19
  import { recordAndEmitIssueActivity } from "./issue-activity";
15
20
  import type { IssueAssociationEntityType, IssueProvider, IssueRef, WorkspaceRecord } from "../types";
@@ -80,42 +85,6 @@ function logFailure(opts: IssueLifecycleOptions, message: string): void {
80
85
  else console.warn(message);
81
86
  }
82
87
 
83
- /**
84
- * `owner/repo` out of any git remote URL form: `git@github.com:owner/repo.git`,
85
- * `https://github.com/owner/repo.git`, `ssh://git@host/owner/repo`, trailing slash/`.git`
86
- * optional. Pure — exported for tests.
87
- */
88
- export function parseOwnerRepoFromRemote(url: string | undefined): string | undefined {
89
- if (!url) return undefined;
90
- const match = url.trim().match(/[:/]([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+?)(?:\.git)?\/?$/);
91
- return match?.[1];
92
- }
93
-
94
- let remoteRepoCache: Map<string, string | undefined> | undefined;
95
-
96
- function repoFromGitRemote(repoRoot: string | undefined): string | undefined {
97
- if (!repoRoot) return undefined;
98
- if (!remoteRepoCache) remoteRepoCache = new Map();
99
- if (remoteRepoCache.has(repoRoot)) return remoteRepoCache.get(repoRoot);
100
- let repo: string | undefined;
101
- try {
102
- const proc = Bun.spawnSync(["git", "-C", repoRoot, "remote", "get-url", "origin"], {
103
- stdin: "ignore",
104
- stdout: "pipe",
105
- stderr: "ignore",
106
- });
107
- if (proc.exitCode === 0) repo = parseOwnerRepoFromRemote(Buffer.from(proc.stdout).toString("utf8"));
108
- } catch {
109
- repo = undefined;
110
- }
111
- remoteRepoCache.set(repoRoot, repo);
112
- return repo;
113
- }
114
-
115
- export function __resetRemoteRepoCacheForTests(): void {
116
- remoteRepoCache = undefined;
117
- }
118
-
119
88
  /**
120
89
  * The repo a bare `#NNN` in a land's commit subject resolves against. Derived per-workspace
121
90
  * from its own git remote so a single relay serving many repos closes the RIGHT repo's issue;
@@ -1,7 +1,8 @@
1
1
  import { statSync } from "node:fs";
2
2
  import { basename, dirname, join, resolve } from "node:path";
3
- import { addProjectRoot, ensureProject, resolveProjectForCwd, rootsForProject } from "../db";
3
+ import { addProjectRoot, ensureProject, resolveProjectForCwd, rootsForProject, setProjectIssueRepo } from "../db";
4
4
  import { ingestClaudeMd } from "../project-ingest";
5
+ import { repoFromGitRemote } from "./git-remote";
5
6
  import type { Project, ProjectRoot } from "../types";
6
7
 
7
8
  interface EnsureProjectRootInput {
@@ -10,6 +11,8 @@ interface EnsureProjectRootInput {
10
11
  title?: string;
11
12
  description?: string;
12
13
  tenantId?: string;
14
+ /** Explicit `owner/repo` override (#533); wins over the git-remote-derived default. */
15
+ issueRepo?: string;
13
16
  }
14
17
 
15
18
  interface EnsureProjectRootResult {
@@ -33,8 +36,19 @@ export function ensureProjectRoot(input: EnsureProjectRootInput): EnsureProjectR
33
36
  ...(input.title !== undefined ? { title: input.title } : {}),
34
37
  ...(input.description !== undefined ? { description: input.description } : {}),
35
38
  ...(input.tenantId !== undefined ? { tenantId: input.tenantId } : {}),
39
+ ...(input.issueRepo !== undefined ? { issueRepo: input.issueRepo } : {}),
36
40
  });
37
- return { project, roots: addProjectRoot(project.id, input.rootPath) };
41
+ const roots = addProjectRoot(project.id, input.rootPath);
42
+ // Auto-derive issueRepo from the root's git remote (#533) when not explicitly provided.
43
+ // `onlyIfNull` ensures an explicit override (or earlier derivation) is never clobbered.
44
+ if (input.issueRepo === undefined && !project.issueRepo) {
45
+ const derived = repoFromGitRemote(input.rootPath);
46
+ if (derived) {
47
+ const updated = setProjectIssueRepo(project.id, derived, { onlyIfNull: true });
48
+ if (updated) return { project: updated, roots };
49
+ }
50
+ }
51
+ return { project, roots };
38
52
  }
39
53
 
40
54
  export function ingestProjectClaudeMd(projectId: string, authorId: string): ClaudeMdIngestResult {
@@ -72,7 +86,13 @@ export function autoSeedProjectForCwd(cwd: string, authorId: string): AutoSeedPr
72
86
  const existing = resolveProjectForCwd(cwd);
73
87
  if (existing) {
74
88
  const repoRoot = findGitRepoRoot(cwd) ?? cwd;
75
- return { project: existing, repoRoot, roots: rootsForProject(existing.id) };
89
+ let project = existing;
90
+ if (!existing.issueRepo) {
91
+ const derived = repoFromGitRemote(repoRoot);
92
+ const updated = derived ? setProjectIssueRepo(existing.id, derived, { onlyIfNull: true }) : null;
93
+ if (updated) project = updated;
94
+ }
95
+ return { project, repoRoot, roots: rootsForProject(existing.id) };
76
96
  }
77
97
 
78
98
  const repoRoot = findGitRepoRoot(cwd);
@@ -62,6 +62,7 @@ export function registerAgent(input: RegisterAgentInput, ctx: AuthContext): Agen
62
62
  // #413 — a spawned worker with a report-back contract gets a pending reply obligation to its
63
63
  // spawner so it can't idle with its verdict undelivered (vent #121). First-registration only.
64
64
  const spawnRequestId = metaStr(agent.meta, "spawnRequestId");
65
+ const provider = metaStr(agent.meta, "provider");
65
66
  const promptMirror = seedSpawnPromptMirror(agent.id, spawnRequestId);
66
67
  if (promptMirror?.created || promptMirror?.updated) emitNewMessage(promptMirror.message);
67
68
  seedSpawnReplyObligation(agent.id, agent.spawnedBy, spawnRequestId);
@@ -74,7 +75,12 @@ export function registerAgent(input: RegisterAgentInput, ctx: AuthContext): Agen
74
75
  icon: "ti-robot",
75
76
  view: "agents",
76
77
  agentId: agent.id,
77
- metadata: { actor: ctx.actor.id, actorKind: ctx.actor.kind },
78
+ metadata: {
79
+ actor: ctx.actor.id,
80
+ actorKind: ctx.actor.kind,
81
+ ...(spawnRequestId ? { spawnRequestId } : {}),
82
+ ...(provider ? { provider } : {}),
83
+ },
78
84
  });
79
85
  }
80
86
 
@@ -208,16 +208,14 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
208
208
  // Stamped on the child token's constraints (identity-only, like teamId) so callerProject(auth)
209
209
  // resolves it. Absent (graceful) when the cwd is inside no registered root.
210
210
  let callerProject = resolveProjectForCwd(resolvedCwd);
211
- if (!callerProject) {
212
- try {
213
- const seeded = autoSeedProjectForCwd(resolvedCwd, requestedBy);
214
- callerProject = seeded?.project ?? null;
215
- if (seeded?.ingestError) {
216
- console.warn(`project auto-seed failed to ingest CLAUDE.md for ${resolvedCwd}: ${seeded.ingestError.message}`);
217
- }
218
- } catch (err) {
219
- console.warn(`project auto-seed skipped for ${resolvedCwd}: ${errMessage(err)}`);
211
+ try {
212
+ const seeded = autoSeedProjectForCwd(resolvedCwd, requestedBy);
213
+ callerProject = seeded?.project ?? callerProject;
214
+ if (seeded?.ingestError) {
215
+ console.warn(`project auto-seed failed to ingest CLAUDE.md for ${resolvedCwd}: ${seeded.ingestError.message}`);
220
216
  }
217
+ } catch (err) {
218
+ if (!callerProject) console.warn(`project auto-seed skipped for ${resolvedCwd}: ${errMessage(err)}`);
221
219
  }
222
220
 
223
221
  // #409 + #463 — one composition home for the prompt material handed to providers.
@@ -1,7 +1,7 @@
1
1
  import { isRecord } from "agent-relay-sdk";
2
2
  import { emitCommandEvent } from "../command-events";
3
3
  import { updateCommand } from "../commands-db";
4
- import { SPAWN_REGISTRATION_DEADLINE_MS } from "../config";
4
+ import { SPAWN_REGISTRATION_DEADLINE_MS, SPAWN_REGISTRATION_NOTIFY_MAX_AGE_MS } from "../config";
5
5
  import { getDb } from "../db";
6
6
  import { notifyAgentSpawnFailed } from "../agent-lifecycle-events";
7
7
 
@@ -9,19 +9,24 @@ interface SpawnCommandRow {
9
9
  id: string;
10
10
  params: string;
11
11
  correlation_id: string | null;
12
+ created_at: number;
12
13
  }
13
14
 
14
15
  interface SpawnRegistrationWatchdogResult extends Record<string, unknown> {
15
16
  failedSpawnCommandIds: string[];
17
+ notifiedSpawnCommandIds: string[];
18
+ silencedSpawnCommandIds: string[];
16
19
  }
17
20
 
18
21
  export function reapUnregisteredSpawnCommands(
19
22
  now = Date.now(),
20
23
  deadlineMs = SPAWN_REGISTRATION_DEADLINE_MS,
24
+ notifyMaxAgeMs = SPAWN_REGISTRATION_NOTIFY_MAX_AGE_MS,
21
25
  ): SpawnRegistrationWatchdogResult {
22
26
  const cutoff = now - deadlineMs;
27
+ const notifyCutoff = now - notifyMaxAgeMs;
23
28
  const rows = getDb().query(`
24
- SELECT id, params, correlation_id
29
+ SELECT id, params, correlation_id, created_at
25
30
  FROM commands
26
31
  WHERE type = 'agent.spawn'
27
32
  AND status = 'succeeded'
@@ -30,37 +35,54 @@ export function reapUnregisteredSpawnCommands(
30
35
  `).all(cutoff) as SpawnCommandRow[];
31
36
 
32
37
  const failedSpawnCommandIds: string[] = [];
38
+ const notifiedSpawnCommandIds: string[] = [];
39
+ const silencedSpawnCommandIds: string[] = [];
33
40
  for (const row of rows) {
34
41
  const params = parseParams(row.params);
35
42
  const spawnRequestId = stringParam(params, "spawnRequestId") ?? row.correlation_id ?? undefined;
36
43
  const parent = stringParam(params, "spawnedBy");
37
44
  if (!spawnRequestId || !parent) continue;
38
- if (hasRegisteredAgent(spawnRequestId)) continue;
45
+ if (hasEverRegisteredAgent(spawnRequestId)) continue;
39
46
 
40
47
  const reason = `spawned agent did not register within ${deadlineMs}ms`;
41
48
  const failed = updateCommand(row.id, { status: "failed", error: reason });
42
49
  if (!failed || failed.status !== "failed") continue;
43
50
  failedSpawnCommandIds.push(failed.id);
44
- notifyAgentSpawnFailed({
45
- parent,
46
- spawnRequestId,
47
- provider: stringParam(params, "provider"),
48
- reason,
49
- });
51
+ if (row.created_at >= notifyCutoff) {
52
+ notifiedSpawnCommandIds.push(failed.id);
53
+ notifyAgentSpawnFailed({
54
+ parent,
55
+ spawnRequestId,
56
+ provider: stringParam(params, "provider"),
57
+ reason,
58
+ });
59
+ } else {
60
+ silencedSpawnCommandIds.push(failed.id);
61
+ }
50
62
  emitCommandEvent(failed, "command.failed");
51
63
  }
52
64
 
53
- return { failedSpawnCommandIds };
65
+ return { failedSpawnCommandIds, notifiedSpawnCommandIds, silencedSpawnCommandIds };
54
66
  }
55
67
 
56
- function hasRegisteredAgent(spawnRequestId: string): boolean {
68
+ function hasEverRegisteredAgent(spawnRequestId: string): boolean {
57
69
  const row = getDb().query(`
58
70
  SELECT 1
59
71
  FROM agents
60
72
  WHERE json_extract(meta, '$.spawnRequestId') = ?
61
73
  LIMIT 1
62
74
  `).get(spawnRequestId);
63
- return Boolean(row);
75
+ if (row) return true;
76
+
77
+ const registration = getDb().query(`
78
+ SELECT 1
79
+ FROM activity_events
80
+ WHERE kind = 'state'
81
+ AND title = 'Agent registered'
82
+ AND json_extract(metadata, '$.spawnRequestId') = ?
83
+ LIMIT 1
84
+ `).get(spawnRequestId);
85
+ return Boolean(registration);
64
86
  }
65
87
 
66
88
  function parseParams(raw: string): Record<string, unknown> {
@@ -181,6 +181,8 @@ const CONTEXT_THRESHOLD_SCHEMA: JSONSchema = {
181
181
  properties: {
182
182
  enabled: { type: "boolean" },
183
183
  advisoryUtilization: { type: "number", minimum: 0, maximum: 1 },
184
+ selfCompactUtilization: { type: "number", minimum: 0, maximum: 1 },
185
+ warnUtilization: { type: "number", minimum: 0, maximum: 1 },
184
186
  hardBackstopUtilization: { type: "number", minimum: 0, maximum: 1 },
185
187
  bandSize: { type: "number", minimum: 0, maximum: 1 },
186
188
  },
package/src/sse.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { getAgent, getOrchestrator, onWorkspaceChange } from "./db";
1
+ import { getAgent, getOrchestrator, matchingDeliveryAgents, onWorkspaceChange } from "./db";
2
2
  import { attachBranchState } from "./agent-branch-state";
3
+ import { attachIssueRepo } from "./agent-issue-repo";
3
4
  import { emitRelayEvent, subscribeRelayEvents, type RelayEvent } from "./events";
4
5
  import { messageMatchesAgent, targetMatchesAgent } from "./agent-ref";
5
6
  import type { ActivityEvent, AgentCard, Message, RelayNotification, Task } from "./types";
@@ -85,11 +86,15 @@ function fanout(event: RelayEvent): void {
85
86
  }
86
87
 
87
88
  function sendNewMessage(msg: Message): void {
89
+ const scopedBroadcastAgentIds = msg.to === "broadcast"
90
+ ? new Set(matchingDeliveryAgents("broadcast", { from: msg.from, channel: msg.channel }).map((agent) => agent.id))
91
+ : null;
88
92
  for (const conn of connections.values()) {
89
93
  if (!conn.agentId) {
90
94
  send(conn, "message.new", msg);
91
95
  continue;
92
96
  }
97
+ if (scopedBroadcastAgentIds && !scopedBroadcastAgentIds.has(conn.agentId)) continue;
93
98
  if (!messageMatchesAgent(msg, conn.agentId, getAgent(conn.agentId))) continue;
94
99
  send(conn, "message.new", msg);
95
100
  }
@@ -103,9 +108,9 @@ export function emitNewMessage(msg: Message) {
103
108
 
104
109
  export function emitAgentStatus(agentId: string) {
105
110
  const agent = getAgent(agentId);
106
- // Enrich with the branch-state badge fields (#236) so the dashboard's live agent
107
- // updates carry the same projection as GET /api/agents.
108
- const data = agent ? attachBranchState(agent) : { id: agentId, status: "offline" };
111
+ // Enrich with the branch-state badge fields (#236) and the resolved issueRepo (#533) so
112
+ // the dashboard's live agent updates carry the same projection as GET /api/agents.
113
+ const data = agent ? attachIssueRepo(attachBranchState(agent)) : { id: agentId, status: "offline" };
109
114
  emitRelayEvent({ type: "agent.status", source: "server", subject: agentId, data: data as unknown as Record<string, unknown> });
110
115
  const notification = agent ? notificationForAgentStatus(agent) : undefined;
111
116
  if (notification) emitNotificationCreated(notification);
@@ -11,7 +11,7 @@
11
11
  // dragging in db/sse/merge — the server graph stays out of the client.
12
12
  //
13
13
  // The load-bearing decision: `ready` and `review_requested` collapse to the SAME
14
- // "handed off, healthy, wait" guidance, and `actionNeeded:false` is the explicit
14
+ // "handed off, healthy, stop" guidance, and `actionNeeded:false` is the explicit
15
15
  // anti-panic signal.
16
16
 
17
17
  import { TERMINAL_WORKSPACE_STATUS_VALUES } from "agent-relay-sdk";
@@ -118,6 +118,12 @@ const WAIT_ACTION: WorkspaceNextAction = {
118
118
  when: "to block until your branch lands (returns when the status changes)",
119
119
  };
120
120
 
121
+ const CHECK_STATUS_ACTION: WorkspaceNextAction = {
122
+ tool: "relay_workspace_status",
123
+ cli: "agent-relay workspace status",
124
+ when: "only if you are explicitly checking state later; do not poll or wait after marking ready",
125
+ };
126
+
121
127
  const READY_ACTION: WorkspaceNextAction = {
122
128
  tool: "relay_workspace_ready",
123
129
  cli: "agent-relay workspace ready",
@@ -150,9 +156,10 @@ export function describeWorkspacePhase(
150
156
  };
151
157
  case "ready":
152
158
  case "review_requested": {
153
- // The #235 crux: these are the SAME healthy "handed off, waiting" state.
159
+ // The #235/#538 crux: these are the SAME healthy "handed off, stop now" state.
154
160
  // `review_requested` reads like an escalation but is the normal post-ready
155
- // node; an absent steward is the healthy case, not a stall.
161
+ // node; an absent steward is the healthy case, not a stall. The land result
162
+ // now wakes the worker via landed-success/landed-failure instead of polling.
156
163
  const now = opts.now ?? Date.now();
157
164
  const stallMs = opts.stallMs ?? LAND_PENDING_STALL_MS;
158
165
  const pendingMs = typeof workspace.readyAt === "number" ? now - workspace.readyAt : undefined;
@@ -185,10 +192,10 @@ export function describeWorkspacePhase(
185
192
  }
186
193
  return {
187
194
  phase: "land-pending",
188
- headline: "Handed off — waiting for the auto-merge to land your branch. This is the normal, healthy post-ready state (not an escalation).",
189
- hint: "No action needed. Relay auto-merges clean rebases roughly every 2 minutes; a steward agent is spawned only if it can't land deterministically so no steward visible means it's healthy, not stuck. Wait. Do NOT merge, push, resolve anything, or touch the main checkout.",
195
+ headline: "Handed off — stop this turn and go idle while Relay lands your branch. This is the normal, healthy post-ready state (not an escalation).",
196
+ hint: "No action needed. Stop your turn now; do not poll or wait on the steward queue. Relay will wake you with a `landed-success` notification when the merge lands and your branch is refreshed, or `landed-failure` if landing fatally fails. Do NOT merge, push, resolve anything, or touch the main checkout.",
190
197
  actionNeeded: false,
191
- nextActions: [WAIT_ACTION],
198
+ nextActions: [CHECK_STATUS_ACTION],
192
199
  blockers: [],
193
200
  };
194
201
  }
@@ -302,8 +309,9 @@ export function readyContract(workspace: Pick<WorkspaceRecord, "status">): strin
302
309
  return [
303
310
  `Marked ready. Status is now \`${workspace.status}\` — this is the normal, healthy hand-off state, not an escalation.`,
304
311
  "Relay auto-merges clean rebases roughly every 2 minutes. A steward agent is spawned (after a short delay) ONLY if it can't land deterministically — so no steward appearing means it's working, not stuck.",
305
- "Wait with `relay_workspace_status wait:true` (or `agent-relay workspace status --wait`) it returns the moment your branch lands.",
306
- "On landing you'll be moved onto a fresh rebased branch (its name gains a `--N` suffix expected). Keep working there.",
312
+ "STOP this turn now and go idle. Do not call `relay_workspace_status wait:true`, `agent-relay workspace status --wait`, or any polling loop after marking ready.",
313
+ "Relay will wake you with `landed-success` when the merge lands and your branch is refreshed, or `landed-failure` if landing fatally fails.",
314
+ "On `landed-success` you'll be on a fresh rebased branch (its name gains a `--N` suffix — expected). Keep working there.",
307
315
  "Do NOT merge, push, rebase, resolve conflicts, or `cd` into the main checkout — Relay (and the steward) own all of that.",
308
316
  ].join("\n");
309
317
  }
@@ -321,7 +329,7 @@ export function worktreeMcpInstructions(workspace: Pick<WorkspaceRecord, "branch
321
329
  `You are in an isolated git worktree on branch ${branch}, based on ${base} — NOT the main checkout. ${base} moves under you as other agents land in parallel; that's expected.`,
322
330
  "Changes reach the base via: commit your work, then call `relay_workspace_ready`. Relay rebases onto the latest base, lands, and pushes for you.",
323
331
  "Do NOT push, rebase, merge, resolve conflicts, or `cd` into the main checkout — Relay (and a steward, spawned only if a clean auto-merge isn't possible) own all of that.",
324
- "After `ready` the status is `ready` (a normal, healthy hand-off state, not a stall). Call `relay_workspace_status` with `wait:true` to block until your branch lands; you'll then continue on a fresh rebased branch (name gains a `--N` suffix).",
332
+ "After `ready` the status is `ready` (a normal, healthy hand-off state, not a stall). Stop your turn and go idle; Relay wakes you with `landed-success` when your branch lands and refreshes, or `landed-failure` if landing fatally fails.",
325
333
  "Call `relay_workspace_status` anytime to see where you are and the exact next step.",
326
334
  ].join("\n");
327
335
  }
@@ -1,2 +0,0 @@
1
- import{r as e}from"./chunk-CilyBKbf.js";import{An as t,Bn as n,Ct as r,F as i,Hn as a,Pt as o,Qn as s,Qt as c,R as l,Rn as u,St as d,Wt as f,at as p,b as m,bn as h,c as g,cn as _,ct as v,fn as y,h as b,i as x,jn as S,ln as C,mn as w,nn as T,p as E,pn as D,r as O,tn as k,un as A,y as ee,z as j}from"./lucide-react-BbMYCUlW.js";import{h as M,r as N,t as P}from"./store-DnHOGovN.js";import{D as F,I as te,M as ne,W as I,at as L,b as re,d as ie,f as ae,j as R,w as z,z as oe}from"./display-LAWaAboe.js";import{C as se,a as ce,i as le,o as ue,t as B}from"./index-BSWui_-2.js";var V=e(s(),1),H={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`},de=new Set(Object.keys(H)),fe=3e3;function U(e){return new Date(e.occurredAt??e.createdAt).getTime()}function pe(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:U(e),turnId:typeof t.turnId==`string`?t.turnId:void 0}}function me(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:U(e)}}function W(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 G(e){return e.kind===`system`&&e.from===`system`}var he=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 ge(e){let t=e.filter(e=>de.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)<=fe)||n.push(e);return n}function _e(e,t,n,r=[],i){let a=[];for(let e of r){let t=e.entries.reduce((e,t)=>Math.min(e,I(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:I(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`||G(t)||z(t)||!(t.from===`user`||o!==void 0&&t.from===o)||!F(t).trim())continue;let e=U(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=>W(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=W(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)&&oe(e,r.body)){p.add(r.id);break}}}let m=new Map,h=[];for(let t of e){if(G(t)){let e=typeof t.payload?.kind==`string`?t.payload.kind:``;if(he.has(e)){let n=t.payload,r=typeof n.agentId==`string`?n.agentId:``,i=U(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:U(t),entry:{type:`notice`,msg:t}});continue}let e=me(t);if(e){h.push(e);continue}let n=pe(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}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:U(t),entry:{type:`message`,msg:{...t,body:e}}});continue}}}let r=t.id===s?`initial-prompt`:`message`;a.push({ts:U(t),entry:{type:r,msg:t}})}for(let e of ge([...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,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`&&ve(e,t)){e.steps.push(...t.steps);continue}}_.push(t)}return _}function ve(e,t){let n=e.steps[e.steps.length-1]?.turnId,r=t.steps[0]?.turnId;return n&&r?n===r:!n&&!r}function ye(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function be(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 xe(e){let t=e.replace(/\/+$/,``),n=t.lastIndexOf(`/`);return n>0?t.slice(0,n):`/`}function Se(e,t){return e.filter(e=>e.status===`online`&&te(t,e.baseDir)).sort((e,t)=>R(t.baseDir).length-R(e.baseDir).length)[0]||e.find(e=>e.status===`online`)}function Ce(){return typeof window<`u`&&window.matchMedia(`(min-width: 1280px)`).matches}function q(){return typeof window<`u`&&!!window.getSelection()?.toString()}function we(e){let t=e.payload?.attachments;return Array.isArray(t)?t.filter(e=>!!(e&&typeof e==`object`&&typeof e.artifactId==`string`)):[]}var Te=[`👍`,`❤️`,`✅`,`👀`];function Ee(e){let t=new Map;for(let n of e.reactions||[]){let e=ne(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 J(e){return z(e)}function De(e,t){let n=e.readBy||[],r=e.resolvedToAgent||t||e.to,i=r?n.includes(r):!1,a=n.some(e=>e!==L);if(i||a){let e=i?r:n.find(e=>e!==L);return{label:`read`,title:e?`Read by ${e}`:`Read by agent`,tone:`ok`,icon:w}}if(e.deliveryStatus===`delivered`)return{label:`delivered`,title:`Delivered to agent inbox`,tone:`ok`,icon:w};if(e.deliveryStatus===`queued`)return{label:`queued`,title:`Queued until the target agent is available`,tone:`warn`,icon:c};if(e.deliveryStatus===`failed`||e.deliveryStatus===`dead`){let t=e.deliveryPoisonReason||e.deliveryLastError||e.deliveryStatus;return{label:e.deliveryStatus,title:t,tone:`danger`,icon:_}}return{label:`sent`,title:`Accepted by Relay`,tone:`muted`,icon:D}}function Oe(e){let t=I(e.createdAt);return(e.reactions||[]).reduce((e,t)=>Math.max(e,I(t.updatedAt||t.createdAt)),t)}function ke(e){return e?e.messages.reduce((e,t)=>Math.max(e,Oe(t)),0):0}function Ae(e){if(!e)return 0;let t=0;for(let n of e.messages)re(n)&&(t=Math.max(t,I(n.createdAt)));return t}function Y(e){return new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`})}function je(e){for(let t of e)t.previewUrl&&URL.revokeObjectURL(t.previewUrl)}function Me(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[N(e.threadId,e.channel)])??a[0];return o?.threadId?{threadId:o.threadId,...o.channel?{channel:o.channel}:{}}:null}var X=n(),Ne={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 Pe(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 Fe({event:e}){return(0,X.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,X.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,X.jsx)(k,{className:u(`w-2 h-2 fill-current`,Ne[e.status]||`text-zinc-400`)}),(0,X.jsx)(`span`,{children:H[e.status]||e.status}),(0,X.jsx)(`span`,{className:`text-muted-foreground/60`,children:Y(e.timestamp)})]}),(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}var Ie={"branch.landed":d,"context.warning":E,"agent.context_threshold":E,"agent.resume_budget_exhausted":E,"agent.rate_limit_resume":j},Le={"branch.landed":`branch landed`,"context.warning":`context warning`,"agent.context_threshold":`context threshold reached`};function Re(e){return e&&(e.includes(`.`)?e.slice(e.indexOf(`.`)+1):e).replace(/[._-]+/g,` `).trim()||`system signal`}function Z({agentId:e,fallbackLabel:t,className:n}){let r=P(t=>t.agentsById[e])||null,i=P(e=>e.openInboxThread),a=P(e=>e.switchView),o=r?ie(r):t||e;return(0,X.jsxs)(`button`,{type:`button`,className:u(`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(),i(e),a(`chat`)},title:`Open chat for ${o}`,children:[(0,X.jsx)(se,{agent:r,className:`w-4 h-4 text-[10px]`}),(0,X.jsx)(`span`,{className:`max-w-[160px] truncate`,children:o})]})}function ze({msg:e}){let t=e.payload??{},n=typeof t.sha==`string`?t.sha:``,r=n?n.slice(0,7):``,i=typeof t.author==`string`?t.author:``,a=typeof t.branch==`string`?t.branch:``,o=typeof t.base==`string`?t.base:``,s=t.pushed;return(0,X.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,X.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-500/25 bg-emerald-500/10 px-2.5 py-1 text-xs text-emerald-300/90`,children:[(0,X.jsx)(d,{className:`h-3 w-3 shrink-0 text-emerald-400`}),(0,X.jsx)(`span`,{className:`text-emerald-300`,children:`branch landed`}),a&&o&&(0,X.jsxs)(`span`,{className:`font-mono text-emerald-200/70`,title:`${a} → ${o}`,children:[a,(0,X.jsx)(`span`,{className:`opacity-50`,children:` → `}),o]}),r&&(0,X.jsx)(`span`,{className:`rounded bg-emerald-500/15 px-1 font-mono text-emerald-200`,title:n,children:r}),i&&(0,X.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-emerald-300/80`,children:[(0,X.jsx)(`span`,{className:`opacity-70`,children:`by`}),(0,X.jsx)(Z,{agentId:i,className:`text-emerald-300/90 hover:text-emerald-100`})]}),s===!1&&(0,X.jsx)(`span`,{className:`text-amber-300/80`,title:`Local-only land — not pushed to origin`,children:`· local only`}),(0,X.jsx)(`span`,{className:`text-emerald-300/50`,children:Y(e.occurredAt??e.createdAt)})]}),(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function Be({msg:e}){let t=typeof e.payload?.kind==`string`?e.payload.kind:``;if(t===`branch.landed`)return(0,X.jsx)(ze,{msg:e});let n=Ie[t]??i,r=Le[t]??Re(t);return(0,X.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,X.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,X.jsx)(n,{className:`h-3 w-3`}),(0,X.jsx)(`span`,{children:r}),(0,X.jsx)(`span`,{className:`text-muted-foreground/60`,children:Y(e.occurredAt??e.createdAt)})]}),(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}var Ve={"spawned-child":{ready:`spawned`,exited:`spawned · exited`,failed:`spawn failed`},"spawned-by":{ready:`spawned by`,exited:`spawned by`,failed:`spawned by`}},He={"spawned-child-ready":l,"spawned-child-exited":p,"spawned-child-failed":_,"spawned-by-ready":S,"spawned-by-exited":S,"spawned-by-failed":S},Ue={"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 We({entry:e}){let t=`${e.direction}-${e.status}`,n=Ve[e.direction]?.[e.status]??e.direction,r=He[t]??i,a=Ue[t]??`text-muted-foreground`,o=e.status===`failed`;return(0,X.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,X.jsxs)(`div`,{className:u(`flex items-center gap-1.5 rounded-full border bg-muted/30 px-2.5 py-1 text-xs`,o?`border-red-500/30`:`border-border`),children:[(0,X.jsx)(r,{className:u(`h-3 w-3 shrink-0`,a)}),(0,X.jsx)(`span`,{className:`text-muted-foreground`,children:n}),(0,X.jsx)(Z,{agentId:e.agentId}),e.reason&&o&&(0,X.jsxs)(`span`,{className:`text-red-400/80 max-w-[120px] truncate`,title:e.reason,children:[`— `,e.reason]}),(0,X.jsx)(`span`,{className:`text-muted-foreground/60 shrink-0`,children:Y(e.timestamp)})]}),(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function Ge({blockedLabel:e,onInterrupt:t}){return e?(0,X.jsx)(`div`,{className:`flex justify-start mb-3 animate-in fade-in slide-in-from-bottom-1 duration-150`,children:(0,X.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,X.jsx)(_,{className:`w-3.5 h-3.5 text-red-400`}),(0,X.jsxs)(`span`,{className:`text-xs text-red-300`,children:[`blocked: `,e]})]})}):(0,X.jsx)(`div`,{className:`flex justify-start mb-3 animate-in fade-in slide-in-from-bottom-1 duration-150`,children:(0,X.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,X.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,X.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-yellow-400 animate-[pulse_1.4s_ease-in-out_infinite]`}),(0,X.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,X.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,X.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`working`}),t&&(0,X.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,X.jsx)(T,{className:`w-3.5 h-3.5`}),`Stop`]})]})})}var Q=`agent-relay:chat-hide-tools`,$=(()=>{let e=new Set,t=(()=>{try{return window.localStorage.getItem(Q)===`on`}catch{return!1}})(),n=()=>e.forEach(e=>e());return typeof window<`u`&&window.addEventListener(`storage`,e=>{e.key===Q&&(t=e.newValue===`on`,n())}),{subscribe(t){return e.add(t),()=>e.delete(t)},get:()=>t,toggle(){t=!t;try{window.localStorage.setItem(Q,t?`on`:`off`)}catch{}n()}}})();function Ke(){return[(0,V.useSyncExternalStore)($.subscribe,$.get,()=>!1),$.toggle]}function qe({steps:e,showReasoning:t}){let[n,r]=Ke(),i=t?e:e.filter(e=>e.kind!==`reasoning`);if(!i.length)return null;let a=i.filter(e=>e.kind===`tool`).length;return(0,X.jsx)(`div`,{className:`flex justify-start mb-2`,children:(0,X.jsxs)(`div`,{className:`max-w-[85%] md:max-w-[75%] min-w-0 space-y-1.5`,children:[i.map(e=>e.kind===`narration`?(0,X.jsx)(B,{text:e.text,className:`text-sm leading-relaxed break-words text-foreground/90 min-w-0`},e.id):e.kind===`reasoning`?(0,X.jsxs)(`div`,{className:`flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground/80`,children:[(0,X.jsx)(h,{className:`w-3.5 h-3.5 mt-0.5 shrink-0 opacity-70`}),(0,X.jsx)(B,{text:e.text,className:`italic break-words min-w-0`})]},e.id):n?null:(0,X.jsxs)(`div`,{className:`flex items-start gap-1.5 text-xs leading-relaxed text-muted-foreground`,children:[(0,X.jsx)(b,{className:`w-3 h-3 mt-0.5 shrink-0 opacity-70`}),(0,X.jsxs)(`span`,{className:`min-w-0 break-words`,children:[(0,X.jsx)(`span`,{className:`font-medium`,children:e.label||`tool`}),e.text&&e.text.trim()&&e.text.trim()!==(e.label??``).trim()?(0,X.jsxs)(`span`,{className:`opacity-70`,children:[` — `,e.text]}):null]})]},e.id)),a>0&&(0,X.jsxs)(`button`,{onClick:r,className:`flex items-center gap-1 text-[11px] text-muted-foreground/50 hover:text-muted-foreground transition-colors text-left`,children:[(0,X.jsx)(A,{className:u(`w-3 h-3 shrink-0 transition-transform`,!n&&`rotate-90`)}),(0,X.jsx)(`span`,{children:n?`show ${a} tool step${a===1?``:`s`}`:`hide tool steps`})]})]})})}function Je({date:e}){return(0,X.jsxs)(`div`,{className:`flex items-center justify-center gap-3 py-3 my-1`,children:[(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,X.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground`,children:Pe(e)}),(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function Ye({timestamp:e}){let t=new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,year:`numeric`,hour:`2-digit`,minute:`2-digit`});return(0,X.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,X.jsxs)(`span`,{className:`text-xs text-muted-foreground/60`,children:[`created `,t]}),(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function Xe({history:e}){let t=e.sourceAgentLabel||e.sourcePeerId,n=e.entries.length;return(0,X.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-2 my-1`,children:[(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`}),(0,X.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,X.jsx)(r,{className:`h-3 w-3`}),(0,X.jsxs)(`span`,{children:[`forked history from `,t]}),(0,X.jsxs)(`span`,{className:`text-muted-foreground/60`,children:[n,` `,n===1?`entry`:`entries`]})]}),(0,X.jsx)(`div`,{className:`h-px flex-1 bg-border`})]})}function Ze({entry:e,sourceLabel:t}){let n=e.message,r=F(n),i=e.originalFrom===L;return(0,X.jsx)(`div`,{className:u(`flex mb-3 opacity-80`,i?`justify-end`:`justify-start`),children:(0,X.jsx)(`div`,{className:`max-w-[85%] md:max-w-[75%]`,children:(0,X.jsxs)(`div`,{className:u(`rounded-2xl border border-dashed px-3.5 py-2 text-sm select-text`,i?`border-primary/25 bg-primary/10 text-foreground rounded-br-sm`:`border-border bg-card/70 rounded-bl-sm`),children:[(0,X.jsxs)(`div`,{className:u(`mb-1 text-[10px] uppercase tracking-normal`,i?`text-primary/70`:`text-muted-foreground`),children:[`forked history · `,i?`you`:t||e.originalFrom]}),(0,X.jsx)(B,{text:r,rawBody:n.body,className:`leading-relaxed`}),(0,X.jsxs)(`p`,{className:u(`mt-1 flex items-center justify-end gap-1.5 text-xs`,i?`text-primary/60`:`text-muted-foreground`),children:[(0,X.jsxs)(`span`,{className:`opacity-40`,children:[`#`,e.originalMessageId]}),(0,X.jsx)(`span`,{children:Y(e.originalCreatedAt)})]})]})})})}function Qe({msg:e}){let t=F(e),n=Y(e.occurredAt??e.createdAt);return(0,X.jsx)(`div`,{"data-msg-id":e.id,className:`mb-3`,children:(0,X.jsxs)(`div`,{className:`rounded-xl border border-primary/30 bg-primary/[0.06] px-3.5 py-2.5 shadow-sm`,children:[(0,X.jsxs)(`div`,{className:`mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-primary/80`,children:[(0,X.jsx)(ee,{className:`h-3.5 w-3.5`}),(0,X.jsx)(`span`,{children:`Initial prompt`}),(0,X.jsx)(`span`,{className:`ml-auto text-[10px] font-normal normal-case text-muted-foreground/60`,children:n})]}),(0,X.jsx)(B,{text:t,rawBody:e.body,className:`text-sm leading-relaxed text-foreground`})]})})}function $e({scrollRef:e,timeline:t}){let[n,r]=(0,V.useState)(!0),[i,a]=(0,V.useState)(null),[o,s]=(0,V.useState)(null),[c,l]=(0,V.useState)(!0),d=(0,V.useMemo)(()=>{for(let e=t.length-1;e>=0;e--){let n=t[e];if(!(!n||n.type!==`message`)&&n.msg.from===`user`)return{id:n.msg.id,body:F(n.msg)}}return null},[t]);if((0,V.useEffect)(()=>{let t=e.current;if(!d||!t){r(!0);return}let n=t.querySelector(`[data-msg-id="${d.id}"]`);if(!n){r(!0);return}let i=new IntersectionObserver(([e])=>{if(e&&(r(e.isIntersecting),!e.isIntersecting)){let n=e.rootBounds?.top??t.getBoundingClientRect().top;l(e.boundingClientRect.top<n)}},{root:t,threshold:0});i.observe(n);let a=()=>{let e=n.getBoundingClientRect(),r=t.getBoundingClientRect();l(e.top<r.top)};return t.addEventListener(`scroll`,a,{passive:!0}),()=>{i.disconnect(),t.removeEventListener(`scroll`,a)}},[d?.id,e]),n||!d||!d.body.trim())return null;let f=i?.id===d.id?i.value:!1,p=o?.id===d.id?o.value:!1;function m(){let t=e.current;!t||!d||t.querySelector(`[data-msg-id="${d.id}"]`)?.scrollIntoView({behavior:`smooth`,block:`center`})}let h=c?`↑`:`↓`;return p?(0,X.jsx)(`div`,{className:`sticky top-0 z-10 -mx-3 md:-mx-4 -mt-3 md:-mt-4 bg-background`,children:(0,X.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 border-b border-primary/10 transition-colors`,onClick:()=>s({id:d.id,value:!1}),children:[(0,X.jsx)(`span`,{children:`Your prompt`}),(0,X.jsx)(y,{className:`w-3 h-3`})]})}):(0,X.jsxs)(`div`,{className:`sticky top-0 z-10 -mx-3 md:-mx-4 -mt-3 md:-mt-4 px-2 md:px-3 pt-2 pb-1.5 bg-background border-b border-primary/10`,children:[(0,X.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px] text-muted-foreground mb-0.5`,children:[(0,X.jsx)(`span`,{className:`font-medium text-primary/70`,children:`Your prompt`}),(0,X.jsxs)(`button`,{type:`button`,className:`ml-auto hover:text-foreground transition-colors`,onClick:m,children:[h,` scroll to original`]}),(0,X.jsx)(`button`,{type:`button`,className:`hover:text-foreground transition-colors`,onClick:()=>s({id:d.id,value:!0}),title:`Minimize`,children:(0,X.jsx)(C,{className:`w-3 h-3`})})]}),(0,X.jsx)(`p`,{className:u(`text-sm text-foreground leading-snug cursor-pointer`,!f&&`line-clamp-2`),onClick:()=>a({id:d.id,value:!f}),children:d.body})]})}function et(){return(0,V.useSyncExternalStore)(e=>M.subscribe(e),()=>M.getPlayingKey(),()=>null)}function tt({attachment:e,outbound:t}){let n=e.kind===`image`,r=e.title||e.artifactId,[i,s]=(0,V.useState)(null),[c,l]=(0,V.useState)(null),[d,p]=(0,V.useState)(!1),[m,h]=(0,V.useState)(!1);(0,V.useEffect)(()=>{let t=!1,n=null;async function r(){p(!0),l(null),s(null);try{let r=await a(`/artifacts/${encodeURIComponent(e.artifactId)}/content`);if(t)return;n=URL.createObjectURL(r),s(n)}catch(e){t||l(e.message)}finally{t||p(!1)}}return r(),()=>{t=!0,n&&URL.revokeObjectURL(n)}},[e.artifactId]);function g(){if(!i)return;let e=document.createElement(`a`);e.href=i,e.download=r,document.body.appendChild(e),e.click(),e.remove()}return n?(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(`button`,{type:`button`,onClick:()=>i&&h(!0),disabled:!i,className:`group/img mt-2 block overflow-hidden rounded-md border border-foreground/10 bg-black/10 text-left disabled:cursor-default relative`,children:i?(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(`img`,{src:i,alt:r,loading:`lazy`,className:`block max-h-72 max-w-full object-contain`}),(0,X.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-black/0 group-hover/img:bg-black/30 transition-colors`,children:(0,X.jsx)(O,{className:`w-6 h-6 text-white opacity-0 group-hover/img:opacity-100 transition-opacity drop-shadow-md`})})]}):(0,X.jsxs)(`span`,{className:u(`flex min-h-20 items-center gap-2 px-3 py-2 text-xs`,c?`text-red-400`:`text-muted-foreground`),children:[d?(0,X.jsx)(v,{className:`h-4 w-4 animate-spin`}):(0,X.jsx)(_,{className:`h-4 w-4`}),c||`Loading image`]})}),i&&(0,X.jsx)(le,{open:m,onOpenChange:h,children:(0,X.jsxs)(ce,{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,X.jsx)(ue,{className:`sr-only`,children:r}),(0,X.jsxs)(`div`,{className:`relative flex items-center justify-center min-h-[200px]`,children:[(0,X.jsx)(`img`,{src:i,alt:r,className:`max-w-[93vw] max-h-[90vh] object-contain`}),(0,X.jsxs)(`div`,{className:`absolute top-2 right-2 flex gap-1`,children:[(0,X.jsx)(`button`,{type:`button`,onClick:g,className:`rounded-md bg-black/60 hover:bg-black/80 p-2 text-white transition-colors`,title:`Download`,children:(0,X.jsx)(f,{className:`w-4 h-4`})}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:`rounded-md bg-black/60 hover:bg-black/80 p-2 text-white transition-colors`,title:`Close`,children:(0,X.jsx)(x,{className:`w-4 h-4`})})]})]})]})})]}):(0,X.jsxs)(`button`,{type:`button`,onClick:g,disabled:!i,className:u(`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:[d?(0,X.jsx)(v,{className:`h-4 w-4 shrink-0 animate-spin`}):c?(0,X.jsx)(_,{className:`h-4 w-4 shrink-0 text-red-400`}):(0,X.jsx)(o,{className:`h-4 w-4 shrink-0`}),(0,X.jsx)(`span`,{className:u(`min-w-0 flex-1 truncate`,c&&`text-red-400`),children:c||r}),(0,X.jsx)(f,{className:`h-3.5 w-3.5 shrink-0`})]})}function nt({open:e,onToggle:t,onReact:n}){return(0,X.jsxs)(`div`,{className:`relative shrink-0`,children:[(0,X.jsx)(`button`,{type:`button`,title:`Add reaction`,onClick:t,className:u(`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,X.jsx)(m,{className:`h-3 w-3`})}),e&&(0,X.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:Te.map(e=>(0,X.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 rt({msg:e,peer:n}){let[r,i]=(0,V.useState)(!1),a=P(e=>e.agentsById),o=e.from===n,s=(o?e.to:e.from)||``,c=!s||s===`broadcast`||s.includes(`:`),l=F(e),d=Y(e.occurredAt??e.createdAt),f=o?t:S;return(0,X.jsx)(`div`,{"data-msg-id":e.id,className:`flex justify-center mb-1.5`,children:(0,X.jsxs)(`div`,{className:`w-full max-w-[94%] rounded-md border border-border/50 bg-muted/15 px-2.5 py-1`,children:[(0,X.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs cursor-pointer select-none`,onClick:()=>i(e=>!e),children:[(0,X.jsx)(A,{className:u(`h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform`,r&&`rotate-90`)}),(0,X.jsx)(f,{className:`h-3 w-3 shrink-0 text-muted-foreground/70`}),(0,X.jsxs)(`span`,{className:`shrink-0 text-muted-foreground`,children:[`Message `,o?`to`:`from`]}),c?(0,X.jsx)(`span`,{className:`shrink-0 font-medium text-muted-foreground`,children:ae(s,a)}):(0,X.jsx)(Z,{agentId:s,className:`shrink-0 px-0.5 text-foreground/80`}),!r&&(0,X.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-muted-foreground/50`,children:l}),(0,X.jsx)(`span`,{className:`ml-auto shrink-0 text-muted-foreground/40`,children:d})]}),r&&(0,X.jsx)(`div`,{className:`mt-1.5 pl-5`,children:(0,X.jsx)(B,{text:l,rawBody:e.body,className:`text-sm leading-relaxed text-foreground/90`})})]})})}var it=(0,V.memo)(function({msg:e,peer:t,onOpenReferencedPath:n,onPreviewReferencedPath:r,onPreviewReferencedPathEnd:i}){if(e.from!==`user`&&e.to!==`user`)return(0,X.jsx)(rt,{msg:e,peer:t});let a=e.from===L,o=P(e=>e.reactToMessage),s=P(e=>e.voiceTtsEnabled),c=et(),l=P(e=>{let n=e.agentsById[t]?.meta?.cwd;return typeof n==`string`?n:``}),[d,f]=(0,V.useState)(!1),p=(0,V.useRef)(null),m=(0,V.useRef)(null),h=(0,V.useRef)(!1),_=F(e),v=Y(e.occurredAt??e.createdAt),y=we(e),b=Ee(e),x=a?De(e,t):null,S=x?.icon,C=c===String(e.id),w=s&&!a&&!J(e)&&_.trim().length>0;function E(t){t.stopPropagation(),C?M.bargeIn():M.speak(e.body,String(e.id))}(0,V.useEffect)(()=>{if(!d)return;function e(e){q()||p.current&&!p.current.contains(e.target)&&f(!1)}return document.addEventListener(`mousedown`,e),document.addEventListener(`touchstart`,e),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`touchstart`,e)}},[d]);function D(e){return be(l||`/`,e)}function O(e,t){let r=D(e);n?.(r,t)}function k(e,t,n){let i=D(e);r?.(i,t,n)}function A(t){o(e,t),f(!1)}function ee(e){e.button===0&&(m.current={x:e.clientX,y:e.clientY},h.current=!1)}function j(e){let t=m.current;t&&(Math.abs(e.clientX-t.x)>3||Math.abs(e.clientY-t.y)>3)&&(h.current=!0)}function N(t){if(!(J(e)||a)&&!t.target.closest(`a,button,input,textarea,select,[role="button"]`)){if(h.current||q()){h.current=!1;return}f(e=>!e)}}return(0,X.jsx)(`div`,{"data-msg-id":e.id,className:u(`group/msg flex mb-3`,a?`justify-end`:`justify-start`),children:(0,X.jsxs)(`div`,{ref:p,className:`relative max-w-[85%] md:max-w-[75%]`,children:[w&&(0,X.jsx)(`button`,{type:`button`,title:C?`Stop playback`:`Play aloud`,onClick:E,className:u(`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`,C?`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:C?(0,X.jsx)(T,{className:`h-3.5 w-3.5 animate-pulse`}):(0,X.jsx)(g,{className:`h-3.5 w-3.5`})}),(0,X.jsxs)(`div`,{className:u(`rounded-2xl px-3.5 py-2 text-sm select-text`,!a&&!J(e)&&`cursor-pointer`,a?`bg-primary text-primary-foreground rounded-br-sm`:`bg-card ring-1 ring-foreground/10 rounded-bl-sm`),onPointerDown:ee,onPointerMove:j,onClick:N,children:[e.subject&&(0,X.jsx)(`p`,{className:u(`text-xs font-semibold mb-1`,a?`text-primary-foreground/70`:`text-muted-foreground`),children:e.subject}),(0,X.jsx)(B,{text:_,rawBody:e.body,className:`leading-relaxed`,onOpenPath:O,onPreviewPath:k,onPreviewPathEnd:i,resolvePathTitle:(e,t)=>`${D(e)}${t?`:${t}`:``}`}),y.map(t=>(0,X.jsx)(tt,{attachment:t,outbound:a},`${e.id}-${t.artifactId}-${t.role||``}`)),(0,X.jsxs)(`p`,{className:u(`text-xs mt-1 flex items-center gap-1.5`,a?`justify-end text-primary-foreground/60`:`justify-end text-muted-foreground`),children:[(0,X.jsxs)(`span`,{className:`opacity-40`,children:[`#`,e.id]}),(0,X.jsx)(`span`,{children:v}),x&&S&&(0,X.jsxs)(`span`,{className:u(`inline-flex items-center gap-1`,x.tone===`ok`&&`text-emerald-300`,x.tone===`warn`&&`text-amber-200`,x.tone===`danger`&&`text-red-200`),title:x.title,children:[(0,X.jsx)(S,{className:`h-3 w-3`}),x.label]})]})]}),!J(e)&&b.length>0&&(0,X.jsxs)(`div`,{className:u(`flex flex-wrap items-center gap-0.5 -mt-1 relative z-10`,a?`justify-end pr-2`:`justify-start pl-2`),children:[!a&&(0,X.jsx)(nt,{open:d,onToggle:()=>f(e=>!e),onReact:A}),b.map(e=>(0,X.jsxs)(`button`,{type:`button`,title:e.actors.join(`, `),onClick:()=>A(e.emoji),className:u(`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,X.jsx)(`span`,{children:e.emoji}),e.count>1&&(0,X.jsx)(`span`,{children:e.count})]},e.emoji))]}),!J(e)&&!a&&b.length===0&&(0,X.jsx)(`div`,{className:`absolute -bottom-2.5 left-1 z-20`,children:(0,X.jsx)(nt,{open:d,onToggle:()=>f(e=>!e),onReact:A})})]})})});export{Me as _,Ye as a,ke as b,Ze as c,Fe as d,$e as f,xe as g,Se as h,Ge as i,Qe as l,Ae as m,qe as n,Je as o,ye as p,We as r,Xe as s,it as t,Be as u,je as v,_e as x,Ce as y};
2
- //# sourceMappingURL=MessageBubble-DLF9fJLb.js.map