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.
- package/docs/openapi.json +1 -1
- package/package.json +2 -2
- package/public/assets/MessageBubble-CG_eCKDI.js +3 -0
- package/public/assets/MessageBubble-CG_eCKDI.js.map +1 -0
- package/public/assets/{PlanGraphPanel-DrHNFbg6.js → PlanGraphPanel-Ba9qh-if.js} +2 -2
- package/public/assets/{PlanGraphPanel-DrHNFbg6.js.map → PlanGraphPanel-Ba9qh-if.js.map} +1 -1
- package/public/assets/{activity-CECdsDpd.js → activity-8eZ4FhxO.js} +2 -2
- package/public/assets/{activity-CECdsDpd.js.map → activity-8eZ4FhxO.js.map} +1 -1
- package/public/assets/{agent-profiles-CHitqihm.js → agent-profiles-1Nx8ROA_.js} +2 -2
- package/public/assets/{agent-profiles-CHitqihm.js.map → agent-profiles-1Nx8ROA_.js.map} +1 -1
- package/public/assets/{agents-GG-aJj6Z.js → agents-C8fM2VwM.js} +2 -2
- package/public/assets/{agents-GG-aJj6Z.js.map → agents-C8fM2VwM.js.map} +1 -1
- package/public/assets/{analytics-y0Yf26cD.js → analytics-D6ffu1ji.js} +2 -2
- package/public/assets/{analytics-y0Yf26cD.js.map → analytics-D6ffu1ji.js.map} +1 -1
- package/public/assets/{automation-CmzftGBn.js → automation-BVmzNi6H.js} +2 -2
- package/public/assets/{automation-CmzftGBn.js.map → automation-BVmzNi6H.js.map} +1 -1
- package/public/assets/{branch-state-badge-Biam17QK.js → branch-state-badge-DrwCnoKR.js} +2 -2
- package/public/assets/{branch-state-badge-Biam17QK.js.map → branch-state-badge-DrwCnoKR.js.map} +1 -1
- package/public/assets/{channels-CmAXppQu.js → channels-BuqbbyaO.js} +2 -2
- package/public/assets/{channels-CmAXppQu.js.map → channels-BuqbbyaO.js.map} +1 -1
- package/public/assets/chat-DCnEGe-x.js +2 -0
- package/public/assets/chat-DCnEGe-x.js.map +1 -0
- package/public/assets/{connectors-bZ0YsSqg.js → connectors-_LpoKQNb.js} +2 -2
- package/public/assets/{connectors-bZ0YsSqg.js.map → connectors-_LpoKQNb.js.map} +1 -1
- package/public/assets/formatted-body-impl-C7ftpr0y.js +3 -0
- package/public/assets/formatted-body-impl-C7ftpr0y.js.map +1 -0
- package/public/assets/index-eCpWfoCA.css +2 -0
- package/public/assets/{index-BSWui_-2.js → index-ksV0Snw6.js} +10 -10
- package/public/assets/index-ksV0Snw6.js.map +1 -0
- package/public/assets/{insights-cC2lVGUs.js → insights-BjRehGVP.js} +2 -2
- package/public/assets/{insights-cC2lVGUs.js.map → insights-BjRehGVP.js.map} +1 -1
- package/public/assets/{integrations--k7_eYP2.js → integrations-DCyxAv8c.js} +2 -2
- package/public/assets/{integrations--k7_eYP2.js.map → integrations-DCyxAv8c.js.map} +1 -1
- package/public/assets/{maintenance-B6wOij_l.js → maintenance-CKiNcUMS.js} +2 -2
- package/public/assets/{maintenance-B6wOij_l.js.map → maintenance-CKiNcUMS.js.map} +1 -1
- package/public/assets/{managed-agents-CDzLSKp1.js → managed-agents-Os_T-7w7.js} +2 -2
- package/public/assets/{managed-agents-CDzLSKp1.js.map → managed-agents-Os_T-7w7.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-D3Y4uUgk.js → markdown-preview-impl-grkpBldu.js} +2 -2
- package/public/assets/{markdown-preview-impl-D3Y4uUgk.js.map → markdown-preview-impl-grkpBldu.js.map} +1 -1
- package/public/assets/{memory-DYzw5EXn.js → memory-YiYlqWUZ.js} +2 -2
- package/public/assets/{memory-DYzw5EXn.js.map → memory-YiYlqWUZ.js.map} +1 -1
- package/public/assets/{messages-ATbJw7jy.js → messages-CVDtrrub.js} +2 -2
- package/public/assets/messages-CVDtrrub.js.map +1 -0
- package/public/assets/orchestrators-Dzup-DDB.js +2 -0
- package/public/assets/{orchestrators-Dtr4zNWI.js.map → orchestrators-Dzup-DDB.js.map} +1 -1
- package/public/assets/{overview-B071A7FM.js → overview-DZltfAFn.js} +2 -2
- package/public/assets/{overview-B071A7FM.js.map → overview-DZltfAFn.js.map} +1 -1
- package/public/assets/{pairs-DgiNK9mA.js → pairs-Q2CmriBh.js} +2 -2
- package/public/assets/{pairs-DgiNK9mA.js.map → pairs-Q2CmriBh.js.map} +1 -1
- package/public/assets/{projects-DhQUdwcb.js → projects-DtJmrhI0.js} +2 -2
- package/public/assets/projects-DtJmrhI0.js.map +1 -0
- package/public/assets/{security-COHkbWIm.js → security-Bur19Sp4.js} +2 -2
- package/public/assets/{security-COHkbWIm.js.map → security-Bur19Sp4.js.map} +1 -1
- package/public/assets/{select-CKPIes_u.js → select-CuzWJuBz.js} +2 -2
- package/public/assets/{select-CKPIes_u.js.map → select-CuzWJuBz.js.map} +1 -1
- package/public/assets/settings-CEMCJ31_.js +4 -0
- package/public/assets/settings-CEMCJ31_.js.map +1 -0
- package/public/assets/store-BeKcuJ2q.js +9 -0
- package/public/assets/store-BeKcuJ2q.js.map +1 -0
- package/public/assets/{tasks-DdVsKCUN.js → tasks-DjwAusKz.js} +2 -2
- package/public/assets/{tasks-DdVsKCUN.js.map → tasks-DjwAusKz.js.map} +1 -1
- package/public/assets/{teams-BLQeR-qJ.js → teams-CFCnB12u.js} +2 -2
- package/public/assets/{teams-BLQeR-qJ.js.map → teams-CFCnB12u.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-eFq9PBWV.js → terminal-viewer-impl-CWu5RTp2.js} +2 -2
- package/public/assets/{terminal-viewer-impl-eFq9PBWV.js.map → terminal-viewer-impl-CWu5RTp2.js.map} +1 -1
- package/public/assets/{work-queue-OFw-Hwir.js → work-queue-TZQ5Gz0t.js} +2 -2
- package/public/assets/{work-queue-OFw-Hwir.js.map → work-queue-TZQ5Gz0t.js.map} +1 -1
- package/public/assets/{workspaces-zum4lO_O.js → workspaces-Bu4uVUcu.js} +2 -2
- package/public/assets/{workspaces-zum4lO_O.js.map → workspaces-Bu4uVUcu.js.map} +1 -1
- package/public/index.html +3 -3
- package/src/agent-issue-repo.ts +29 -0
- package/src/branch-landed.ts +69 -2
- package/src/cli/index.ts +6 -4
- package/src/config.ts +1 -0
- package/src/context-advisory.ts +93 -15
- package/src/context-threshold-config.ts +14 -2
- package/src/db/migrations.ts +24 -0
- package/src/db/projects.ts +34 -6
- package/src/db/schema.ts +1 -0
- package/src/mcp/tools-workspace.ts +3 -3
- package/src/mcp-project-tools.ts +2 -0
- package/src/notification-router.ts +2 -0
- package/src/provider-catalog-store.ts +35 -0
- package/src/routes/agents.ts +3 -2
- package/src/routes/commands.ts +6 -1
- package/src/routes/provider-config.ts +27 -0
- package/src/services/git-remote.ts +46 -0
- package/src/services/issue-lifecycle.ts +5 -36
- package/src/services/project.ts +23 -3
- package/src/services/register-agent.ts +7 -1
- package/src/services/spawn-agent.ts +7 -9
- package/src/services/spawn-registration-watchdog.ts +34 -12
- package/src/settings/registry.ts +2 -0
- package/src/sse.ts +9 -4
- package/src/workspace-phase.ts +17 -9
- package/public/assets/MessageBubble-DLF9fJLb.js +0 -2
- package/public/assets/MessageBubble-DLF9fJLb.js.map +0 -1
- package/public/assets/chat-C-FI9bLO.js +0 -2
- package/public/assets/chat-C-FI9bLO.js.map +0 -1
- package/public/assets/formatted-body-impl-D--5zVSd.js +0 -3
- package/public/assets/formatted-body-impl-D--5zVSd.js.map +0 -1
- package/public/assets/index-BSWui_-2.js.map +0 -1
- package/public/assets/index-B_On3Osd.css +0 -2
- package/public/assets/messages-ATbJw7jy.js.map +0 -1
- package/public/assets/orchestrators-Dtr4zNWI.js +0 -2
- package/public/assets/projects-DhQUdwcb.js.map +0 -1
- package/public/assets/settings-B4SN1TpB.js +0 -4
- package/public/assets/settings-B4SN1TpB.js.map +0 -1
- package/public/assets/store-DnHOGovN.js +0 -9
- 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;
|
package/src/services/project.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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: {
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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 (
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
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
|
-
|
|
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> {
|
package/src/settings/registry.ts
CHANGED
|
@@ -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)
|
|
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);
|
package/src/workspace-phase.ts
CHANGED
|
@@ -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,
|
|
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,
|
|
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 —
|
|
189
|
-
hint: "No action needed.
|
|
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: [
|
|
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
|
-
"
|
|
306
|
-
"
|
|
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).
|
|
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
|