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/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
- get().openConfirm(label + " Workspace", `${label} workspace "${target}"?`, run);
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
- const payload = {
12757
- from: HUMAN_AGENT_ID,
12758
- to: thread.peer,
12759
- body: body.trim() || "Attachment"
12760
- };
12761
- if (thread.lastMessage?.channel) payload.channel = thread.lastMessage.channel;
12762
- if (thread.lastMessage?.id) payload.replyTo = thread.lastMessage.id;
12763
- if (attachments.length) payload.payload = { attachments };
12764
- await api("POST", "/messages", payload);
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.jsx)("div", {
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: reactions.map((reaction) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
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: cn$1("absolute -top-3 flex gap-0.5 transition-opacity z-20", showQuickReact ? "opacity-100" : "opacity-0 pointer-events-none md:group-hover/msg:opacity-100 md:group-hover/msg:pointer-events-auto", "left-1"),
119798
- children: QUICK_REACTIONS.map((emoji) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
119799
- type: "button",
119800
- title: `React ${emoji}`,
119801
- onClick: () => handleReact(emoji),
119802
- className: "inline-flex h-6 w-7 items-center justify-center rounded-full border border-border bg-popover text-xs shadow-md transition-colors hover:bg-muted",
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
- setFilePreview({
120272
+ setFloatingPreview({
120070
120273
  ...info,
120071
120274
  line: line || 0,
120072
- pinned: false
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
- setFilePreview((current) => current?.pinned ? current : null);
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: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120213
- className: "flex h-full min-w-0",
120214
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120215
- className: "flex h-full min-w-0 flex-1 flex-col",
120216
- children: [
120217
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120218
- className: "flex items-center justify-between px-3 md:px-4 py-2.5 md:py-3 border-b border-border shrink-0",
120219
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120220
- className: "flex items-center gap-2 md:gap-2.5 min-w-0",
120221
- children: [
120222
- showBackButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120223
- variant: "ghost",
120224
- size: "icon-sm",
120225
- onClick: onBack,
120226
- className: "shrink-0 -ml-1",
120227
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowLeft, { className: "w-4 h-4" })
120228
- }),
120229
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
120230
- type: "button",
120231
- className: "flex items-center gap-2 md:gap-2.5 min-w-0 hover:opacity-80 transition-opacity",
120232
- onClick: () => agent && openAgentDetail(agent),
120233
- disabled: !agent,
120234
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120235
- className: "relative shrink-0",
120236
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentTypeIcon, { agent }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusDot, {
120237
- agent,
120238
- now,
120239
- className: "absolute -bottom-0.5 -right-0.5 w-2 h-2"
120240
- })]
120241
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120242
- className: "min-w-0 text-left",
120243
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
120244
- className: "text-sm font-medium truncate",
120245
- children: agent ? displayName(agent) : selectedInboxThread
120246
- }), agent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
120247
- className: "text-xs text-muted-foreground truncate",
120248
- children: [
120249
- blockedState ? `blocked: ${blockedState.label}` : agent.status,
120250
- agent.machine && ` · ${agent.machine}`,
120251
- typeof agent.meta?.cwd === "string" && agent.meta.cwd && ` · ${shortPath$1(agent.meta.cwd, 1)}`
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
- agent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentRuntimeChips, {
120257
- agent,
120258
- compact: true,
120259
- className: "hidden md:flex shrink-0"
120260
- }),
120261
- agent?.context && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextRing, { utilization: agent.context.utilization }),
120262
- thread?.attention.unread ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
120263
- className: "bg-red-500/20 text-red-400 text-xs shrink-0 hidden sm:flex",
120264
- children: [thread.attention.unread, " unread"]
120265
- }) : null
120266
- ]
120267
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
120268
- className: "flex items-center gap-0.5 md:gap-1 shrink-0",
120269
- children: agent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
120270
- canOpenTerminal && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120271
- variant: "ghost",
120272
- size: "icon-sm",
120273
- className: "hidden sm:inline-flex",
120274
- disabled: terminalOpening,
120275
- title: "Terminal",
120276
- onClick: () => void handleOpenTerminal(),
120277
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Terminal, { className: "w-3.5 h-3.5" })
120278
- }),
120279
- canCompact && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120280
- variant: "ghost",
120281
- size: "icon-sm",
120282
- className: "hidden sm:inline-flex",
120283
- title: "Compact",
120284
- onClick: () => openConfirm("Compact Agent", `Compact context for ${displayName(agent)}?`, () => doAgentAction(agent, "compact")),
120285
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minimize2, { className: "w-3.5 h-3.5" })
120286
- }),
120287
- canClearContext && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120288
- variant: "ghost",
120289
- size: "icon-sm",
120290
- className: "hidden sm:inline-flex",
120291
- title: "Clear context",
120292
- onClick: () => openConfirm("Clear Context", `Clear context for ${displayName(agent)}?`, () => doAgentAction(agent, "clearContext")),
120293
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eraser, { className: "w-3.5 h-3.5" })
120294
- }),
120295
- canShutdown && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120296
- variant: "ghost",
120297
- size: "icon-sm",
120298
- className: "hidden sm:inline-flex",
120299
- title: "Shutdown",
120300
- onClick: () => openConfirm("Shutdown Agent", `Shutdown ${displayName(agent)}?`, () => doAgentAction(agent, "shutdown")),
120301
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Power, { className: "w-3.5 h-3.5" })
120302
- }),
120303
- agent && typeof agent.meta?.cwd === "string" && agent.meta.cwd && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120304
- variant: "ghost",
120305
- size: "icon-sm",
120306
- className: "hidden sm:inline-flex",
120307
- title: `Open ${agent.meta.cwd} in Files`,
120308
- onClick: () => void openFilesForAgent(agent),
120309
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderOpen, { className: "w-3.5 h-3.5" })
120310
- }),
120311
- agent && thread && thread.messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120312
- variant: "ghost",
120313
- size: "icon-sm",
120314
- className: "hidden sm:inline-flex",
120315
- title: "Fork spawn new agent with this chat history",
120316
- onClick: () => forkFromAgent(agent.id, thread.messages),
120317
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFork, { className: "w-3.5 h-3.5" })
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
- thread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120320
- variant: "ghost",
120321
- size: "icon-sm",
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
- thread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120328
- variant: "ghost",
120329
- size: "icon-sm",
120330
- className: "hidden sm:inline-flex",
120331
- title: "Mark read",
120332
- onClick: () => markInboxThreadRead(thread.peer, thread.messages),
120333
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailOpen, { className: "w-3.5 h-3.5" })
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
- exportableThread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120336
- variant: "ghost",
120337
- size: "icon-sm",
120338
- className: "hidden sm:inline-flex",
120339
- title: "Export thread",
120340
- onClick: () => exportThread({
120341
- ...exportableThread,
120342
- importedHistory
120343
- }, "json"),
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)(DropdownMenu, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DropdownMenuTrigger, {
120347
- asChild: true,
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
- canOpenTerminal && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120358
- disabled: terminalOpening,
120359
- onClick: () => void handleOpenTerminal(),
120360
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Terminal, { className: "w-3.5 h-3.5" }), "Terminal"]
120361
- }),
120362
- canCompact && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120363
- onClick: () => openConfirm("Compact Agent", `Compact context for ${displayName(agent)}?`, () => doAgentAction(agent, "compact")),
120364
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minimize2, { className: "w-3.5 h-3.5" }), "Compact"]
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
- thread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120388
- onClick: () => markInboxThreadRead(thread.peer, thread.messages),
120389
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailOpen, { className: "w-3.5 h-3.5" }), "Mark Read"]
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
- exportableThread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120392
- onClick: () => exportThread({
120393
- ...exportableThread,
120394
- importedHistory
120395
- }, "json"),
120396
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "w-3.5 h-3.5" }), "Download"]
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: "flex-1"
120489
- }),
120490
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120491
- size: "icon",
120492
- disabled: !draft.trim() && readyAttachments.length === 0 || hasPendingUploads || chatSending,
120493
- onClick: handleSend,
120494
- className: "shrink-0 mb-0.5 rounded-xl h-[42px] w-[42px]",
120495
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Send, { className: "w-4 h-4" })
120496
- })
120497
- ]
120498
- }),
120499
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120500
- className: "md:hidden space-y-2",
120501
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoGrowTextarea, {
120502
- value: draft,
120503
- onChange: (e) => setReplyDraft(selectedInboxThread, e.target.value),
120504
- onKeyDown: handleKeyDown,
120505
- onPaste: handlePaste,
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)("p", {
120528
- className: "text-xs text-muted-foreground mt-1.5 hidden md:block",
120529
- children: "Enter to send · Shift+Enter for newline"
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
- }), filePreview && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
120535
- className: "hidden h-full w-[min(44vw,720px)] min-w-[360px] shrink-0 flex-col border-l border-border bg-background xl:flex",
120536
- onMouseEnter: clearFilePreviewCloseTimer,
120537
- onMouseLeave: filePreview.pinned ? void 0 : scheduleCloseReferencedFilePreview,
120538
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120539
- className: "flex h-10 shrink-0 items-center gap-2 border-b border-border px-3",
120540
- children: [
120541
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
120542
- className: "min-w-0 flex-1 text-xs font-medium text-muted-foreground",
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
- }), terminalTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalDialog, {
120572
- open: terminalOpen,
120573
- onOpenChange: handleCloseTerminal,
120574
- orchestratorId: terminalTarget.orchestratorId,
120575
- session: terminalTarget.session,
120576
- interactive: terminalTarget.interactive || canWriteTerminal
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
- abandoned: 6,
121848
- cleaned: 7
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 === "cleaned");
121885
- return workspaces.filter((workspace) => workspace.status !== "cleaned");
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 disabled = workspace.status === "cleaned" || workspace.status === "abandoned" || workspace.status === "cleanup_requested";
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 WorkspaceRow({ workspace }) {
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 agentsById = useRelayStore((s) => s.agentsById);
121952
- const owner = workspace.ownerAgentId ? agentsById[workspace.ownerAgentId] : void 0;
121953
- const steward = workspace.stewardAgentId ? agentsById[workspace.stewardAgentId] : void 0;
121954
- const path = workspace.worktreePath || workspace.sourceCwd || workspace.repoRoot;
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: "grid gap-3 border-t border-border px-3 py-3 text-sm lg:grid-cols-[minmax(180px,1.2fr)_minmax(220px,1.5fr)_minmax(160px,1fr)_minmax(170px,auto)]",
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: "min-w-0 space-y-1",
121960
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
121961
- className: "flex min-w-0 items-center gap-2",
121962
- 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", {
121963
- className: "truncate font-medium",
121964
- title: workspace.branch || workspace.id,
121965
- children: workspace.branch || workspace.id
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
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
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)("div", {
121989
- className: "min-w-0 space-y-1",
121990
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
121991
- className: "truncate font-mono text-xs",
121992
- title: path,
121993
- children: shortPath(path)
121994
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
121995
- className: "truncate text-xs text-muted-foreground",
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
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122001
- className: "grid grid-cols-[4.5rem_minmax(0,1fr)] gap-x-2 gap-y-1 text-xs",
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)("span", {
122004
- className: "text-muted-foreground",
122005
- children: "Owner"
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)("span", {
122008
- className: "truncate",
122009
- title: workspace.ownerAgentId,
122010
- children: agentLabel(owner, workspace.ownerPolicyName || workspace.ownerAgentId)
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: "text-muted-foreground",
122014
- children: "Steward"
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: workspace.stewardAgentId,
122019
- children: agentLabel(steward, workspace.stewardAgentId)
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)("span", {
122022
- className: "text-muted-foreground",
122023
- children: "Updated"
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.jsx)("span", { children: timeAgo(now, workspace.updatedAt) }),
122026
- workspace.baseRef && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122027
- className: "text-muted-foreground",
122028
- children: "Base"
122029
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122030
- className: "truncate",
122031
- title: workspace.baseSha,
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
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceActions, { workspace })
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 cleanedCount = workspaces.filter((item) => item.status === "cleaned").length;
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 - cleanedCount
122748
+ count: workspaces.length - doneCount
122101
122749
  },
122102
122750
  {
122103
122751
  key: "cleaned",
122104
- label: "Cleaned",
122105
- count: cleanedCount
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
  }