agent-relay-server 0.10.20 → 0.10.22
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 +459 -70
- package/package.json +2 -2
- package/public/index.html +1200 -472
- package/scripts/orchestrator-spawn-smoke.ts +26 -2
- package/src/db.ts +97 -21
- package/src/lifecycle-manager.ts +56 -1
- package/src/maintenance.ts +117 -0
- package/src/routes.ts +415 -27
package/public/index.html
CHANGED
|
@@ -11610,6 +11610,10 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
11610
11610
|
health: null,
|
|
11611
11611
|
maintenanceJobs: [],
|
|
11612
11612
|
workspaces: [],
|
|
11613
|
+
workspaceGitState: {},
|
|
11614
|
+
workspaceMergePreview: {},
|
|
11615
|
+
workspaceDiff: {},
|
|
11616
|
+
workspaceOrphans: [],
|
|
11613
11617
|
taskEvents: [],
|
|
11614
11618
|
taskEventCache: {},
|
|
11615
11619
|
activityEvents: [],
|
|
@@ -12003,12 +12007,83 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12003
12007
|
set({ workspaces: await api("GET", "/workspaces") });
|
|
12004
12008
|
} catch {}
|
|
12005
12009
|
},
|
|
12010
|
+
async fetchWorkspaceGitState(workspaceId) {
|
|
12011
|
+
try {
|
|
12012
|
+
const state = await api("GET", "/workspaces/" + encodeURIComponent(workspaceId) + "/git-state");
|
|
12013
|
+
set((s) => ({ workspaceGitState: {
|
|
12014
|
+
...s.workspaceGitState,
|
|
12015
|
+
[workspaceId]: state
|
|
12016
|
+
} }));
|
|
12017
|
+
} catch (e) {
|
|
12018
|
+
set((s) => ({ workspaceGitState: {
|
|
12019
|
+
...s.workspaceGitState,
|
|
12020
|
+
[workspaceId]: {
|
|
12021
|
+
available: false,
|
|
12022
|
+
reason: e.message
|
|
12023
|
+
}
|
|
12024
|
+
} }));
|
|
12025
|
+
}
|
|
12026
|
+
},
|
|
12027
|
+
async fetchWorkspaceMergePreview(workspaceId) {
|
|
12028
|
+
try {
|
|
12029
|
+
const preview = await api("GET", "/workspaces/" + encodeURIComponent(workspaceId) + "/merge-preview");
|
|
12030
|
+
set((s) => ({ workspaceMergePreview: {
|
|
12031
|
+
...s.workspaceMergePreview,
|
|
12032
|
+
[workspaceId]: preview
|
|
12033
|
+
} }));
|
|
12034
|
+
} catch (e) {
|
|
12035
|
+
set((s) => ({ workspaceMergePreview: {
|
|
12036
|
+
...s.workspaceMergePreview,
|
|
12037
|
+
[workspaceId]: {
|
|
12038
|
+
available: false,
|
|
12039
|
+
reason: e.message
|
|
12040
|
+
}
|
|
12041
|
+
} }));
|
|
12042
|
+
}
|
|
12043
|
+
},
|
|
12044
|
+
async fetchWorkspaceDiff(workspaceId) {
|
|
12045
|
+
try {
|
|
12046
|
+
const diff = await api("GET", "/workspaces/" + encodeURIComponent(workspaceId) + "/diff");
|
|
12047
|
+
set((s) => ({ workspaceDiff: {
|
|
12048
|
+
...s.workspaceDiff,
|
|
12049
|
+
[workspaceId]: diff
|
|
12050
|
+
} }));
|
|
12051
|
+
} catch (e) {
|
|
12052
|
+
set((s) => ({ workspaceDiff: {
|
|
12053
|
+
...s.workspaceDiff,
|
|
12054
|
+
[workspaceId]: {
|
|
12055
|
+
available: false,
|
|
12056
|
+
reason: e.message
|
|
12057
|
+
}
|
|
12058
|
+
} }));
|
|
12059
|
+
}
|
|
12060
|
+
},
|
|
12061
|
+
async fetchWorkspaceOrphans() {
|
|
12062
|
+
try {
|
|
12063
|
+
set({ workspaceOrphans: (await api("GET", "/workspaces/orphans")).orphans ?? [] });
|
|
12064
|
+
} catch {}
|
|
12065
|
+
},
|
|
12066
|
+
async reclaimWorkspaceOrphan(orphan) {
|
|
12067
|
+
get().openConfirm("Reclaim Orphan Worktree", `Remove the orphaned worktree "${orphan.branch || orphan.worktreePath}" from disk? It has no live agent.`, async () => {
|
|
12068
|
+
try {
|
|
12069
|
+
await api("POST", "/workspaces/orphans/reclaim", {
|
|
12070
|
+
worktreePath: orphan.worktreePath,
|
|
12071
|
+
repoRoot: orphan.repoRoot,
|
|
12072
|
+
branch: orphan.branch
|
|
12073
|
+
});
|
|
12074
|
+
get().showNotification("Orphan reclaim dispatched");
|
|
12075
|
+
await Promise.all([get().fetchWorkspaceOrphans(), get().fetchActivityEvents()]);
|
|
12076
|
+
} catch (e) {
|
|
12077
|
+
get().showError("Reclaim Failed", e.message);
|
|
12078
|
+
}
|
|
12079
|
+
});
|
|
12080
|
+
},
|
|
12006
12081
|
async workspaceAction(workspaceId, action) {
|
|
12007
|
-
const label = action === "ready" ? "Mark ready" : action === "request-review" ? "Request review" : action === "merge-plan" ? "Mark merge planned" : action === "abandon" ? "Abandon" : "Cleanup";
|
|
12082
|
+
const label = action === "ready" ? "Mark ready" : action === "request-review" ? "Request review" : action === "merge-plan" ? "Mark merge planned" : action === "merge" ? "Merge" : action === "abandon" ? "Abandon" : "Cleanup";
|
|
12008
12083
|
const run = async () => {
|
|
12009
12084
|
try {
|
|
12010
12085
|
await api("POST", "/workspaces/" + encodeURIComponent(workspaceId) + "/actions", { action });
|
|
12011
|
-
get().showNotification(action === "cleanup" ? "Workspace cleanup requested" : `Workspace updated: ${label}`);
|
|
12086
|
+
get().showNotification(action === "cleanup" ? "Workspace cleanup requested" : action === "merge" ? "Workspace merge dispatched" : `Workspace updated: ${label}`);
|
|
12012
12087
|
await Promise.all([
|
|
12013
12088
|
get().fetchWorkspaces(),
|
|
12014
12089
|
get().fetchOrchestrators(),
|
|
@@ -12018,14 +12093,45 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12018
12093
|
get().showError("Workspace Action Failed", e.message);
|
|
12019
12094
|
}
|
|
12020
12095
|
};
|
|
12021
|
-
if (action === "cleanup" || action === "abandon") {
|
|
12096
|
+
if (action === "cleanup" || action === "abandon" || action === "merge") {
|
|
12022
12097
|
const workspace = get().workspaces.find((item) => item.id === workspaceId);
|
|
12023
12098
|
const target = workspace?.branch || workspace?.worktreePath || workspaceId;
|
|
12024
|
-
|
|
12099
|
+
if (action === "merge") {
|
|
12100
|
+
const preview = get().workspaceMergePreview[workspaceId];
|
|
12101
|
+
const mergeDetail = preview && preview.available !== false ? ` — ${preview.strategy === "pr" ? "opens a PR" : `rebases & fast-forwards into ${preview.baseRef || "base"}, then deletes the branch`}.` : " — lands the work and deletes the branch.";
|
|
12102
|
+
get().openConfirm("Merge Workspace", `Merge workspace "${target}"?${mergeDetail}`, run);
|
|
12103
|
+
return;
|
|
12104
|
+
}
|
|
12105
|
+
if (action === "cleanup") {
|
|
12106
|
+
await get().fetchWorkspaceGitState(workspaceId);
|
|
12107
|
+
const gs = get().workspaceGitState[workspaceId];
|
|
12108
|
+
let warn = "";
|
|
12109
|
+
if (gs && gs.available !== false && !gs.missing) {
|
|
12110
|
+
const ahead = gs.ahead ?? 0;
|
|
12111
|
+
const dirty = gs.dirtyCount ?? 0;
|
|
12112
|
+
if (ahead > 0 || dirty > 0) warn = ` ⚠ This destroys ${[ahead > 0 ? `${ahead} unmerged commit(s)` : "", dirty > 0 ? `${dirty} uncommitted change(s)` : ""].filter(Boolean).join(" and ")}.`;
|
|
12113
|
+
}
|
|
12114
|
+
get().openConfirm("Cleanup Workspace", `Remove the worktree for "${target}" on the host?${warn}`, run);
|
|
12115
|
+
return;
|
|
12116
|
+
}
|
|
12117
|
+
get().openConfirm("Abandon Workspace", `Abandon workspace "${target}"?`, run);
|
|
12025
12118
|
return;
|
|
12026
12119
|
}
|
|
12027
12120
|
await run();
|
|
12028
12121
|
},
|
|
12122
|
+
async purgeWorkspace(workspaceId) {
|
|
12123
|
+
const workspace = get().workspaces.find((item) => item.id === workspaceId);
|
|
12124
|
+
const target = workspace?.branch || workspace?.worktreePath || workspaceId;
|
|
12125
|
+
get().openConfirm("Purge Workspace Record", `Permanently remove the record for "${target}"? This only clears the dashboard row — it does not touch disk.`, async () => {
|
|
12126
|
+
try {
|
|
12127
|
+
await api("DELETE", "/workspaces/" + encodeURIComponent(workspaceId));
|
|
12128
|
+
get().showNotification("Workspace record purged");
|
|
12129
|
+
await Promise.all([get().fetchWorkspaces(), get().fetchActivityEvents()]);
|
|
12130
|
+
} catch (e) {
|
|
12131
|
+
get().showError("Purge Failed", e.message);
|
|
12132
|
+
}
|
|
12133
|
+
});
|
|
12134
|
+
},
|
|
12029
12135
|
async fetchAgentProfiles() {
|
|
12030
12136
|
try {
|
|
12031
12137
|
set({ agentProfiles: (await api("GET", "/agent-profiles")).map((entry) => entry.value) });
|
|
@@ -12227,6 +12333,8 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12227
12333
|
const msgs = [...s.messages, msg];
|
|
12228
12334
|
if (msgs.length > 500) msgs.splice(0, msgs.length - 500);
|
|
12229
12335
|
set({ messages: msgs });
|
|
12336
|
+
const peer = inboxPeer(msg);
|
|
12337
|
+
if (isHumanInboundMessage(msg) && peer && s.view === "chat" && s.selectedInboxThread === peer && !isDashboardHidden()) get().markInboxThreadReadTo(peer, msg.id);
|
|
12230
12338
|
return;
|
|
12231
12339
|
}
|
|
12232
12340
|
if (event === "message.queued" || event === "message.expired" || event === "message.delivery_updated" || event === "message.reaction_updated") {
|
|
@@ -12753,15 +12861,18 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12753
12861
|
if (!body.trim() && attachments.length === 0 || get().chatSending) return;
|
|
12754
12862
|
set({ chatSending: true });
|
|
12755
12863
|
try {
|
|
12756
|
-
|
|
12757
|
-
|
|
12758
|
-
|
|
12759
|
-
|
|
12760
|
-
|
|
12761
|
-
|
|
12762
|
-
|
|
12763
|
-
|
|
12764
|
-
|
|
12864
|
+
if (get().agentsById[thread.peer]?.providerCapabilities?.liveSession?.inject && attachments.length === 0) await api("POST", "/agents/" + encodeURIComponent(thread.peer) + "/prompt", { body: body.trim() });
|
|
12865
|
+
else {
|
|
12866
|
+
const payload = {
|
|
12867
|
+
from: HUMAN_AGENT_ID,
|
|
12868
|
+
to: thread.peer,
|
|
12869
|
+
body: body.trim() || "Attachment"
|
|
12870
|
+
};
|
|
12871
|
+
if (thread.lastMessage?.channel) payload.channel = thread.lastMessage.channel;
|
|
12872
|
+
if (thread.lastMessage?.id) payload.replyTo = thread.lastMessage.id;
|
|
12873
|
+
if (attachments.length) payload.payload = { attachments };
|
|
12874
|
+
await api("POST", "/messages", payload);
|
|
12875
|
+
}
|
|
12765
12876
|
const next = { ...get().inboxDrafts };
|
|
12766
12877
|
delete next[thread.peer];
|
|
12767
12878
|
set({ inboxDrafts: next });
|
|
@@ -13209,6 +13320,20 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
13209
13320
|
}
|
|
13210
13321
|
});
|
|
13211
13322
|
},
|
|
13323
|
+
upgradeOrchestrator(orchId, targetVersion) {
|
|
13324
|
+
const to = targetVersion ? ` to v${targetVersion}` : " to match the relay";
|
|
13325
|
+
get().openConfirm("Upgrade Orchestrator", `Upgrade "${orchId}"${to}? It will install the new version and restart itself.`, async () => {
|
|
13326
|
+
try {
|
|
13327
|
+
await api("POST", "/orchestrators/" + encodeURIComponent(orchId) + "/actions", {
|
|
13328
|
+
action: "upgrade",
|
|
13329
|
+
...targetVersion ? { targetVersion } : {}
|
|
13330
|
+
});
|
|
13331
|
+
await Promise.all([get().fetchOrchestrators(), get().fetchActivityEvents()]);
|
|
13332
|
+
} catch (e) {
|
|
13333
|
+
get().showError("Upgrade Failed", e.message);
|
|
13334
|
+
}
|
|
13335
|
+
});
|
|
13336
|
+
},
|
|
13212
13337
|
deleteOrchestrator(orchId) {
|
|
13213
13338
|
get().openConfirm("Remove Orchestrator", `Remove orchestrator "${orchId}"?`, async () => {
|
|
13214
13339
|
try {
|
|
@@ -106939,8 +107064,8 @@ function TextWithLinks({ text, onOpenPath, onPreviewPath, onPreviewPathEnd, isPa
|
|
|
106939
107064
|
e.stopPropagation();
|
|
106940
107065
|
onOpenPath(part.path, part.line);
|
|
106941
107066
|
},
|
|
106942
|
-
onMouseEnter: () => onPreviewPath?.(part.path, part.line),
|
|
106943
|
-
onFocus: () => onPreviewPath?.(part.path, part.line),
|
|
107067
|
+
onMouseEnter: (e) => onPreviewPath?.(part.path, part.line, e.currentTarget.getBoundingClientRect()),
|
|
107068
|
+
onFocus: (e) => onPreviewPath?.(part.path, part.line, e.currentTarget.getBoundingClientRect()),
|
|
106944
107069
|
onMouseLeave: () => onPreviewPathEnd?.(),
|
|
106945
107070
|
onBlur: () => onPreviewPathEnd?.(),
|
|
106946
107071
|
title: resolvedTitle ? `Open ${resolvedTitle}` : "Open file",
|
|
@@ -117489,15 +117614,21 @@ var h$1 = 2, _$1 = 1, o$1 = class {
|
|
|
117489
117614
|
};
|
|
117490
117615
|
//#endregion
|
|
117491
117616
|
//#region src/components/ui/dialog.tsx
|
|
117617
|
+
var suppressGuardPop = false;
|
|
117492
117618
|
function useBackClose$1(open, onOpenChange) {
|
|
117493
117619
|
const pushedRef = import_react.useRef(false);
|
|
117494
117620
|
const cbRef = import_react.useRef(onOpenChange);
|
|
117495
117621
|
cbRef.current = onOpenChange;
|
|
117496
117622
|
import_react.useEffect(() => {
|
|
117497
117623
|
if (!open || !cbRef.current) return;
|
|
117624
|
+
suppressGuardPop = false;
|
|
117498
117625
|
window.history.pushState({ dialogGuard: true }, "");
|
|
117499
117626
|
pushedRef.current = true;
|
|
117500
117627
|
function onPop() {
|
|
117628
|
+
if (suppressGuardPop) {
|
|
117629
|
+
suppressGuardPop = false;
|
|
117630
|
+
return;
|
|
117631
|
+
}
|
|
117501
117632
|
if (pushedRef.current) {
|
|
117502
117633
|
pushedRef.current = false;
|
|
117503
117634
|
cbRef.current?.(false);
|
|
@@ -117508,6 +117639,7 @@ function useBackClose$1(open, onOpenChange) {
|
|
|
117508
117639
|
window.removeEventListener("popstate", onPop);
|
|
117509
117640
|
if (pushedRef.current) {
|
|
117510
117641
|
pushedRef.current = false;
|
|
117642
|
+
suppressGuardPop = true;
|
|
117511
117643
|
window.history.back();
|
|
117512
117644
|
}
|
|
117513
117645
|
};
|
|
@@ -119670,6 +119802,74 @@ function PendingAttachmentPreview({ item, onRemove }) {
|
|
|
119670
119802
|
})
|
|
119671
119803
|
})] });
|
|
119672
119804
|
}
|
|
119805
|
+
function FloatingFilePreview({ preview, error, onReadError, onMouseEnter, onMouseLeave }) {
|
|
119806
|
+
const { anchor } = preview;
|
|
119807
|
+
const gap = 8;
|
|
119808
|
+
const width = Math.min(560, window.innerWidth - 24);
|
|
119809
|
+
const height = Math.min(380, window.innerHeight - 24);
|
|
119810
|
+
const left = Math.max(12, Math.min(anchor.left, window.innerWidth - width - 12));
|
|
119811
|
+
return (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
119812
|
+
className: "fixed z-50 flex flex-col overflow-hidden rounded-lg border border-border bg-background shadow-xl",
|
|
119813
|
+
style: {
|
|
119814
|
+
top: window.innerHeight - anchor.bottom >= height + gap ? anchor.bottom + gap : anchor.top - gap - height >= 12 ? anchor.top - gap - height : Math.max(12, window.innerHeight - height - 12),
|
|
119815
|
+
left,
|
|
119816
|
+
width,
|
|
119817
|
+
height
|
|
119818
|
+
},
|
|
119819
|
+
onMouseEnter,
|
|
119820
|
+
onMouseLeave,
|
|
119821
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
119822
|
+
className: "flex h-8 shrink-0 items-center gap-2 border-b border-border px-2.5",
|
|
119823
|
+
children: [
|
|
119824
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
119825
|
+
className: "min-w-0 flex-1 truncate text-[11px] font-medium text-muted-foreground",
|
|
119826
|
+
children: preview.path
|
|
119827
|
+
}),
|
|
119828
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
119829
|
+
className: "max-w-[12rem] truncate text-[11px] text-red-400",
|
|
119830
|
+
children: error
|
|
119831
|
+
}),
|
|
119832
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
119833
|
+
className: "shrink-0 text-[10px] text-muted-foreground/70",
|
|
119834
|
+
children: "click to pin"
|
|
119835
|
+
})
|
|
119836
|
+
]
|
|
119837
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
119838
|
+
className: "min-h-0 flex-1",
|
|
119839
|
+
children: preview.type === "directory" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectoryContent, {
|
|
119840
|
+
orchestratorId: preview.orchestratorId,
|
|
119841
|
+
selectedPath: preview.path,
|
|
119842
|
+
onReadError
|
|
119843
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileContent, {
|
|
119844
|
+
orchestratorId: preview.orchestratorId,
|
|
119845
|
+
selectedPath: preview.path,
|
|
119846
|
+
line: preview.line,
|
|
119847
|
+
onReadError
|
|
119848
|
+
})
|
|
119849
|
+
})]
|
|
119850
|
+
}), document.body);
|
|
119851
|
+
}
|
|
119852
|
+
function AddReaction({ open, onToggle, onReact }) {
|
|
119853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
119854
|
+
className: "relative shrink-0",
|
|
119855
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
119856
|
+
type: "button",
|
|
119857
|
+
title: "Add reaction",
|
|
119858
|
+
onClick: onToggle,
|
|
119859
|
+
className: cn$1("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", open ? "opacity-100" : "opacity-0 pointer-events-none md:group-hover/msg:opacity-100 md:group-hover/msg:pointer-events-auto"),
|
|
119860
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmilePlus, { className: "h-3 w-3" })
|
|
119861
|
+
}), open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
119862
|
+
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",
|
|
119863
|
+
children: QUICK_REACTIONS.map((emoji) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
119864
|
+
type: "button",
|
|
119865
|
+
title: `React ${emoji}`,
|
|
119866
|
+
onClick: () => onReact(emoji),
|
|
119867
|
+
className: "inline-flex h-6 w-7 items-center justify-center rounded-full text-xs transition-colors hover:bg-muted",
|
|
119868
|
+
children: emoji
|
|
119869
|
+
}, emoji))
|
|
119870
|
+
})]
|
|
119871
|
+
});
|
|
119872
|
+
}
|
|
119673
119873
|
var MessageBubble = (0, import_react.memo)(function MessageBubble({ msg, peer, onOpenReferencedPath, onPreviewReferencedPath, onPreviewReferencedPathEnd }) {
|
|
119674
119874
|
const isOutbound = msg.from === HUMAN_AGENT_ID;
|
|
119675
119875
|
const reactToMessage = useRelayStore((s) => s.reactToMessage);
|
|
@@ -119707,9 +119907,9 @@ var MessageBubble = (0, import_react.memo)(function MessageBubble({ msg, peer, o
|
|
|
119707
119907
|
const absolute = resolvedReferencedPath(path);
|
|
119708
119908
|
onOpenReferencedPath?.(absolute, line);
|
|
119709
119909
|
}
|
|
119710
|
-
function previewReferencedPath(path, line) {
|
|
119910
|
+
function previewReferencedPath(path, line, anchor) {
|
|
119711
119911
|
const absolute = resolvedReferencedPath(path);
|
|
119712
|
-
onPreviewReferencedPath?.(absolute, line);
|
|
119912
|
+
onPreviewReferencedPath?.(absolute, line, anchor);
|
|
119713
119913
|
}
|
|
119714
119914
|
function handleReact(emoji) {
|
|
119715
119915
|
reactToMessage(msg, emoji);
|
|
@@ -119783,25 +119983,27 @@ var MessageBubble = (0, import_react.memo)(function MessageBubble({ msg, peer, o
|
|
|
119783
119983
|
})
|
|
119784
119984
|
]
|
|
119785
119985
|
}),
|
|
119786
|
-
!isReactionEvent(msg) && reactions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
119787
|
-
className: cn$1("flex flex-wrap gap-0.5 -mt-1 relative z-10", isOutbound ? "justify-end pr-2" : "justify-start pl-2"),
|
|
119788
|
-
children:
|
|
119986
|
+
!isReactionEvent(msg) && reactions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
119987
|
+
className: cn$1("flex flex-wrap items-center gap-0.5 -mt-1 relative z-10", isOutbound ? "justify-end pr-2" : "justify-start pl-2"),
|
|
119988
|
+
children: [!isOutbound && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddReaction, {
|
|
119989
|
+
open: showQuickReact,
|
|
119990
|
+
onToggle: () => setShowQuickReact((v) => !v),
|
|
119991
|
+
onReact: handleReact
|
|
119992
|
+
}), reactions.map((reaction) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
119789
119993
|
type: "button",
|
|
119790
119994
|
title: reaction.actors.join(", "),
|
|
119791
119995
|
onClick: () => handleReact(reaction.emoji),
|
|
119792
119996
|
className: cn$1("inline-flex h-5 items-center gap-0.5 rounded-full border px-1.5 text-[11px] shadow-sm transition-colors", reaction.mine ? "border-primary/40 bg-primary/10 text-primary" : "border-border bg-background hover:bg-muted text-foreground"),
|
|
119793
119997
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: reaction.emoji }), reaction.count > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: reaction.count })]
|
|
119794
|
-
}, reaction.emoji))
|
|
119998
|
+
}, reaction.emoji))]
|
|
119795
119999
|
}),
|
|
119796
|
-
!isReactionEvent(msg) && !isOutbound && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
119797
|
-
className:
|
|
119798
|
-
children:
|
|
119799
|
-
|
|
119800
|
-
|
|
119801
|
-
|
|
119802
|
-
|
|
119803
|
-
children: emoji
|
|
119804
|
-
}, emoji))
|
|
120000
|
+
!isReactionEvent(msg) && !isOutbound && reactions.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120001
|
+
className: "absolute -bottom-2.5 left-1 z-20",
|
|
120002
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddReaction, {
|
|
120003
|
+
open: showQuickReact,
|
|
120004
|
+
onToggle: () => setShowQuickReact((v) => !v),
|
|
120005
|
+
onReact: handleReact
|
|
120006
|
+
})
|
|
119805
120007
|
})
|
|
119806
120008
|
]
|
|
119807
120009
|
})
|
|
@@ -119961,6 +120163,7 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
119961
120163
|
const [terminalTarget, setTerminalTarget] = (0, import_react.useState)(null);
|
|
119962
120164
|
const [terminalOpening, setTerminalOpening] = (0, import_react.useState)(false);
|
|
119963
120165
|
const [filePreview, setFilePreview] = (0, import_react.useState)(null);
|
|
120166
|
+
const [floatingPreview, setFloatingPreview] = (0, import_react.useState)(null);
|
|
119964
120167
|
const [filePreviewError, setFilePreviewError] = (0, import_react.useState)("");
|
|
119965
120168
|
const filePreviewCloseTimer = (0, import_react.useRef)(null);
|
|
119966
120169
|
const filePreviewRequest = (0, import_react.useRef)(0);
|
|
@@ -120059,17 +120262,17 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
120059
120262
|
return null;
|
|
120060
120263
|
}
|
|
120061
120264
|
}, [orchestrators]);
|
|
120062
|
-
const previewReferencedFile = (0, import_react.useCallback)((path, line) => {
|
|
120063
|
-
if (!supportsSideFilePreview()) return;
|
|
120265
|
+
const previewReferencedFile = (0, import_react.useCallback)((path, line, anchor) => {
|
|
120266
|
+
if (!supportsSideFilePreview() || !anchor) return;
|
|
120064
120267
|
const request = ++filePreviewRequest.current;
|
|
120065
120268
|
resolveReferencedFile(path).then((info) => {
|
|
120066
120269
|
if (filePreviewRequest.current !== request) return;
|
|
120067
120270
|
if (!info) return;
|
|
120068
120271
|
clearFilePreviewCloseTimer();
|
|
120069
|
-
|
|
120272
|
+
setFloatingPreview({
|
|
120070
120273
|
...info,
|
|
120071
120274
|
line: line || 0,
|
|
120072
|
-
|
|
120275
|
+
anchor
|
|
120073
120276
|
});
|
|
120074
120277
|
setFilePreviewError("");
|
|
120075
120278
|
});
|
|
@@ -120078,7 +120281,7 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
120078
120281
|
filePreviewRequest.current += 1;
|
|
120079
120282
|
clearFilePreviewCloseTimer();
|
|
120080
120283
|
filePreviewCloseTimer.current = window.setTimeout(() => {
|
|
120081
|
-
|
|
120284
|
+
setFloatingPreview(null);
|
|
120082
120285
|
}, 250);
|
|
120083
120286
|
}, [clearFilePreviewCloseTimer]);
|
|
120084
120287
|
const openReferencedFile = (0, import_react.useCallback)((path, line) => {
|
|
@@ -120088,11 +120291,12 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
120088
120291
|
return;
|
|
120089
120292
|
}
|
|
120090
120293
|
if (supportsSideFilePreview()) {
|
|
120294
|
+
filePreviewRequest.current += 1;
|
|
120091
120295
|
clearFilePreviewCloseTimer();
|
|
120296
|
+
setFloatingPreview(null);
|
|
120092
120297
|
setFilePreview({
|
|
120093
120298
|
...info,
|
|
120094
|
-
line: line || 0
|
|
120095
|
-
pinned: true
|
|
120299
|
+
line: line || 0
|
|
120096
120300
|
});
|
|
120097
120301
|
setFilePreviewError("");
|
|
120098
120302
|
return;
|
|
@@ -120117,8 +120321,6 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
120117
120321
|
showError
|
|
120118
120322
|
]);
|
|
120119
120323
|
function closeFilePreview() {
|
|
120120
|
-
filePreviewRequest.current += 1;
|
|
120121
|
-
clearFilePreviewCloseTimer();
|
|
120122
120324
|
setFilePreview(null);
|
|
120123
120325
|
setFilePreviewError("");
|
|
120124
120326
|
}
|
|
@@ -120209,372 +120411,380 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
120209
120411
|
children: "Select an agent to start chatting"
|
|
120210
120412
|
})]
|
|
120211
120413
|
});
|
|
120212
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
120213
|
-
|
|
120214
|
-
|
|
120215
|
-
|
|
120216
|
-
|
|
120217
|
-
|
|
120218
|
-
|
|
120219
|
-
|
|
120220
|
-
|
|
120221
|
-
|
|
120222
|
-
|
|
120223
|
-
|
|
120224
|
-
|
|
120225
|
-
|
|
120226
|
-
|
|
120227
|
-
|
|
120228
|
-
|
|
120229
|
-
|
|
120230
|
-
|
|
120231
|
-
|
|
120232
|
-
|
|
120233
|
-
|
|
120234
|
-
|
|
120235
|
-
|
|
120236
|
-
|
|
120237
|
-
agent,
|
|
120238
|
-
|
|
120239
|
-
|
|
120240
|
-
|
|
120241
|
-
|
|
120242
|
-
|
|
120243
|
-
|
|
120244
|
-
|
|
120245
|
-
|
|
120246
|
-
|
|
120247
|
-
|
|
120248
|
-
|
|
120249
|
-
|
|
120250
|
-
|
|
120251
|
-
|
|
120252
|
-
|
|
120414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
120415
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120416
|
+
className: "flex h-full min-w-0",
|
|
120417
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120418
|
+
className: "flex h-full min-w-0 flex-1 flex-col",
|
|
120419
|
+
children: [
|
|
120420
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120421
|
+
className: "flex items-center justify-between px-3 md:px-4 py-2.5 md:py-3 border-b border-border shrink-0",
|
|
120422
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120423
|
+
className: "flex items-center gap-2 md:gap-2.5 min-w-0",
|
|
120424
|
+
children: [
|
|
120425
|
+
showBackButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120426
|
+
variant: "ghost",
|
|
120427
|
+
size: "icon-sm",
|
|
120428
|
+
onClick: onBack,
|
|
120429
|
+
className: "shrink-0 -ml-1",
|
|
120430
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowLeft, { className: "w-4 h-4" })
|
|
120431
|
+
}),
|
|
120432
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
120433
|
+
type: "button",
|
|
120434
|
+
className: "flex items-center gap-2 md:gap-2.5 min-w-0 hover:opacity-80 transition-opacity",
|
|
120435
|
+
onClick: () => agent && openAgentDetail(agent),
|
|
120436
|
+
disabled: !agent,
|
|
120437
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120438
|
+
className: "relative shrink-0",
|
|
120439
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentTypeIcon, { agent }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusDot, {
|
|
120440
|
+
agent,
|
|
120441
|
+
now,
|
|
120442
|
+
className: "absolute -bottom-0.5 -right-0.5 w-2 h-2"
|
|
120443
|
+
})]
|
|
120444
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120445
|
+
className: "min-w-0 text-left",
|
|
120446
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
120447
|
+
className: "text-sm font-medium truncate",
|
|
120448
|
+
children: agent ? displayName(agent) : selectedInboxThread
|
|
120449
|
+
}), agent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
|
|
120450
|
+
className: "text-xs text-muted-foreground truncate",
|
|
120451
|
+
children: [
|
|
120452
|
+
blockedState ? `blocked: ${blockedState.label}` : agent.status,
|
|
120453
|
+
agent.machine && ` · ${agent.machine}`,
|
|
120454
|
+
typeof agent.meta?.cwd === "string" && agent.meta.cwd && ` · ${shortPath$1(agent.meta.cwd, 1)}`
|
|
120455
|
+
]
|
|
120456
|
+
})]
|
|
120253
120457
|
})]
|
|
120254
|
-
})
|
|
120255
|
-
|
|
120256
|
-
|
|
120257
|
-
|
|
120258
|
-
|
|
120259
|
-
|
|
120260
|
-
|
|
120261
|
-
|
|
120262
|
-
|
|
120263
|
-
|
|
120264
|
-
|
|
120265
|
-
|
|
120266
|
-
|
|
120267
|
-
|
|
120268
|
-
|
|
120269
|
-
|
|
120270
|
-
|
|
120271
|
-
|
|
120272
|
-
|
|
120273
|
-
|
|
120274
|
-
|
|
120275
|
-
|
|
120276
|
-
|
|
120277
|
-
|
|
120278
|
-
|
|
120279
|
-
|
|
120280
|
-
|
|
120281
|
-
|
|
120282
|
-
|
|
120283
|
-
|
|
120284
|
-
|
|
120285
|
-
|
|
120286
|
-
|
|
120287
|
-
|
|
120288
|
-
|
|
120289
|
-
|
|
120290
|
-
|
|
120291
|
-
|
|
120292
|
-
|
|
120293
|
-
|
|
120294
|
-
|
|
120295
|
-
|
|
120296
|
-
|
|
120297
|
-
|
|
120298
|
-
|
|
120299
|
-
|
|
120300
|
-
|
|
120301
|
-
|
|
120302
|
-
|
|
120303
|
-
|
|
120304
|
-
|
|
120305
|
-
|
|
120306
|
-
|
|
120307
|
-
|
|
120308
|
-
|
|
120309
|
-
|
|
120310
|
-
|
|
120311
|
-
|
|
120312
|
-
|
|
120313
|
-
|
|
120314
|
-
|
|
120315
|
-
|
|
120316
|
-
|
|
120317
|
-
|
|
120458
|
+
}),
|
|
120459
|
+
agent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentRuntimeChips, {
|
|
120460
|
+
agent,
|
|
120461
|
+
compact: true,
|
|
120462
|
+
className: "hidden md:flex shrink-0"
|
|
120463
|
+
}),
|
|
120464
|
+
agent?.context && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextRing, { utilization: agent.context.utilization }),
|
|
120465
|
+
thread?.attention.unread ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
120466
|
+
className: "bg-red-500/20 text-red-400 text-xs shrink-0 hidden sm:flex",
|
|
120467
|
+
children: [thread.attention.unread, " unread"]
|
|
120468
|
+
}) : null
|
|
120469
|
+
]
|
|
120470
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120471
|
+
className: "flex items-center gap-0.5 md:gap-1 shrink-0",
|
|
120472
|
+
children: agent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
120473
|
+
canOpenTerminal && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120474
|
+
variant: "ghost",
|
|
120475
|
+
size: "icon-sm",
|
|
120476
|
+
className: "hidden sm:inline-flex",
|
|
120477
|
+
disabled: terminalOpening,
|
|
120478
|
+
title: "Terminal",
|
|
120479
|
+
onClick: () => void handleOpenTerminal(),
|
|
120480
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Terminal, { className: "w-3.5 h-3.5" })
|
|
120481
|
+
}),
|
|
120482
|
+
canCompact && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120483
|
+
variant: "ghost",
|
|
120484
|
+
size: "icon-sm",
|
|
120485
|
+
className: "hidden sm:inline-flex",
|
|
120486
|
+
title: "Compact",
|
|
120487
|
+
onClick: () => openConfirm("Compact Agent", `Compact context for ${displayName(agent)}?`, () => doAgentAction(agent, "compact")),
|
|
120488
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minimize2, { className: "w-3.5 h-3.5" })
|
|
120489
|
+
}),
|
|
120490
|
+
canClearContext && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120491
|
+
variant: "ghost",
|
|
120492
|
+
size: "icon-sm",
|
|
120493
|
+
className: "hidden sm:inline-flex",
|
|
120494
|
+
title: "Clear context",
|
|
120495
|
+
onClick: () => openConfirm("Clear Context", `Clear context for ${displayName(agent)}?`, () => doAgentAction(agent, "clearContext")),
|
|
120496
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eraser, { className: "w-3.5 h-3.5" })
|
|
120497
|
+
}),
|
|
120498
|
+
canShutdown && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120499
|
+
variant: "ghost",
|
|
120500
|
+
size: "icon-sm",
|
|
120501
|
+
className: "hidden sm:inline-flex",
|
|
120502
|
+
title: "Shutdown",
|
|
120503
|
+
onClick: () => openConfirm("Shutdown Agent", `Shutdown ${displayName(agent)}?`, () => doAgentAction(agent, "shutdown")),
|
|
120504
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Power, { className: "w-3.5 h-3.5" })
|
|
120505
|
+
}),
|
|
120506
|
+
agent && typeof agent.meta?.cwd === "string" && agent.meta.cwd && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120507
|
+
variant: "ghost",
|
|
120508
|
+
size: "icon-sm",
|
|
120509
|
+
className: "hidden sm:inline-flex",
|
|
120510
|
+
title: `Open ${agent.meta.cwd} in Files`,
|
|
120511
|
+
onClick: () => void openFilesForAgent(agent),
|
|
120512
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderOpen, { className: "w-3.5 h-3.5" })
|
|
120513
|
+
}),
|
|
120514
|
+
agent && thread && thread.messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120515
|
+
variant: "ghost",
|
|
120516
|
+
size: "icon-sm",
|
|
120517
|
+
className: "hidden sm:inline-flex",
|
|
120518
|
+
title: "Fork — spawn new agent with this chat history",
|
|
120519
|
+
onClick: () => forkFromAgent(agent.id, thread.messages),
|
|
120520
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFork, { className: "w-3.5 h-3.5" })
|
|
120521
|
+
}),
|
|
120522
|
+
thread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120523
|
+
variant: "ghost",
|
|
120524
|
+
size: "icon-sm",
|
|
120525
|
+
className: "hidden sm:inline-flex",
|
|
120526
|
+
title: "Mark unread",
|
|
120527
|
+
onClick: () => markInboxThreadUnread(selectedInboxThread),
|
|
120528
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailX, { className: "w-3.5 h-3.5" })
|
|
120529
|
+
}),
|
|
120530
|
+
thread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120531
|
+
variant: "ghost",
|
|
120532
|
+
size: "icon-sm",
|
|
120533
|
+
className: "hidden sm:inline-flex",
|
|
120534
|
+
title: "Mark read",
|
|
120535
|
+
onClick: () => markInboxThreadRead(thread.peer, thread.messages),
|
|
120536
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailOpen, { className: "w-3.5 h-3.5" })
|
|
120537
|
+
}),
|
|
120538
|
+
exportableThread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120539
|
+
variant: "ghost",
|
|
120540
|
+
size: "icon-sm",
|
|
120541
|
+
className: "hidden sm:inline-flex",
|
|
120542
|
+
title: "Export thread",
|
|
120543
|
+
onClick: () => exportThread({
|
|
120544
|
+
...exportableThread,
|
|
120545
|
+
importedHistory
|
|
120546
|
+
}, "json"),
|
|
120547
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "w-3.5 h-3.5" })
|
|
120548
|
+
}),
|
|
120549
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenu, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DropdownMenuTrigger, {
|
|
120550
|
+
asChild: true,
|
|
120551
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120552
|
+
variant: "ghost",
|
|
120553
|
+
size: "icon-sm",
|
|
120554
|
+
className: "sm:hidden",
|
|
120555
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Ellipsis, { className: "w-3.5 h-3.5" })
|
|
120556
|
+
})
|
|
120557
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuContent, {
|
|
120558
|
+
align: "end",
|
|
120559
|
+
children: [
|
|
120560
|
+
canOpenTerminal && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120561
|
+
disabled: terminalOpening,
|
|
120562
|
+
onClick: () => void handleOpenTerminal(),
|
|
120563
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Terminal, { className: "w-3.5 h-3.5" }), "Terminal"]
|
|
120564
|
+
}),
|
|
120565
|
+
canCompact && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120566
|
+
onClick: () => openConfirm("Compact Agent", `Compact context for ${displayName(agent)}?`, () => doAgentAction(agent, "compact")),
|
|
120567
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minimize2, { className: "w-3.5 h-3.5" }), "Compact"]
|
|
120568
|
+
}),
|
|
120569
|
+
canClearContext && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120570
|
+
onClick: () => openConfirm("Clear Context", `Clear context for ${displayName(agent)}?`, () => doAgentAction(agent, "clearContext")),
|
|
120571
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eraser, { className: "w-3.5 h-3.5" }), "Clear Context"]
|
|
120572
|
+
}),
|
|
120573
|
+
canShutdown && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120574
|
+
onClick: () => openConfirm("Shutdown Agent", `Shutdown ${displayName(agent)}?`, () => doAgentAction(agent, "shutdown")),
|
|
120575
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Power, { className: "w-3.5 h-3.5" }), "Shutdown"]
|
|
120576
|
+
}),
|
|
120577
|
+
agent && typeof agent.meta?.cwd === "string" && agent.meta.cwd && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120578
|
+
onClick: () => void openFilesForAgent(agent),
|
|
120579
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderOpen, { className: "w-3.5 h-3.5" }), "Open Files"]
|
|
120580
|
+
}),
|
|
120581
|
+
agent && thread && thread.messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120582
|
+
onClick: () => forkFromAgent(agent.id, thread.messages),
|
|
120583
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFork, { className: "w-3.5 h-3.5" }), "Fork"]
|
|
120584
|
+
}),
|
|
120585
|
+
(canOpenTerminal || canCompact || canClearContext || canShutdown) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DropdownMenuSeparator, {}),
|
|
120586
|
+
thread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120587
|
+
onClick: () => markInboxThreadUnread(selectedInboxThread),
|
|
120588
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailX, { className: "w-3.5 h-3.5" }), "Mark Unread"]
|
|
120589
|
+
}),
|
|
120590
|
+
thread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120591
|
+
onClick: () => markInboxThreadRead(thread.peer, thread.messages),
|
|
120592
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailOpen, { className: "w-3.5 h-3.5" }), "Mark Read"]
|
|
120593
|
+
}),
|
|
120594
|
+
exportableThread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120595
|
+
onClick: () => exportThread({
|
|
120596
|
+
...exportableThread,
|
|
120597
|
+
importedHistory
|
|
120598
|
+
}, "json"),
|
|
120599
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "w-3.5 h-3.5" }), "Download"]
|
|
120600
|
+
})
|
|
120601
|
+
]
|
|
120602
|
+
})] })
|
|
120603
|
+
] })
|
|
120604
|
+
})]
|
|
120605
|
+
}),
|
|
120606
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120607
|
+
ref: pinnedScroll.ref,
|
|
120608
|
+
onScroll: pinnedScroll.onScroll,
|
|
120609
|
+
className: "flex-1 overflow-y-auto px-3 md:px-4 py-3 md:py-4",
|
|
120610
|
+
style: { minHeight: 0 },
|
|
120611
|
+
children: timeline.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120612
|
+
className: "flex flex-col items-center justify-center h-full text-center",
|
|
120613
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageSquare, { className: "w-8 h-8 text-zinc-600 mb-2" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
120614
|
+
className: "text-xs text-muted-foreground",
|
|
120615
|
+
children: "No messages yet"
|
|
120616
|
+
})]
|
|
120617
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
120618
|
+
timeline.map((entry) => {
|
|
120619
|
+
if (entry.type === "message") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageBubble, {
|
|
120620
|
+
msg: entry.msg,
|
|
120621
|
+
peer: selectedInboxThread,
|
|
120622
|
+
onOpenReferencedPath: openReferencedFile,
|
|
120623
|
+
onPreviewReferencedPath: previewReferencedFile,
|
|
120624
|
+
onPreviewReferencedPathEnd: scheduleCloseReferencedFilePreview
|
|
120625
|
+
}, entry.msg.id);
|
|
120626
|
+
if (entry.type === "import-boundary") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImportedHistoryMarker, { history: entry.history }, `import-${entry.history.id}`);
|
|
120627
|
+
if (entry.type === "imported-message") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImportedMessageBubble, {
|
|
120628
|
+
entry: entry.entry,
|
|
120629
|
+
sourceLabel: entry.history.sourceAgentLabel || entry.history.sourcePeerId
|
|
120630
|
+
}, `import-${entry.history.id}-${entry.entry.originalMessageId}-${entry.entry.position}`);
|
|
120631
|
+
if (entry.type === "status") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusMarker, { event: entry.event }, entry.event.id);
|
|
120632
|
+
if (entry.type === "date") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DateSeparator, { date: entry.date }, `d-${entry.date}`);
|
|
120633
|
+
if (entry.type === "created") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreatedMarker, { timestamp: entry.timestamp }, "created");
|
|
120634
|
+
return null;
|
|
120318
120635
|
}),
|
|
120319
|
-
|
|
120320
|
-
|
|
120321
|
-
|
|
120322
|
-
className: "hidden sm:inline-flex",
|
|
120323
|
-
title: "Mark unread",
|
|
120324
|
-
onClick: () => markInboxThreadUnread(selectedInboxThread),
|
|
120325
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailX, { className: "w-3.5 h-3.5" })
|
|
120636
|
+
pendingApproval && agent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PermissionRequestBubble, {
|
|
120637
|
+
agentId: agent.id,
|
|
120638
|
+
approval: pendingApproval
|
|
120326
120639
|
}),
|
|
120327
|
-
|
|
120328
|
-
|
|
120329
|
-
|
|
120330
|
-
|
|
120331
|
-
|
|
120332
|
-
|
|
120333
|
-
|
|
120640
|
+
agent?.status === "busy" && !pendingApproval && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BusyIndicator, { blockedLabel: blockedState?.label })
|
|
120641
|
+
] })
|
|
120642
|
+
}),
|
|
120643
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120644
|
+
className: cn$1("shrink-0 border-t border-border px-3 md:px-4 py-2.5 md:py-3 safe-area-bottom", dragActive && "bg-primary/5 ring-1 ring-primary/40"),
|
|
120645
|
+
onDragOver: (e) => {
|
|
120646
|
+
e.preventDefault();
|
|
120647
|
+
setDragActive(true);
|
|
120648
|
+
},
|
|
120649
|
+
onDragLeave: () => setDragActive(false),
|
|
120650
|
+
onDrop: (e) => {
|
|
120651
|
+
e.preventDefault();
|
|
120652
|
+
setDragActive(false);
|
|
120653
|
+
uploadFiles(e.dataTransfer.files);
|
|
120654
|
+
},
|
|
120655
|
+
children: [
|
|
120656
|
+
pendingAttachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120657
|
+
className: "mb-2 grid gap-2 sm:grid-cols-2",
|
|
120658
|
+
children: pendingAttachments.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PendingAttachmentPreview, {
|
|
120659
|
+
item,
|
|
120660
|
+
onRemove: () => removePendingAttachment(item.id)
|
|
120661
|
+
}, item.id))
|
|
120334
120662
|
}),
|
|
120335
|
-
|
|
120336
|
-
|
|
120337
|
-
|
|
120338
|
-
|
|
120339
|
-
|
|
120340
|
-
|
|
120341
|
-
|
|
120342
|
-
|
|
120343
|
-
}
|
|
120344
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "w-3.5 h-3.5" })
|
|
120663
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
120664
|
+
ref: fileInputRef,
|
|
120665
|
+
type: "file",
|
|
120666
|
+
multiple: true,
|
|
120667
|
+
className: "hidden",
|
|
120668
|
+
onChange: (e) => {
|
|
120669
|
+
if (e.target.files) uploadFiles(e.target.files);
|
|
120670
|
+
e.currentTarget.value = "";
|
|
120671
|
+
}
|
|
120345
120672
|
}),
|
|
120346
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
120347
|
-
|
|
120348
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120349
|
-
variant: "ghost",
|
|
120350
|
-
size: "icon-sm",
|
|
120351
|
-
className: "sm:hidden",
|
|
120352
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Ellipsis, { className: "w-3.5 h-3.5" })
|
|
120353
|
-
})
|
|
120354
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuContent, {
|
|
120355
|
-
align: "end",
|
|
120673
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120674
|
+
className: "hidden md:flex items-end gap-2",
|
|
120356
120675
|
children: [
|
|
120357
|
-
|
|
120358
|
-
|
|
120359
|
-
|
|
120360
|
-
|
|
120361
|
-
|
|
120362
|
-
|
|
120363
|
-
|
|
120364
|
-
children:
|
|
120365
|
-
}),
|
|
120366
|
-
canClearContext && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120367
|
-
onClick: () => openConfirm("Clear Context", `Clear context for ${displayName(agent)}?`, () => doAgentAction(agent, "clearContext")),
|
|
120368
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eraser, { className: "w-3.5 h-3.5" }), "Clear Context"]
|
|
120369
|
-
}),
|
|
120370
|
-
canShutdown && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120371
|
-
onClick: () => openConfirm("Shutdown Agent", `Shutdown ${displayName(agent)}?`, () => doAgentAction(agent, "shutdown")),
|
|
120372
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Power, { className: "w-3.5 h-3.5" }), "Shutdown"]
|
|
120373
|
-
}),
|
|
120374
|
-
agent && typeof agent.meta?.cwd === "string" && agent.meta.cwd && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120375
|
-
onClick: () => void openFilesForAgent(agent),
|
|
120376
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderOpen, { className: "w-3.5 h-3.5" }), "Open Files"]
|
|
120377
|
-
}),
|
|
120378
|
-
agent && thread && thread.messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120379
|
-
onClick: () => forkFromAgent(agent.id, thread.messages),
|
|
120380
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFork, { className: "w-3.5 h-3.5" }), "Fork"]
|
|
120381
|
-
}),
|
|
120382
|
-
(canOpenTerminal || canCompact || canClearContext || canShutdown) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DropdownMenuSeparator, {}),
|
|
120383
|
-
thread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
|
|
120384
|
-
onClick: () => markInboxThreadUnread(selectedInboxThread),
|
|
120385
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailX, { className: "w-3.5 h-3.5" }), "Mark Unread"]
|
|
120676
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120677
|
+
variant: "ghost",
|
|
120678
|
+
size: "icon",
|
|
120679
|
+
title: "Attach files",
|
|
120680
|
+
disabled: chatSending,
|
|
120681
|
+
onClick: () => fileInputRef.current?.click(),
|
|
120682
|
+
className: "shrink-0 mb-0.5 rounded-xl h-[42px] w-[42px]",
|
|
120683
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Paperclip, { className: "w-4 h-4" })
|
|
120386
120684
|
}),
|
|
120387
|
-
|
|
120388
|
-
|
|
120389
|
-
|
|
120685
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoGrowTextarea, {
|
|
120686
|
+
value: draft,
|
|
120687
|
+
onChange: (e) => setReplyDraft(selectedInboxThread, e.target.value),
|
|
120688
|
+
onKeyDown: handleKeyDown,
|
|
120689
|
+
onPaste: handlePaste,
|
|
120690
|
+
placeholder: `Message ${agent ? displayName(agent) : selectedInboxThread}…`,
|
|
120691
|
+
className: "flex-1"
|
|
120390
120692
|
}),
|
|
120391
|
-
|
|
120392
|
-
|
|
120393
|
-
|
|
120394
|
-
|
|
120395
|
-
|
|
120396
|
-
children:
|
|
120693
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120694
|
+
size: "icon",
|
|
120695
|
+
disabled: !draft.trim() && readyAttachments.length === 0 || hasPendingUploads || chatSending,
|
|
120696
|
+
onClick: handleSend,
|
|
120697
|
+
className: "shrink-0 mb-0.5 rounded-xl h-[42px] w-[42px]",
|
|
120698
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Send, { className: "w-4 h-4" })
|
|
120397
120699
|
})
|
|
120398
120700
|
]
|
|
120399
|
-
})
|
|
120400
|
-
|
|
120401
|
-
|
|
120402
|
-
|
|
120403
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120404
|
-
ref: pinnedScroll.ref,
|
|
120405
|
-
onScroll: pinnedScroll.onScroll,
|
|
120406
|
-
className: "flex-1 overflow-y-auto px-3 md:px-4 py-3 md:py-4",
|
|
120407
|
-
style: { minHeight: 0 },
|
|
120408
|
-
children: timeline.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120409
|
-
className: "flex flex-col items-center justify-center h-full text-center",
|
|
120410
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageSquare, { className: "w-8 h-8 text-zinc-600 mb-2" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
120411
|
-
className: "text-xs text-muted-foreground",
|
|
120412
|
-
children: "No messages yet"
|
|
120413
|
-
})]
|
|
120414
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
120415
|
-
timeline.map((entry) => {
|
|
120416
|
-
if (entry.type === "message") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageBubble, {
|
|
120417
|
-
msg: entry.msg,
|
|
120418
|
-
peer: selectedInboxThread,
|
|
120419
|
-
onOpenReferencedPath: openReferencedFile,
|
|
120420
|
-
onPreviewReferencedPath: previewReferencedFile,
|
|
120421
|
-
onPreviewReferencedPathEnd: scheduleCloseReferencedFilePreview
|
|
120422
|
-
}, entry.msg.id);
|
|
120423
|
-
if (entry.type === "import-boundary") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImportedHistoryMarker, { history: entry.history }, `import-${entry.history.id}`);
|
|
120424
|
-
if (entry.type === "imported-message") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImportedMessageBubble, {
|
|
120425
|
-
entry: entry.entry,
|
|
120426
|
-
sourceLabel: entry.history.sourceAgentLabel || entry.history.sourcePeerId
|
|
120427
|
-
}, `import-${entry.history.id}-${entry.entry.originalMessageId}-${entry.entry.position}`);
|
|
120428
|
-
if (entry.type === "status") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusMarker, { event: entry.event }, entry.event.id);
|
|
120429
|
-
if (entry.type === "date") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DateSeparator, { date: entry.date }, `d-${entry.date}`);
|
|
120430
|
-
if (entry.type === "created") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreatedMarker, { timestamp: entry.timestamp }, "created");
|
|
120431
|
-
return null;
|
|
120432
|
-
}),
|
|
120433
|
-
pendingApproval && agent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PermissionRequestBubble, {
|
|
120434
|
-
agentId: agent.id,
|
|
120435
|
-
approval: pendingApproval
|
|
120436
|
-
}),
|
|
120437
|
-
agent?.status === "busy" && !pendingApproval && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BusyIndicator, { blockedLabel: blockedState?.label })
|
|
120438
|
-
] })
|
|
120439
|
-
}),
|
|
120440
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120441
|
-
className: cn$1("shrink-0 border-t border-border px-3 md:px-4 py-2.5 md:py-3 safe-area-bottom", dragActive && "bg-primary/5 ring-1 ring-primary/40"),
|
|
120442
|
-
onDragOver: (e) => {
|
|
120443
|
-
e.preventDefault();
|
|
120444
|
-
setDragActive(true);
|
|
120445
|
-
},
|
|
120446
|
-
onDragLeave: () => setDragActive(false),
|
|
120447
|
-
onDrop: (e) => {
|
|
120448
|
-
e.preventDefault();
|
|
120449
|
-
setDragActive(false);
|
|
120450
|
-
uploadFiles(e.dataTransfer.files);
|
|
120451
|
-
},
|
|
120452
|
-
children: [
|
|
120453
|
-
pendingAttachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120454
|
-
className: "mb-2 grid gap-2 sm:grid-cols-2",
|
|
120455
|
-
children: pendingAttachments.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PendingAttachmentPreview, {
|
|
120456
|
-
item,
|
|
120457
|
-
onRemove: () => removePendingAttachment(item.id)
|
|
120458
|
-
}, item.id))
|
|
120459
|
-
}),
|
|
120460
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
120461
|
-
ref: fileInputRef,
|
|
120462
|
-
type: "file",
|
|
120463
|
-
multiple: true,
|
|
120464
|
-
className: "hidden",
|
|
120465
|
-
onChange: (e) => {
|
|
120466
|
-
if (e.target.files) uploadFiles(e.target.files);
|
|
120467
|
-
e.currentTarget.value = "";
|
|
120468
|
-
}
|
|
120469
|
-
}),
|
|
120470
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120471
|
-
className: "hidden md:flex items-end gap-2",
|
|
120472
|
-
children: [
|
|
120473
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120474
|
-
variant: "ghost",
|
|
120475
|
-
size: "icon",
|
|
120476
|
-
title: "Attach files",
|
|
120477
|
-
disabled: chatSending,
|
|
120478
|
-
onClick: () => fileInputRef.current?.click(),
|
|
120479
|
-
className: "shrink-0 mb-0.5 rounded-xl h-[42px] w-[42px]",
|
|
120480
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Paperclip, { className: "w-4 h-4" })
|
|
120481
|
-
}),
|
|
120482
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoGrowTextarea, {
|
|
120701
|
+
}),
|
|
120702
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120703
|
+
className: "md:hidden space-y-2",
|
|
120704
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoGrowTextarea, {
|
|
120483
120705
|
value: draft,
|
|
120484
120706
|
onChange: (e) => setReplyDraft(selectedInboxThread, e.target.value),
|
|
120485
120707
|
onKeyDown: handleKeyDown,
|
|
120486
120708
|
onPaste: handlePaste,
|
|
120487
120709
|
placeholder: `Message ${agent ? displayName(agent) : selectedInboxThread}…`,
|
|
120488
|
-
className: "
|
|
120489
|
-
}),
|
|
120490
|
-
|
|
120491
|
-
|
|
120492
|
-
|
|
120493
|
-
|
|
120494
|
-
|
|
120495
|
-
|
|
120496
|
-
|
|
120497
|
-
|
|
120498
|
-
|
|
120499
|
-
|
|
120500
|
-
|
|
120501
|
-
|
|
120502
|
-
|
|
120503
|
-
|
|
120504
|
-
|
|
120505
|
-
|
|
120506
|
-
placeholder: `Message ${agent ? displayName(agent) : selectedInboxThread}…`,
|
|
120507
|
-
className: "w-full"
|
|
120508
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120509
|
-
className: "flex items-center justify-between",
|
|
120510
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120511
|
-
variant: "ghost",
|
|
120512
|
-
size: "icon",
|
|
120513
|
-
title: "Attach files",
|
|
120514
|
-
disabled: chatSending,
|
|
120515
|
-
onClick: () => fileInputRef.current?.click(),
|
|
120516
|
-
className: "rounded-xl h-9 w-9",
|
|
120517
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Paperclip, { className: "w-4 h-4" })
|
|
120518
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120519
|
-
size: "icon",
|
|
120520
|
-
disabled: !draft.trim() && readyAttachments.length === 0 || hasPendingUploads || chatSending,
|
|
120521
|
-
onClick: handleSend,
|
|
120522
|
-
className: "rounded-xl h-9 w-9",
|
|
120523
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Send, { className: "w-4 h-4" })
|
|
120710
|
+
className: "w-full"
|
|
120711
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120712
|
+
className: "flex items-center justify-between",
|
|
120713
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120714
|
+
variant: "ghost",
|
|
120715
|
+
size: "icon",
|
|
120716
|
+
title: "Attach files",
|
|
120717
|
+
disabled: chatSending,
|
|
120718
|
+
onClick: () => fileInputRef.current?.click(),
|
|
120719
|
+
className: "rounded-xl h-9 w-9",
|
|
120720
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Paperclip, { className: "w-4 h-4" })
|
|
120721
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120722
|
+
size: "icon",
|
|
120723
|
+
disabled: !draft.trim() && readyAttachments.length === 0 || hasPendingUploads || chatSending,
|
|
120724
|
+
onClick: handleSend,
|
|
120725
|
+
className: "rounded-xl h-9 w-9",
|
|
120726
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Send, { className: "w-4 h-4" })
|
|
120727
|
+
})]
|
|
120524
120728
|
})]
|
|
120525
|
-
})
|
|
120729
|
+
}),
|
|
120730
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
120731
|
+
className: "text-xs text-muted-foreground mt-1.5 hidden md:block",
|
|
120732
|
+
children: "Enter to send · Shift+Enter for newline"
|
|
120733
|
+
})
|
|
120734
|
+
]
|
|
120735
|
+
})
|
|
120736
|
+
]
|
|
120737
|
+
}), filePreview && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
|
|
120738
|
+
className: "hidden h-full w-[min(44vw,720px)] min-w-[360px] shrink-0 flex-col border-l border-border bg-background xl:flex",
|
|
120739
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
120740
|
+
className: "flex h-10 shrink-0 items-center gap-2 border-b border-border px-3",
|
|
120741
|
+
children: [
|
|
120742
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120743
|
+
className: "min-w-0 flex-1 text-xs font-medium text-muted-foreground",
|
|
120744
|
+
children: "File preview"
|
|
120526
120745
|
}),
|
|
120527
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
120528
|
-
className: "text-xs text-
|
|
120529
|
-
children:
|
|
120746
|
+
filePreviewError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120747
|
+
className: "max-w-[18rem] truncate text-xs text-red-400",
|
|
120748
|
+
children: filePreviewError
|
|
120749
|
+
}),
|
|
120750
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120751
|
+
variant: "ghost",
|
|
120752
|
+
size: "icon-sm",
|
|
120753
|
+
title: "Close preview",
|
|
120754
|
+
onClick: closeFilePreview,
|
|
120755
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" })
|
|
120530
120756
|
})
|
|
120531
120757
|
]
|
|
120532
|
-
})
|
|
120533
|
-
|
|
120534
|
-
|
|
120535
|
-
|
|
120536
|
-
|
|
120537
|
-
|
|
120538
|
-
|
|
120539
|
-
|
|
120540
|
-
|
|
120541
|
-
|
|
120542
|
-
|
|
120543
|
-
children: "File preview"
|
|
120544
|
-
}),
|
|
120545
|
-
filePreviewError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
120546
|
-
className: "max-w-[18rem] truncate text-xs text-red-400",
|
|
120547
|
-
children: filePreviewError
|
|
120548
|
-
}),
|
|
120549
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
120550
|
-
variant: "ghost",
|
|
120551
|
-
size: "icon-sm",
|
|
120552
|
-
title: "Close preview",
|
|
120553
|
-
onClick: closeFilePreview,
|
|
120554
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" })
|
|
120758
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120759
|
+
className: "min-h-0 flex-1",
|
|
120760
|
+
children: filePreview.type === "directory" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectoryContent, {
|
|
120761
|
+
orchestratorId: filePreview.orchestratorId,
|
|
120762
|
+
selectedPath: filePreview.path,
|
|
120763
|
+
onReadError: setFilePreviewError
|
|
120764
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileContent, {
|
|
120765
|
+
orchestratorId: filePreview.orchestratorId,
|
|
120766
|
+
selectedPath: filePreview.path,
|
|
120767
|
+
line: filePreview.line,
|
|
120768
|
+
onReadError: setFilePreviewError
|
|
120555
120769
|
})
|
|
120556
|
-
]
|
|
120557
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
120558
|
-
className: "min-h-0 flex-1",
|
|
120559
|
-
children: filePreview.type === "directory" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectoryContent, {
|
|
120560
|
-
orchestratorId: filePreview.orchestratorId,
|
|
120561
|
-
selectedPath: filePreview.path,
|
|
120562
|
-
onReadError: setFilePreviewError
|
|
120563
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileContent, {
|
|
120564
|
-
orchestratorId: filePreview.orchestratorId,
|
|
120565
|
-
selectedPath: filePreview.path,
|
|
120566
|
-
line: filePreview.line,
|
|
120567
|
-
onReadError: setFilePreviewError
|
|
120568
|
-
})
|
|
120770
|
+
})]
|
|
120569
120771
|
})]
|
|
120570
|
-
})
|
|
120571
|
-
|
|
120572
|
-
|
|
120573
|
-
|
|
120574
|
-
|
|
120575
|
-
|
|
120576
|
-
|
|
120577
|
-
|
|
120772
|
+
}),
|
|
120773
|
+
floatingPreview && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FloatingFilePreview, {
|
|
120774
|
+
preview: floatingPreview,
|
|
120775
|
+
error: filePreviewError,
|
|
120776
|
+
onReadError: setFilePreviewError,
|
|
120777
|
+
onMouseEnter: clearFilePreviewCloseTimer,
|
|
120778
|
+
onMouseLeave: scheduleCloseReferencedFilePreview
|
|
120779
|
+
}),
|
|
120780
|
+
terminalTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalDialog, {
|
|
120781
|
+
open: terminalOpen,
|
|
120782
|
+
onOpenChange: handleCloseTerminal,
|
|
120783
|
+
orchestratorId: terminalTarget.orchestratorId,
|
|
120784
|
+
session: terminalTarget.session,
|
|
120785
|
+
interactive: terminalTarget.interactive || canWriteTerminal
|
|
120786
|
+
})
|
|
120787
|
+
] });
|
|
120578
120788
|
}
|
|
120579
120789
|
function ChatView() {
|
|
120580
120790
|
const threads = useAllInboxThreads();
|
|
@@ -121582,6 +121792,8 @@ function ManagedAgentRow({ agent, orch }) {
|
|
|
121582
121792
|
function OrchestratorCard({ orch }) {
|
|
121583
121793
|
const now = useNow();
|
|
121584
121794
|
const orchestratorAction = useRelayStore((s) => s.orchestratorAction);
|
|
121795
|
+
const upgradeOrchestrator = useRelayStore((s) => s.upgradeOrchestrator);
|
|
121796
|
+
const fleetTarget = useRelayStore((s) => s.stats.version);
|
|
121585
121797
|
const openOrchestratorSpawnFor = useRelayStore((s) => s.openOrchestratorSpawnFor);
|
|
121586
121798
|
const openFilesAt = useRelayStore((s) => s.openFilesAt);
|
|
121587
121799
|
const deleteOrchestrator = useRelayStore((s) => s.deleteOrchestrator);
|
|
@@ -121590,6 +121802,10 @@ function OrchestratorCard({ orch }) {
|
|
|
121590
121802
|
const healthClass = orchestratorHealthClass(orch);
|
|
121591
121803
|
const online = orch.status === "online";
|
|
121592
121804
|
const packageVersion = orch.package?.version || orch.version;
|
|
121805
|
+
const upgrade = orch.upgrade;
|
|
121806
|
+
const upgrading = upgrade?.status === "pending";
|
|
121807
|
+
const driftAvailable = online && !!orch.version && !!fleetTarget && orch.version !== fleetTarget;
|
|
121808
|
+
const canUpgrade = online && !upgrading && (driftAvailable || upgrade?.status === "failed");
|
|
121593
121809
|
const contractEntries = Object.entries(orch.contracts || {}).filter(([, value]) => typeof value === "number");
|
|
121594
121810
|
const providerStatus = orch.providerStatus || orch.providers.map((provider) => ({
|
|
121595
121811
|
name: provider,
|
|
@@ -121642,6 +121858,27 @@ function OrchestratorCard({ orch }) {
|
|
|
121642
121858
|
" v",
|
|
121643
121859
|
packageVersion
|
|
121644
121860
|
] }),
|
|
121861
|
+
upgrading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
121862
|
+
className: "text-[10px] bg-amber-500/10 text-amber-400 border-amber-500/20 gap-1",
|
|
121863
|
+
children: [
|
|
121864
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleArrowUp, { className: "w-3 h-3 animate-pulse" }),
|
|
121865
|
+
"upgrading → v",
|
|
121866
|
+
upgrade.desiredVersion
|
|
121867
|
+
]
|
|
121868
|
+
}),
|
|
121869
|
+
!upgrading && upgrade?.status === "failed" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
121870
|
+
className: "text-[10px] bg-red-500/10 text-red-400 border-red-500/20 gap-1",
|
|
121871
|
+
title: upgrade.error,
|
|
121872
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "w-3 h-3" }), "upgrade failed"]
|
|
121873
|
+
}),
|
|
121874
|
+
!upgrading && driftAvailable && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
121875
|
+
className: "text-[10px] bg-blue-500/10 text-blue-400 border-blue-500/20",
|
|
121876
|
+
children: [
|
|
121877
|
+
"→ v",
|
|
121878
|
+
fleetTarget,
|
|
121879
|
+
" available"
|
|
121880
|
+
]
|
|
121881
|
+
}),
|
|
121645
121882
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
121646
121883
|
className: "ml-auto",
|
|
121647
121884
|
children: timeAgo(now, orch.lastSeen)
|
|
@@ -121733,6 +121970,15 @@ function OrchestratorCard({ orch }) {
|
|
|
121733
121970
|
onClick: () => refreshOrchestratorProviders(orch.id),
|
|
121734
121971
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCw, { className: "w-3 h-3" }), "Refresh providers"]
|
|
121735
121972
|
}),
|
|
121973
|
+
(canUpgrade || upgrading) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
121974
|
+
size: "sm",
|
|
121975
|
+
variant: "outline",
|
|
121976
|
+
disabled: upgrading,
|
|
121977
|
+
className: "h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 border-blue-500/30 disabled:opacity-60",
|
|
121978
|
+
title: upgrading ? `Upgrading to v${upgrade.desiredVersion}…` : `Upgrade to v${fleetTarget}`,
|
|
121979
|
+
onClick: () => upgradeOrchestrator(orch.id),
|
|
121980
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleArrowUp, { className: `w-3 h-3 ${upgrading ? "animate-pulse" : ""}` }), upgrading ? "Upgrading…" : "Upgrade"]
|
|
121981
|
+
}),
|
|
121736
121982
|
online && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
121737
121983
|
size: "sm",
|
|
121738
121984
|
variant: "outline",
|
|
@@ -121817,12 +122063,27 @@ var LIVE_STATUSES = new Set([
|
|
|
121817
122063
|
"merge_planned",
|
|
121818
122064
|
"cleanup_requested"
|
|
121819
122065
|
]);
|
|
122066
|
+
var GIT_STATE_STATUSES = new Set([
|
|
122067
|
+
"active",
|
|
122068
|
+
"ready",
|
|
122069
|
+
"conflict",
|
|
122070
|
+
"review_requested",
|
|
122071
|
+
"merge_planned"
|
|
122072
|
+
]);
|
|
122073
|
+
var MERGEABLE_STATUSES = new Set([
|
|
122074
|
+
"active",
|
|
122075
|
+
"ready",
|
|
122076
|
+
"review_requested",
|
|
122077
|
+
"merge_planned",
|
|
122078
|
+
"conflict"
|
|
122079
|
+
]);
|
|
121820
122080
|
var STATUS_CLASS$1 = {
|
|
121821
122081
|
active: "bg-blue-500/10 text-blue-400 border-blue-500/20",
|
|
121822
122082
|
ready: "bg-emerald-500/10 text-emerald-400 border-emerald-500/20",
|
|
121823
122083
|
conflict: "bg-red-500/10 text-red-400 border-red-500/20",
|
|
121824
122084
|
review_requested: "bg-yellow-500/10 text-yellow-400 border-yellow-500/20",
|
|
121825
122085
|
merge_planned: "bg-indigo-500/10 text-indigo-400 border-indigo-500/20",
|
|
122086
|
+
merged: "bg-violet-500/10 text-violet-400 border-violet-500/20",
|
|
121826
122087
|
abandoned: "bg-zinc-500/10 text-zinc-400 border-zinc-500/20",
|
|
121827
122088
|
cleanup_requested: "bg-orange-500/10 text-orange-400 border-orange-500/20",
|
|
121828
122089
|
cleaned: "bg-zinc-500/10 text-zinc-400 border-zinc-500/20"
|
|
@@ -121833,6 +122094,7 @@ var STATUS_LABEL = {
|
|
|
121833
122094
|
conflict: "conflict",
|
|
121834
122095
|
review_requested: "review",
|
|
121835
122096
|
merge_planned: "merge planned",
|
|
122097
|
+
merged: "merged",
|
|
121836
122098
|
abandoned: "abandoned",
|
|
121837
122099
|
cleanup_requested: "cleanup",
|
|
121838
122100
|
cleaned: "cleaned"
|
|
@@ -121844,9 +122106,11 @@ var STATUS_ORDER = {
|
|
|
121844
122106
|
merge_planned: 3,
|
|
121845
122107
|
active: 4,
|
|
121846
122108
|
cleanup_requested: 5,
|
|
121847
|
-
|
|
121848
|
-
|
|
122109
|
+
merged: 6,
|
|
122110
|
+
abandoned: 7,
|
|
122111
|
+
cleaned: 8
|
|
121849
122112
|
};
|
|
122113
|
+
var TERMINAL_STATUSES = new Set(["cleaned", "merged"]);
|
|
121850
122114
|
function shortPath(path) {
|
|
121851
122115
|
const parts = path.split("/").filter(Boolean);
|
|
121852
122116
|
if (parts.length <= 3) return path || "-";
|
|
@@ -121881,20 +122145,35 @@ function groupWorkspaces(workspaces) {
|
|
|
121881
122145
|
}
|
|
121882
122146
|
function filterWorkspaces(workspaces, filter) {
|
|
121883
122147
|
if (filter === "all") return workspaces;
|
|
121884
|
-
if (filter === "cleaned") return workspaces.filter((workspace) => workspace.status
|
|
121885
|
-
return workspaces.filter((workspace) => workspace.status
|
|
122148
|
+
if (filter === "cleaned") return workspaces.filter((workspace) => TERMINAL_STATUSES.has(workspace.status));
|
|
122149
|
+
return workspaces.filter((workspace) => !TERMINAL_STATUSES.has(workspace.status));
|
|
121886
122150
|
}
|
|
121887
|
-
function WorkspaceActions({ workspace }) {
|
|
122151
|
+
function WorkspaceActions({ workspace, expanded, onToggleDetails }) {
|
|
121888
122152
|
const workspaceAction = useRelayStore((s) => s.workspaceAction);
|
|
122153
|
+
const purgeWorkspace = useRelayStore((s) => s.purgeWorkspace);
|
|
122154
|
+
const fetchWorkspaceMergePreview = useRelayStore((s) => s.fetchWorkspaceMergePreview);
|
|
121889
122155
|
const openFilesAt = useRelayStore((s) => s.openFilesAt);
|
|
121890
|
-
const
|
|
122156
|
+
const terminal = workspace.status === "cleaned" || workspace.status === "merged" || workspace.status === "abandoned";
|
|
122157
|
+
const disabled = terminal || workspace.status === "cleanup_requested";
|
|
121891
122158
|
const openPath = workspace.worktreePath || workspace.sourceCwd || workspace.repoRoot;
|
|
122159
|
+
const mergeable = workspace.mode === "isolated" && Boolean(workspace.worktreePath) && MERGEABLE_STATUSES.has(workspace.status);
|
|
121892
122160
|
async function copyPath() {
|
|
121893
122161
|
await navigator.clipboard?.writeText(openPath);
|
|
121894
122162
|
}
|
|
122163
|
+
async function merge() {
|
|
122164
|
+
await fetchWorkspaceMergePreview(workspace.id);
|
|
122165
|
+
await workspaceAction(workspace.id, "merge");
|
|
122166
|
+
}
|
|
121895
122167
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
121896
122168
|
className: "flex flex-wrap justify-end gap-1.5",
|
|
121897
122169
|
children: [
|
|
122170
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
122171
|
+
size: "icon-sm",
|
|
122172
|
+
variant: "ghost",
|
|
122173
|
+
title: expanded ? "Hide details" : "Show diff & timeline",
|
|
122174
|
+
onClick: onToggleDetails,
|
|
122175
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { className: "h-3.5 w-3.5" })
|
|
122176
|
+
}),
|
|
121898
122177
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
121899
122178
|
size: "icon-sm",
|
|
121900
122179
|
variant: "ghost",
|
|
@@ -121933,108 +122212,477 @@ function WorkspaceActions({ workspace }) {
|
|
|
121933
122212
|
title: "Mark merge planned",
|
|
121934
122213
|
disabled: disabled || workspace.status === "merge_planned",
|
|
121935
122214
|
onClick: () => void workspaceAction(workspace.id, "merge-plan"),
|
|
122215
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Flag, { className: "h-3.5 w-3.5" })
|
|
122216
|
+
}),
|
|
122217
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
122218
|
+
size: "icon-sm",
|
|
122219
|
+
variant: "default",
|
|
122220
|
+
title: "Merge & land work",
|
|
122221
|
+
disabled: !mergeable,
|
|
122222
|
+
onClick: () => void merge(),
|
|
121936
122223
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitMerge, { className: "h-3.5 w-3.5" })
|
|
121937
122224
|
}),
|
|
121938
122225
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
121939
122226
|
size: "icon-sm",
|
|
121940
122227
|
variant: "outline",
|
|
121941
|
-
title: "Request cleanup",
|
|
122228
|
+
title: "Request cleanup (removes the worktree on the host)",
|
|
121942
122229
|
disabled: workspace.status === "cleaned" || workspace.status === "cleanup_requested",
|
|
121943
122230
|
onClick: () => void workspaceAction(workspace.id, "cleanup"),
|
|
121944
122231
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" })
|
|
122232
|
+
}),
|
|
122233
|
+
terminal && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
122234
|
+
size: "icon-sm",
|
|
122235
|
+
variant: "ghost",
|
|
122236
|
+
title: "Purge record (clears the row, does not touch disk)",
|
|
122237
|
+
onClick: () => void purgeWorkspace(workspace.id),
|
|
122238
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" })
|
|
121945
122239
|
})
|
|
121946
122240
|
]
|
|
121947
122241
|
});
|
|
121948
122242
|
}
|
|
121949
|
-
function
|
|
122243
|
+
function MergePreviewHint({ workspace, ahead }) {
|
|
122244
|
+
const preview = useRelayStore((s) => s.workspaceMergePreview[workspace.id]);
|
|
122245
|
+
const fetchWorkspaceMergePreview = useRelayStore((s) => s.fetchWorkspaceMergePreview);
|
|
122246
|
+
const eligible = ahead > 0 && MERGEABLE_STATUSES.has(workspace.status);
|
|
122247
|
+
(0, import_react.useEffect)(() => {
|
|
122248
|
+
if (eligible && preview === void 0) fetchWorkspaceMergePreview(workspace.id);
|
|
122249
|
+
}, [
|
|
122250
|
+
eligible,
|
|
122251
|
+
preview,
|
|
122252
|
+
workspace.id,
|
|
122253
|
+
fetchWorkspaceMergePreview
|
|
122254
|
+
]);
|
|
122255
|
+
if (!eligible || preview === void 0 || preview.available === false) return null;
|
|
122256
|
+
if (preview.conflict) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122257
|
+
className: "flex items-center gap-0.5 text-amber-400",
|
|
122258
|
+
title: `Merging into ${preview.baseRef || "base"} would conflict — resolve before merging`,
|
|
122259
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-3 w-3" }), "conflict"]
|
|
122260
|
+
});
|
|
122261
|
+
if (preview.conflict === false) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122262
|
+
className: "flex items-center gap-0.5 text-emerald-400",
|
|
122263
|
+
title: `Clean to merge via ${preview.strategy === "pr" ? "PR" : "rebase + fast-forward"} into ${preview.baseRef || "base"}`,
|
|
122264
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3 w-3" }), preview.strategy === "pr" ? "PR ready" : "clean"]
|
|
122265
|
+
});
|
|
122266
|
+
return null;
|
|
122267
|
+
}
|
|
122268
|
+
function GitState({ workspace }) {
|
|
121950
122269
|
const now = useNow();
|
|
121951
|
-
const
|
|
121952
|
-
const
|
|
121953
|
-
const
|
|
121954
|
-
|
|
122270
|
+
const gitState = useRelayStore((s) => s.workspaceGitState[workspace.id]);
|
|
122271
|
+
const fetchWorkspaceGitState = useRelayStore((s) => s.fetchWorkspaceGitState);
|
|
122272
|
+
const eligible = workspace.mode === "isolated" && Boolean(workspace.worktreePath) && GIT_STATE_STATUSES.has(workspace.status);
|
|
122273
|
+
(0, import_react.useEffect)(() => {
|
|
122274
|
+
if (eligible && gitState === void 0) fetchWorkspaceGitState(workspace.id);
|
|
122275
|
+
}, [
|
|
122276
|
+
eligible,
|
|
122277
|
+
gitState,
|
|
122278
|
+
workspace.id,
|
|
122279
|
+
fetchWorkspaceGitState
|
|
122280
|
+
]);
|
|
122281
|
+
if (!eligible) return null;
|
|
122282
|
+
const refresh = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
122283
|
+
size: "icon-sm",
|
|
122284
|
+
variant: "ghost",
|
|
122285
|
+
className: "h-5 w-5",
|
|
122286
|
+
title: "Refresh git state",
|
|
122287
|
+
onClick: () => void fetchWorkspaceGitState(workspace.id),
|
|
122288
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "h-3 w-3" })
|
|
122289
|
+
});
|
|
122290
|
+
if (gitState === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122291
|
+
className: "flex items-center gap-1 text-[11px] text-muted-foreground",
|
|
122292
|
+
children: "Loading git state…"
|
|
122293
|
+
});
|
|
122294
|
+
if (gitState.available === false) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122295
|
+
className: "flex items-center gap-1 text-[11px] text-muted-foreground",
|
|
122296
|
+
title: gitState.reason,
|
|
122297
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "git state unavailable" }), refresh]
|
|
122298
|
+
});
|
|
122299
|
+
if (gitState.missing) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122300
|
+
className: "flex items-center gap-1 text-[11px] text-muted-foreground",
|
|
122301
|
+
children: ["worktree gone ", refresh]
|
|
122302
|
+
});
|
|
122303
|
+
if (gitState.error) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122304
|
+
className: "flex items-center gap-1 text-[11px] text-red-400",
|
|
122305
|
+
title: gitState.error,
|
|
122306
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "git error" }), refresh]
|
|
122307
|
+
});
|
|
122308
|
+
const ahead = gitState.ahead ?? 0;
|
|
122309
|
+
const behind = gitState.behind ?? 0;
|
|
122310
|
+
const dirty = gitState.dirtyCount ?? 0;
|
|
122311
|
+
const clean = ahead === 0 && dirty === 0;
|
|
122312
|
+
const commit = gitState.lastCommit;
|
|
121955
122313
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
121956
|
-
className: "
|
|
122314
|
+
className: "space-y-0.5",
|
|
122315
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122316
|
+
className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px]",
|
|
122317
|
+
children: [clean ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122318
|
+
className: "text-muted-foreground",
|
|
122319
|
+
children: "no unmerged work"
|
|
122320
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
122321
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122322
|
+
className: ahead > 0 ? "flex items-center text-emerald-400" : "flex items-center text-muted-foreground",
|
|
122323
|
+
title: `${ahead} commit(s) ahead of base`,
|
|
122324
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUp, { className: "h-3 w-3" }), ahead]
|
|
122325
|
+
}),
|
|
122326
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122327
|
+
className: behind > 0 ? "flex items-center text-amber-400" : "flex items-center text-muted-foreground",
|
|
122328
|
+
title: `${behind} commit(s) behind base`,
|
|
122329
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDown, { className: "h-3 w-3" }), behind]
|
|
122330
|
+
}),
|
|
122331
|
+
dirty > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122332
|
+
className: "flex items-center text-orange-400",
|
|
122333
|
+
title: `${dirty} uncommitted change(s)`,
|
|
122334
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilePen, { className: "h-3 w-3" }), dirty]
|
|
122335
|
+
}),
|
|
122336
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MergePreviewHint, {
|
|
122337
|
+
workspace,
|
|
122338
|
+
ahead
|
|
122339
|
+
})
|
|
122340
|
+
] }), refresh]
|
|
122341
|
+
}), commit && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122342
|
+
className: "flex min-w-0 items-center gap-1 text-[11px] text-muted-foreground",
|
|
122343
|
+
title: `${commit.sha.slice(0, 8)} — ${commit.message}`,
|
|
122344
|
+
children: [
|
|
122345
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitCommitHorizontal, { className: "h-3 w-3 shrink-0" }),
|
|
122346
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122347
|
+
className: "truncate",
|
|
122348
|
+
children: commit.message || commit.sha.slice(0, 8)
|
|
122349
|
+
}),
|
|
122350
|
+
commit.at ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122351
|
+
className: "shrink-0 opacity-70",
|
|
122352
|
+
children: ["· ", timeAgo(now, commit.at)]
|
|
122353
|
+
}) : null
|
|
122354
|
+
]
|
|
122355
|
+
})]
|
|
122356
|
+
});
|
|
122357
|
+
}
|
|
122358
|
+
function WorkspaceTimeline({ workspace }) {
|
|
122359
|
+
const now = useNow();
|
|
122360
|
+
const mergedAt = typeof workspace.metadata?.mergedAt === "number" ? workspace.metadata.mergedAt : void 0;
|
|
122361
|
+
const steps = [
|
|
122362
|
+
{
|
|
122363
|
+
label: "created",
|
|
122364
|
+
at: workspace.createdAt
|
|
122365
|
+
},
|
|
122366
|
+
{
|
|
122367
|
+
label: "ready",
|
|
122368
|
+
at: workspace.readyAt
|
|
122369
|
+
},
|
|
122370
|
+
{
|
|
122371
|
+
label: "merged",
|
|
122372
|
+
at: mergedAt
|
|
122373
|
+
},
|
|
122374
|
+
{
|
|
122375
|
+
label: "cleaned",
|
|
122376
|
+
at: workspace.cleanedAt
|
|
122377
|
+
}
|
|
122378
|
+
].filter((step) => typeof step.at === "number" && step.at > 0);
|
|
122379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122380
|
+
className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-muted-foreground",
|
|
122381
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122382
|
+
className: "flex items-center gap-1 font-medium text-foreground",
|
|
122383
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Clock, { className: "h-3 w-3" }), "Timeline"]
|
|
122384
|
+
}), steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122385
|
+
className: "flex items-center gap-1",
|
|
122386
|
+
children: [
|
|
122387
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122388
|
+
className: "opacity-40",
|
|
122389
|
+
children: "→"
|
|
122390
|
+
}),
|
|
122391
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122392
|
+
className: "text-foreground",
|
|
122393
|
+
children: step.label
|
|
122394
|
+
}),
|
|
122395
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122396
|
+
title: new Date(step.at).toLocaleString(),
|
|
122397
|
+
children: timeAgo(now, step.at)
|
|
122398
|
+
})
|
|
122399
|
+
]
|
|
122400
|
+
}, step.label))]
|
|
122401
|
+
});
|
|
122402
|
+
}
|
|
122403
|
+
function diffLineClass(line) {
|
|
122404
|
+
if (line.startsWith("+") && !line.startsWith("+++")) return "text-emerald-400";
|
|
122405
|
+
if (line.startsWith("-") && !line.startsWith("---")) return "text-red-400";
|
|
122406
|
+
if (line.startsWith("@@")) return "text-cyan-400";
|
|
122407
|
+
if (line.startsWith("diff ") || line.startsWith("index ") || line.startsWith("+++") || line.startsWith("---")) return "text-muted-foreground";
|
|
122408
|
+
return "";
|
|
122409
|
+
}
|
|
122410
|
+
function WorkspaceDiffView({ workspace }) {
|
|
122411
|
+
const diff = useRelayStore((s) => s.workspaceDiff[workspace.id]);
|
|
122412
|
+
const fetchWorkspaceDiff = useRelayStore((s) => s.fetchWorkspaceDiff);
|
|
122413
|
+
const eligible = workspace.mode === "isolated" && Boolean(workspace.worktreePath);
|
|
122414
|
+
(0, import_react.useEffect)(() => {
|
|
122415
|
+
if (eligible && diff === void 0) fetchWorkspaceDiff(workspace.id);
|
|
122416
|
+
}, [
|
|
122417
|
+
eligible,
|
|
122418
|
+
diff,
|
|
122419
|
+
workspace.id,
|
|
122420
|
+
fetchWorkspaceDiff
|
|
122421
|
+
]);
|
|
122422
|
+
if (!eligible) return null;
|
|
122423
|
+
if (diff === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122424
|
+
className: "text-[11px] text-muted-foreground",
|
|
122425
|
+
children: "Loading diff…"
|
|
122426
|
+
});
|
|
122427
|
+
if (diff.available === false) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122428
|
+
className: "text-[11px] text-muted-foreground",
|
|
122429
|
+
children: ["Diff unavailable", diff.reason ? `: ${diff.reason}` : ""]
|
|
122430
|
+
});
|
|
122431
|
+
if (diff.missing) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122432
|
+
className: "text-[11px] text-muted-foreground",
|
|
122433
|
+
children: "Worktree no longer on disk"
|
|
122434
|
+
});
|
|
122435
|
+
if (diff.error) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122436
|
+
className: "text-[11px] text-red-400",
|
|
122437
|
+
children: ["Diff error: ", diff.error]
|
|
122438
|
+
});
|
|
122439
|
+
if (!diff.files.length) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122440
|
+
className: "text-[11px] text-muted-foreground",
|
|
122441
|
+
children: ["No committed changes against ", diff.baseRef || "base"]
|
|
122442
|
+
});
|
|
122443
|
+
const refresh = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
122444
|
+
size: "icon-sm",
|
|
122445
|
+
variant: "ghost",
|
|
122446
|
+
className: "h-5 w-5",
|
|
122447
|
+
title: "Refresh diff",
|
|
122448
|
+
onClick: () => void fetchWorkspaceDiff(workspace.id),
|
|
122449
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "h-3 w-3" })
|
|
122450
|
+
});
|
|
122451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122452
|
+
className: "space-y-1",
|
|
121957
122453
|
children: [
|
|
121958
122454
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
121959
|
-
className: "
|
|
121960
|
-
children: [
|
|
121961
|
-
className: "
|
|
121962
|
-
|
|
121963
|
-
|
|
121964
|
-
|
|
121965
|
-
|
|
122455
|
+
className: "flex items-center gap-2 text-[11px] font-medium",
|
|
122456
|
+
children: [
|
|
122457
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileDiff, { className: "h-3 w-3" }),
|
|
122458
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
122459
|
+
diff.files.length,
|
|
122460
|
+
" file",
|
|
122461
|
+
diff.files.length === 1 ? "" : "s",
|
|
122462
|
+
" vs ",
|
|
122463
|
+
diff.baseRef || "base"
|
|
122464
|
+
] }),
|
|
122465
|
+
refresh
|
|
122466
|
+
]
|
|
122467
|
+
}),
|
|
122468
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
|
|
122469
|
+
className: "space-y-0.5 text-[11px]",
|
|
122470
|
+
children: diff.files.map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
|
|
122471
|
+
className: "flex items-center gap-2 font-mono",
|
|
122472
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122473
|
+
className: "truncate",
|
|
122474
|
+
title: file.path,
|
|
122475
|
+
children: file.path
|
|
122476
|
+
}), file.binary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122477
|
+
className: "shrink-0 text-muted-foreground",
|
|
122478
|
+
children: "binary"
|
|
122479
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122480
|
+
className: "shrink-0",
|
|
122481
|
+
children: [
|
|
122482
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122483
|
+
className: "text-emerald-400",
|
|
122484
|
+
children: ["+", file.additions ?? 0]
|
|
122485
|
+
}),
|
|
122486
|
+
" ",
|
|
122487
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
122488
|
+
className: "text-red-400",
|
|
122489
|
+
children: ["−", file.deletions ?? 0]
|
|
122490
|
+
})
|
|
122491
|
+
]
|
|
121966
122492
|
})]
|
|
121967
|
-
}
|
|
121968
|
-
className: "flex flex-wrap gap-1",
|
|
121969
|
-
children: [
|
|
121970
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
121971
|
-
variant: "outline",
|
|
121972
|
-
className: `text-[10px] ${workspace.mode === "isolated" ? "border-sky-500/30 text-sky-400" : "border-zinc-500/30 text-zinc-400"}`,
|
|
121973
|
-
children: workspace.mode
|
|
121974
|
-
}),
|
|
121975
|
-
workspace.requestedMode && workspace.requestedMode !== workspace.mode && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
121976
|
-
variant: "outline",
|
|
121977
|
-
className: "text-[10px]",
|
|
121978
|
-
children: ["requested ", workspace.requestedMode]
|
|
121979
|
-
}),
|
|
121980
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
121981
|
-
variant: "outline",
|
|
121982
|
-
className: `text-[10px] ${statusTone(workspace.status)}`,
|
|
121983
|
-
children: STATUS_LABEL[workspace.status] || workspace.status
|
|
121984
|
-
})
|
|
121985
|
-
]
|
|
121986
|
-
})]
|
|
122493
|
+
}, file.path))
|
|
121987
122494
|
}),
|
|
121988
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("
|
|
121989
|
-
className: "
|
|
121990
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
121991
|
-
className:
|
|
121992
|
-
|
|
121993
|
-
|
|
121994
|
-
|
|
121995
|
-
|
|
121996
|
-
title: workspace.sourceCwd,
|
|
121997
|
-
children: workspace.sourceCwd
|
|
122495
|
+
diff.patch && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("pre", {
|
|
122496
|
+
className: "max-h-80 overflow-auto rounded border border-border bg-muted/30 p-2 text-[10.5px] leading-relaxed",
|
|
122497
|
+
children: [diff.patch.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122498
|
+
className: diffLineClass(line),
|
|
122499
|
+
children: line || " "
|
|
122500
|
+
}, i)), diff.truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122501
|
+
className: "mt-1 text-muted-foreground",
|
|
122502
|
+
children: "… patch truncated"
|
|
121998
122503
|
})]
|
|
121999
|
-
})
|
|
122000
|
-
|
|
122001
|
-
|
|
122504
|
+
})
|
|
122505
|
+
]
|
|
122506
|
+
});
|
|
122507
|
+
}
|
|
122508
|
+
function WorkspaceDetails({ workspace }) {
|
|
122509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122510
|
+
className: "space-y-3 border-t border-dashed border-border bg-muted/20 px-3 py-3",
|
|
122511
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceTimeline, { workspace }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceDiffView, { workspace })]
|
|
122512
|
+
});
|
|
122513
|
+
}
|
|
122514
|
+
function OrphanPanel() {
|
|
122515
|
+
const orphans = useRelayStore((s) => s.workspaceOrphans);
|
|
122516
|
+
const fetchWorkspaceOrphans = useRelayStore((s) => s.fetchWorkspaceOrphans);
|
|
122517
|
+
const reclaimWorkspaceOrphan = useRelayStore((s) => s.reclaimWorkspaceOrphan);
|
|
122518
|
+
(0, import_react.useEffect)(() => {
|
|
122519
|
+
fetchWorkspaceOrphans();
|
|
122520
|
+
}, [fetchWorkspaceOrphans]);
|
|
122521
|
+
if (!orphans.length) return null;
|
|
122522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
|
|
122523
|
+
className: "border-amber-500/30",
|
|
122524
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
|
|
122525
|
+
className: "px-4 py-3",
|
|
122526
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122527
|
+
className: "flex items-center gap-2",
|
|
122002
122528
|
children: [
|
|
122003
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
122004
|
-
|
|
122005
|
-
|
|
122529
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PackageOpen, { className: "h-4 w-4 text-amber-400" }),
|
|
122530
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
|
|
122531
|
+
className: "text-sm font-medium",
|
|
122532
|
+
children: "Orphaned worktrees"
|
|
122006
122533
|
}),
|
|
122007
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
122008
|
-
|
|
122009
|
-
|
|
122010
|
-
children:
|
|
122534
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
122535
|
+
variant: "outline",
|
|
122536
|
+
className: "border-amber-500/30 text-amber-400 text-[10px]",
|
|
122537
|
+
children: orphans.length
|
|
122011
122538
|
}),
|
|
122539
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
122540
|
+
size: "icon-sm",
|
|
122541
|
+
variant: "ghost",
|
|
122542
|
+
className: "ml-auto h-6 w-6",
|
|
122543
|
+
title: "Rescan",
|
|
122544
|
+
onClick: () => void fetchWorkspaceOrphans(),
|
|
122545
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "h-3.5 w-3.5" })
|
|
122546
|
+
})
|
|
122547
|
+
]
|
|
122548
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
122549
|
+
className: "mt-1 text-xs text-muted-foreground",
|
|
122550
|
+
children: "Agent worktrees on disk with no live workspace. Reclaim removes them from the host."
|
|
122551
|
+
})]
|
|
122552
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
|
|
122553
|
+
className: "p-0",
|
|
122554
|
+
children: orphans.map((orphan) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122555
|
+
className: "flex items-center gap-3 border-t border-border px-4 py-2 text-xs",
|
|
122556
|
+
children: [
|
|
122557
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitBranch, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
122012
122558
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122013
|
-
className: "
|
|
122014
|
-
|
|
122559
|
+
className: "truncate font-medium",
|
|
122560
|
+
title: orphan.branch,
|
|
122561
|
+
children: orphan.branch || "(detached)"
|
|
122015
122562
|
}),
|
|
122016
122563
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122017
|
-
className: "truncate",
|
|
122018
|
-
title:
|
|
122019
|
-
children:
|
|
122564
|
+
className: "truncate font-mono text-muted-foreground",
|
|
122565
|
+
title: orphan.worktreePath,
|
|
122566
|
+
children: shortPath(orphan.worktreePath)
|
|
122020
122567
|
}),
|
|
122021
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
122022
|
-
|
|
122023
|
-
|
|
122568
|
+
orphan.hadTerminalRow && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
122569
|
+
variant: "outline",
|
|
122570
|
+
className: "text-[10px]",
|
|
122571
|
+
children: "cleanup failed"
|
|
122024
122572
|
}),
|
|
122025
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
122026
|
-
|
|
122027
|
-
|
|
122028
|
-
|
|
122029
|
-
|
|
122030
|
-
className: "
|
|
122031
|
-
|
|
122032
|
-
children: workspace.baseRef
|
|
122033
|
-
})] })
|
|
122573
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
122574
|
+
size: "sm",
|
|
122575
|
+
variant: "outline",
|
|
122576
|
+
className: "ml-auto h-7 text-xs",
|
|
122577
|
+
onClick: () => void reclaimWorkspaceOrphan(orphan),
|
|
122578
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArchiveRestore, { className: "mr-1 h-3.5 w-3.5" }), "Reclaim"]
|
|
122579
|
+
})
|
|
122034
122580
|
]
|
|
122035
|
-
})
|
|
122036
|
-
|
|
122037
|
-
|
|
122581
|
+
}, orphan.worktreePath))
|
|
122582
|
+
})]
|
|
122583
|
+
});
|
|
122584
|
+
}
|
|
122585
|
+
function WorkspaceRow({ workspace }) {
|
|
122586
|
+
const now = useNow();
|
|
122587
|
+
const [expanded, setExpanded] = (0, import_react.useState)(false);
|
|
122588
|
+
const agentsById = useRelayStore((s) => s.agentsById);
|
|
122589
|
+
const owner = workspace.ownerAgentId ? agentsById[workspace.ownerAgentId] : void 0;
|
|
122590
|
+
const steward = workspace.stewardAgentId ? agentsById[workspace.stewardAgentId] : void 0;
|
|
122591
|
+
const path = workspace.worktreePath || workspace.sourceCwd || workspace.repoRoot;
|
|
122592
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122593
|
+
className: "border-t border-border",
|
|
122594
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122595
|
+
className: "grid gap-3 px-3 py-3 text-sm lg:grid-cols-[minmax(180px,1.2fr)_minmax(220px,1.5fr)_minmax(160px,1fr)_minmax(170px,auto)]",
|
|
122596
|
+
children: [
|
|
122597
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122598
|
+
className: "min-w-0 space-y-1",
|
|
122599
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122600
|
+
className: "flex min-w-0 items-center gap-2",
|
|
122601
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitBranch, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122602
|
+
className: "truncate font-medium",
|
|
122603
|
+
title: workspace.branch || workspace.id,
|
|
122604
|
+
children: workspace.branch || workspace.id
|
|
122605
|
+
})]
|
|
122606
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122607
|
+
className: "flex flex-wrap gap-1",
|
|
122608
|
+
children: [
|
|
122609
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
122610
|
+
variant: "outline",
|
|
122611
|
+
className: `text-[10px] ${workspace.mode === "isolated" ? "border-sky-500/30 text-sky-400" : "border-zinc-500/30 text-zinc-400"}`,
|
|
122612
|
+
children: workspace.mode
|
|
122613
|
+
}),
|
|
122614
|
+
workspace.requestedMode && workspace.requestedMode !== workspace.mode && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
122615
|
+
variant: "outline",
|
|
122616
|
+
className: "text-[10px]",
|
|
122617
|
+
children: ["requested ", workspace.requestedMode]
|
|
122618
|
+
}),
|
|
122619
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
122620
|
+
variant: "outline",
|
|
122621
|
+
className: `text-[10px] ${statusTone(workspace.status)}`,
|
|
122622
|
+
children: STATUS_LABEL[workspace.status] || workspace.status
|
|
122623
|
+
})
|
|
122624
|
+
]
|
|
122625
|
+
})]
|
|
122626
|
+
}),
|
|
122627
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122628
|
+
className: "min-w-0 space-y-1",
|
|
122629
|
+
children: [
|
|
122630
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122631
|
+
className: "truncate font-mono text-xs",
|
|
122632
|
+
title: path,
|
|
122633
|
+
children: shortPath(path)
|
|
122634
|
+
}),
|
|
122635
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122636
|
+
className: "truncate text-xs text-muted-foreground",
|
|
122637
|
+
title: workspace.sourceCwd,
|
|
122638
|
+
children: workspace.sourceCwd
|
|
122639
|
+
}),
|
|
122640
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitState, { workspace })
|
|
122641
|
+
]
|
|
122642
|
+
}),
|
|
122643
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
122644
|
+
className: "grid grid-cols-[4.5rem_minmax(0,1fr)] gap-x-2 gap-y-1 text-xs",
|
|
122645
|
+
children: [
|
|
122646
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122647
|
+
className: "text-muted-foreground",
|
|
122648
|
+
children: "Owner"
|
|
122649
|
+
}),
|
|
122650
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122651
|
+
className: "truncate",
|
|
122652
|
+
title: workspace.ownerAgentId,
|
|
122653
|
+
children: agentLabel(owner, workspace.ownerPolicyName || workspace.ownerAgentId)
|
|
122654
|
+
}),
|
|
122655
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122656
|
+
className: "text-muted-foreground",
|
|
122657
|
+
children: "Steward"
|
|
122658
|
+
}),
|
|
122659
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122660
|
+
className: "truncate",
|
|
122661
|
+
title: workspace.stewardAgentId,
|
|
122662
|
+
children: agentLabel(steward, workspace.stewardAgentId)
|
|
122663
|
+
}),
|
|
122664
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122665
|
+
className: "text-muted-foreground",
|
|
122666
|
+
children: "Updated"
|
|
122667
|
+
}),
|
|
122668
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: timeAgo(now, workspace.updatedAt) }),
|
|
122669
|
+
workspace.baseRef && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122670
|
+
className: "text-muted-foreground",
|
|
122671
|
+
children: "Base"
|
|
122672
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
122673
|
+
className: "truncate",
|
|
122674
|
+
title: workspace.baseSha,
|
|
122675
|
+
children: workspace.baseRef
|
|
122676
|
+
})] })
|
|
122677
|
+
]
|
|
122678
|
+
}),
|
|
122679
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceActions, {
|
|
122680
|
+
workspace,
|
|
122681
|
+
expanded,
|
|
122682
|
+
onToggleDetails: () => setExpanded((value) => !value)
|
|
122683
|
+
})
|
|
122684
|
+
]
|
|
122685
|
+
}), expanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceDetails, { workspace })]
|
|
122038
122686
|
});
|
|
122039
122687
|
}
|
|
122040
122688
|
function RepoGroup({ repoRoot, workspaces }) {
|
|
@@ -122092,17 +122740,17 @@ function WorkspacesView() {
|
|
|
122092
122740
|
const isolatedCount = workspaces.filter((item) => item.mode === "isolated").length;
|
|
122093
122741
|
const readyCount = workspaces.filter((item) => item.status === "ready" || item.status === "review_requested" || item.status === "merge_planned").length;
|
|
122094
122742
|
const conflictCount = workspaces.filter((item) => item.status === "conflict").length;
|
|
122095
|
-
const
|
|
122743
|
+
const doneCount = workspaces.filter((item) => TERMINAL_STATUSES.has(item.status)).length;
|
|
122096
122744
|
const filters = [
|
|
122097
122745
|
{
|
|
122098
122746
|
key: "active",
|
|
122099
122747
|
label: "Active",
|
|
122100
|
-
count: workspaces.length -
|
|
122748
|
+
count: workspaces.length - doneCount
|
|
122101
122749
|
},
|
|
122102
122750
|
{
|
|
122103
122751
|
key: "cleaned",
|
|
122104
|
-
label: "
|
|
122105
|
-
count:
|
|
122752
|
+
label: "Done",
|
|
122753
|
+
count: doneCount
|
|
122106
122754
|
},
|
|
122107
122755
|
{
|
|
122108
122756
|
key: "all",
|
|
@@ -122144,6 +122792,7 @@ function WorkspacesView() {
|
|
|
122144
122792
|
]
|
|
122145
122793
|
})]
|
|
122146
122794
|
}),
|
|
122795
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(OrphanPanel, {}),
|
|
122147
122796
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
122148
122797
|
className: "flex flex-wrap items-center gap-2",
|
|
122149
122798
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -125120,6 +125769,7 @@ function blankForm(orchestratorId = "") {
|
|
|
125120
125769
|
ifNoMatch: "fail",
|
|
125121
125770
|
cwd: "",
|
|
125122
125771
|
approvalMode: "guarded",
|
|
125772
|
+
workspaceMode: "inherit",
|
|
125123
125773
|
keepAlive: false,
|
|
125124
125774
|
budgetMinutes: "",
|
|
125125
125775
|
warningMinutes: "",
|
|
@@ -125158,6 +125808,7 @@ function automationToForm(automation) {
|
|
|
125158
125808
|
ifNoMatch: policy.mode === "existing_agent" ? policy.ifNoMatch || "fail" : "fail",
|
|
125159
125809
|
cwd: policy.mode === "on_demand_agent" ? policy.cwd || "" : "",
|
|
125160
125810
|
approvalMode: policy.mode === "on_demand_agent" ? policy.approvalMode || "guarded" : "guarded",
|
|
125811
|
+
workspaceMode: policy.mode === "on_demand_agent" ? policy.workspaceMode || "inherit" : "inherit",
|
|
125161
125812
|
keepAlive: policy.mode === "on_demand_agent" ? Boolean(policy.keepAlive) : false,
|
|
125162
125813
|
budgetMinutes: policy.mode === "on_demand_agent" && policy.runtimeBudget ? String(Math.round(policy.runtimeBudget.maxRuntimeMs / 6e4)) : "",
|
|
125163
125814
|
warningMinutes: policy.mode === "on_demand_agent" && policy.runtimeBudget?.warnAtMs !== void 0 ? String(Math.round(policy.runtimeBudget.warnAtMs / 6e4)) : "",
|
|
@@ -125195,6 +125846,7 @@ function formToInput(form) {
|
|
|
125195
125846
|
profile: form.profile || void 0,
|
|
125196
125847
|
cwd: form.cwd.trim() || void 0,
|
|
125197
125848
|
approvalMode: form.approvalMode,
|
|
125849
|
+
workspaceMode: form.workspaceMode,
|
|
125198
125850
|
keepAlive: form.keepAlive,
|
|
125199
125851
|
runtimeBudget
|
|
125200
125852
|
};
|
|
@@ -125799,6 +126451,28 @@ function AutomationEditor({ form, selected, saving, orchestrators, agentProfiles
|
|
|
125799
126451
|
children: profile.name
|
|
125800
126452
|
}, profile.name))]
|
|
125801
126453
|
})
|
|
126454
|
+
}),
|
|
126455
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field$1, {
|
|
126456
|
+
label: "Workspace",
|
|
126457
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
126458
|
+
className: "h-9 w-full rounded-md border border-input bg-background px-3 text-sm",
|
|
126459
|
+
value: form.workspaceMode,
|
|
126460
|
+
onChange: (e) => onChange({ workspaceMode: e.target.value }),
|
|
126461
|
+
children: [
|
|
126462
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
126463
|
+
value: "inherit",
|
|
126464
|
+
children: "inherit (default → isolated worktree)"
|
|
126465
|
+
}),
|
|
126466
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
126467
|
+
value: "shared",
|
|
126468
|
+
children: "shared (run in the repo, commit to its branch)"
|
|
126469
|
+
}),
|
|
126470
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
126471
|
+
value: "isolated",
|
|
126472
|
+
children: "isolated (fresh git worktree per run)"
|
|
126473
|
+
})
|
|
126474
|
+
]
|
|
126475
|
+
})
|
|
125802
126476
|
})
|
|
125803
126477
|
]
|
|
125804
126478
|
}),
|
|
@@ -150319,10 +150993,6 @@ if ("serviceWorker" in navigator) {
|
|
|
150319
150993
|
inset-block: calc(var(--spacing) * 0);
|
|
150320
150994
|
}
|
|
150321
150995
|
|
|
150322
|
-
.-top-3 {
|
|
150323
|
-
top: calc(var(--spacing) * -3);
|
|
150324
|
-
}
|
|
150325
|
-
|
|
150326
150996
|
.top-0 {
|
|
150327
150997
|
top: calc(var(--spacing) * 0);
|
|
150328
150998
|
}
|
|
@@ -150363,6 +151033,14 @@ if ("serviceWorker" in navigator) {
|
|
|
150363
151033
|
bottom: calc(var(--spacing) * -.5);
|
|
150364
151034
|
}
|
|
150365
151035
|
|
|
151036
|
+
.-bottom-2\.5 {
|
|
151037
|
+
bottom: calc(var(--spacing) * -2.5);
|
|
151038
|
+
}
|
|
151039
|
+
|
|
151040
|
+
.bottom-full {
|
|
151041
|
+
bottom: 100%;
|
|
151042
|
+
}
|
|
151043
|
+
|
|
150366
151044
|
.left-0 {
|
|
150367
151045
|
left: calc(var(--spacing) * 0);
|
|
150368
151046
|
}
|
|
@@ -150998,6 +151676,10 @@ if ("serviceWorker" in navigator) {
|
|
|
150998
151676
|
max-width: var(--container-2xl);
|
|
150999
151677
|
}
|
|
151000
151678
|
|
|
151679
|
+
.max-w-\[12rem\] {
|
|
151680
|
+
max-width: 12rem;
|
|
151681
|
+
}
|
|
151682
|
+
|
|
151001
151683
|
.max-w-\[18rem\] {
|
|
151002
151684
|
max-width: 18rem;
|
|
151003
151685
|
}
|
|
@@ -151406,6 +152088,10 @@ if ("serviceWorker" in navigator) {
|
|
|
151406
152088
|
column-gap: calc(var(--spacing) * 4);
|
|
151407
152089
|
}
|
|
151408
152090
|
|
|
152091
|
+
.gap-y-0\.5 {
|
|
152092
|
+
row-gap: calc(var(--spacing) * .5);
|
|
152093
|
+
}
|
|
152094
|
+
|
|
151409
152095
|
.gap-y-1 {
|
|
151410
152096
|
row-gap: calc(var(--spacing) * 1);
|
|
151411
152097
|
}
|
|
@@ -151590,6 +152276,16 @@ if ("serviceWorker" in navigator) {
|
|
|
151590
152276
|
}
|
|
151591
152277
|
}
|
|
151592
152278
|
|
|
152279
|
+
.border-amber-500\/20 {
|
|
152280
|
+
border-color: #f99c0033;
|
|
152281
|
+
}
|
|
152282
|
+
|
|
152283
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
152284
|
+
.border-amber-500\/20 {
|
|
152285
|
+
border-color: color-mix(in oklab, var(--color-amber-500) 20%, transparent);
|
|
152286
|
+
}
|
|
152287
|
+
}
|
|
152288
|
+
|
|
151593
152289
|
.border-amber-500\/25 {
|
|
151594
152290
|
border-color: #f99c0040;
|
|
151595
152291
|
}
|
|
@@ -151912,6 +152608,16 @@ if ("serviceWorker" in navigator) {
|
|
|
151912
152608
|
border-color: #0000;
|
|
151913
152609
|
}
|
|
151914
152610
|
|
|
152611
|
+
.border-violet-500\/20 {
|
|
152612
|
+
border-color: #8d54ff33;
|
|
152613
|
+
}
|
|
152614
|
+
|
|
152615
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
152616
|
+
.border-violet-500\/20 {
|
|
152617
|
+
border-color: color-mix(in oklab, var(--color-violet-500) 20%, transparent);
|
|
152618
|
+
}
|
|
152619
|
+
}
|
|
152620
|
+
|
|
151915
152621
|
.border-violet-500\/30 {
|
|
151916
152622
|
border-color: #8d54ff4d;
|
|
151917
152623
|
}
|
|
@@ -152890,6 +153596,10 @@ if ("serviceWorker" in navigator) {
|
|
|
152890
153596
|
font-size: 9px;
|
|
152891
153597
|
}
|
|
152892
153598
|
|
|
153599
|
+
.text-\[10\.5px\] {
|
|
153600
|
+
font-size: 10.5px;
|
|
153601
|
+
}
|
|
153602
|
+
|
|
152893
153603
|
.text-\[10px\] {
|
|
152894
153604
|
font-size: 10px;
|
|
152895
153605
|
}
|
|
@@ -153124,6 +153834,16 @@ if ("serviceWorker" in navigator) {
|
|
|
153124
153834
|
}
|
|
153125
153835
|
}
|
|
153126
153836
|
|
|
153837
|
+
.text-muted-foreground\/70 {
|
|
153838
|
+
color: var(--muted-foreground);
|
|
153839
|
+
}
|
|
153840
|
+
|
|
153841
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
153842
|
+
.text-muted-foreground\/70 {
|
|
153843
|
+
color: color-mix(in oklab, var(--muted-foreground) 70%, transparent);
|
|
153844
|
+
}
|
|
153845
|
+
}
|
|
153846
|
+
|
|
153127
153847
|
.text-muted-foreground\/80 {
|
|
153128
153848
|
color: var(--muted-foreground);
|
|
153129
153849
|
}
|
|
@@ -153330,6 +154050,10 @@ if ("serviceWorker" in navigator) {
|
|
|
153330
154050
|
opacity: .6;
|
|
153331
154051
|
}
|
|
153332
154052
|
|
|
154053
|
+
.opacity-70 {
|
|
154054
|
+
opacity: .7;
|
|
154055
|
+
}
|
|
154056
|
+
|
|
153333
154057
|
.opacity-80 {
|
|
153334
154058
|
opacity: .8;
|
|
153335
154059
|
}
|
|
@@ -154029,6 +154753,10 @@ if ("serviceWorker" in navigator) {
|
|
|
154029
154753
|
opacity: .5;
|
|
154030
154754
|
}
|
|
154031
154755
|
|
|
154756
|
+
.disabled\:opacity-60:disabled {
|
|
154757
|
+
opacity: .6;
|
|
154758
|
+
}
|
|
154759
|
+
|
|
154032
154760
|
.disabled\:opacity-70:disabled {
|
|
154033
154761
|
opacity: .7;
|
|
154034
154762
|
}
|