agent-relay-server 0.10.20 → 0.10.21

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") {
@@ -13209,6 +13317,20 @@ var useRelayStore = create$1()(persist((set, get) => ({
13209
13317
  }
13210
13318
  });
13211
13319
  },
13320
+ upgradeOrchestrator(orchId, targetVersion) {
13321
+ const to = targetVersion ? ` to v${targetVersion}` : " to match the relay";
13322
+ get().openConfirm("Upgrade Orchestrator", `Upgrade "${orchId}"${to}? It will install the new version and restart itself.`, async () => {
13323
+ try {
13324
+ await api("POST", "/orchestrators/" + encodeURIComponent(orchId) + "/actions", {
13325
+ action: "upgrade",
13326
+ ...targetVersion ? { targetVersion } : {}
13327
+ });
13328
+ await Promise.all([get().fetchOrchestrators(), get().fetchActivityEvents()]);
13329
+ } catch (e) {
13330
+ get().showError("Upgrade Failed", e.message);
13331
+ }
13332
+ });
13333
+ },
13212
13334
  deleteOrchestrator(orchId) {
13213
13335
  get().openConfirm("Remove Orchestrator", `Remove orchestrator "${orchId}"?`, async () => {
13214
13336
  try {
@@ -106939,8 +107061,8 @@ function TextWithLinks({ text, onOpenPath, onPreviewPath, onPreviewPathEnd, isPa
106939
107061
  e.stopPropagation();
106940
107062
  onOpenPath(part.path, part.line);
106941
107063
  },
106942
- onMouseEnter: () => onPreviewPath?.(part.path, part.line),
106943
- onFocus: () => onPreviewPath?.(part.path, part.line),
107064
+ onMouseEnter: (e) => onPreviewPath?.(part.path, part.line, e.currentTarget.getBoundingClientRect()),
107065
+ onFocus: (e) => onPreviewPath?.(part.path, part.line, e.currentTarget.getBoundingClientRect()),
106944
107066
  onMouseLeave: () => onPreviewPathEnd?.(),
106945
107067
  onBlur: () => onPreviewPathEnd?.(),
106946
107068
  title: resolvedTitle ? `Open ${resolvedTitle}` : "Open file",
@@ -117489,15 +117611,21 @@ var h$1 = 2, _$1 = 1, o$1 = class {
117489
117611
  };
117490
117612
  //#endregion
117491
117613
  //#region src/components/ui/dialog.tsx
117614
+ var suppressGuardPop = false;
117492
117615
  function useBackClose$1(open, onOpenChange) {
117493
117616
  const pushedRef = import_react.useRef(false);
117494
117617
  const cbRef = import_react.useRef(onOpenChange);
117495
117618
  cbRef.current = onOpenChange;
117496
117619
  import_react.useEffect(() => {
117497
117620
  if (!open || !cbRef.current) return;
117621
+ suppressGuardPop = false;
117498
117622
  window.history.pushState({ dialogGuard: true }, "");
117499
117623
  pushedRef.current = true;
117500
117624
  function onPop() {
117625
+ if (suppressGuardPop) {
117626
+ suppressGuardPop = false;
117627
+ return;
117628
+ }
117501
117629
  if (pushedRef.current) {
117502
117630
  pushedRef.current = false;
117503
117631
  cbRef.current?.(false);
@@ -117508,6 +117636,7 @@ function useBackClose$1(open, onOpenChange) {
117508
117636
  window.removeEventListener("popstate", onPop);
117509
117637
  if (pushedRef.current) {
117510
117638
  pushedRef.current = false;
117639
+ suppressGuardPop = true;
117511
117640
  window.history.back();
117512
117641
  }
117513
117642
  };
@@ -119670,6 +119799,74 @@ function PendingAttachmentPreview({ item, onRemove }) {
119670
119799
  })
119671
119800
  })] });
119672
119801
  }
119802
+ function FloatingFilePreview({ preview, error, onReadError, onMouseEnter, onMouseLeave }) {
119803
+ const { anchor } = preview;
119804
+ const gap = 8;
119805
+ const width = Math.min(560, window.innerWidth - 24);
119806
+ const height = Math.min(380, window.innerHeight - 24);
119807
+ const left = Math.max(12, Math.min(anchor.left, window.innerWidth - width - 12));
119808
+ return (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
119809
+ className: "fixed z-50 flex flex-col overflow-hidden rounded-lg border border-border bg-background shadow-xl",
119810
+ style: {
119811
+ 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),
119812
+ left,
119813
+ width,
119814
+ height
119815
+ },
119816
+ onMouseEnter,
119817
+ onMouseLeave,
119818
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
119819
+ className: "flex h-8 shrink-0 items-center gap-2 border-b border-border px-2.5",
119820
+ children: [
119821
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
119822
+ className: "min-w-0 flex-1 truncate text-[11px] font-medium text-muted-foreground",
119823
+ children: preview.path
119824
+ }),
119825
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
119826
+ className: "max-w-[12rem] truncate text-[11px] text-red-400",
119827
+ children: error
119828
+ }),
119829
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
119830
+ className: "shrink-0 text-[10px] text-muted-foreground/70",
119831
+ children: "click to pin"
119832
+ })
119833
+ ]
119834
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
119835
+ className: "min-h-0 flex-1",
119836
+ children: preview.type === "directory" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectoryContent, {
119837
+ orchestratorId: preview.orchestratorId,
119838
+ selectedPath: preview.path,
119839
+ onReadError
119840
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileContent, {
119841
+ orchestratorId: preview.orchestratorId,
119842
+ selectedPath: preview.path,
119843
+ line: preview.line,
119844
+ onReadError
119845
+ })
119846
+ })]
119847
+ }), document.body);
119848
+ }
119849
+ function AddReaction({ open, onToggle, onReact }) {
119850
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
119851
+ className: "relative shrink-0",
119852
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
119853
+ type: "button",
119854
+ title: "Add reaction",
119855
+ onClick: onToggle,
119856
+ 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"),
119857
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SmilePlus, { className: "h-3 w-3" })
119858
+ }), open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
119859
+ 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",
119860
+ children: QUICK_REACTIONS.map((emoji) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
119861
+ type: "button",
119862
+ title: `React ${emoji}`,
119863
+ onClick: () => onReact(emoji),
119864
+ className: "inline-flex h-6 w-7 items-center justify-center rounded-full text-xs transition-colors hover:bg-muted",
119865
+ children: emoji
119866
+ }, emoji))
119867
+ })]
119868
+ });
119869
+ }
119673
119870
  var MessageBubble = (0, import_react.memo)(function MessageBubble({ msg, peer, onOpenReferencedPath, onPreviewReferencedPath, onPreviewReferencedPathEnd }) {
119674
119871
  const isOutbound = msg.from === HUMAN_AGENT_ID;
119675
119872
  const reactToMessage = useRelayStore((s) => s.reactToMessage);
@@ -119707,9 +119904,9 @@ var MessageBubble = (0, import_react.memo)(function MessageBubble({ msg, peer, o
119707
119904
  const absolute = resolvedReferencedPath(path);
119708
119905
  onOpenReferencedPath?.(absolute, line);
119709
119906
  }
119710
- function previewReferencedPath(path, line) {
119907
+ function previewReferencedPath(path, line, anchor) {
119711
119908
  const absolute = resolvedReferencedPath(path);
119712
- onPreviewReferencedPath?.(absolute, line);
119909
+ onPreviewReferencedPath?.(absolute, line, anchor);
119713
119910
  }
119714
119911
  function handleReact(emoji) {
119715
119912
  reactToMessage(msg, emoji);
@@ -119783,25 +119980,27 @@ var MessageBubble = (0, import_react.memo)(function MessageBubble({ msg, peer, o
119783
119980
  })
119784
119981
  ]
119785
119982
  }),
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", {
119983
+ !isReactionEvent(msg) && reactions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
119984
+ 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"),
119985
+ children: [!isOutbound && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddReaction, {
119986
+ open: showQuickReact,
119987
+ onToggle: () => setShowQuickReact((v) => !v),
119988
+ onReact: handleReact
119989
+ }), reactions.map((reaction) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
119789
119990
  type: "button",
119790
119991
  title: reaction.actors.join(", "),
119791
119992
  onClick: () => handleReact(reaction.emoji),
119792
119993
  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
119994
  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))
119995
+ }, reaction.emoji))]
119795
119996
  }),
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))
119997
+ !isReactionEvent(msg) && !isOutbound && reactions.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
119998
+ className: "absolute -bottom-2.5 left-1 z-20",
119999
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddReaction, {
120000
+ open: showQuickReact,
120001
+ onToggle: () => setShowQuickReact((v) => !v),
120002
+ onReact: handleReact
120003
+ })
119805
120004
  })
119806
120005
  ]
119807
120006
  })
@@ -119961,6 +120160,7 @@ function ChatPanel({ threads, onBack, showBackButton }) {
119961
120160
  const [terminalTarget, setTerminalTarget] = (0, import_react.useState)(null);
119962
120161
  const [terminalOpening, setTerminalOpening] = (0, import_react.useState)(false);
119963
120162
  const [filePreview, setFilePreview] = (0, import_react.useState)(null);
120163
+ const [floatingPreview, setFloatingPreview] = (0, import_react.useState)(null);
119964
120164
  const [filePreviewError, setFilePreviewError] = (0, import_react.useState)("");
119965
120165
  const filePreviewCloseTimer = (0, import_react.useRef)(null);
119966
120166
  const filePreviewRequest = (0, import_react.useRef)(0);
@@ -120059,17 +120259,17 @@ function ChatPanel({ threads, onBack, showBackButton }) {
120059
120259
  return null;
120060
120260
  }
120061
120261
  }, [orchestrators]);
120062
- const previewReferencedFile = (0, import_react.useCallback)((path, line) => {
120063
- if (!supportsSideFilePreview()) return;
120262
+ const previewReferencedFile = (0, import_react.useCallback)((path, line, anchor) => {
120263
+ if (!supportsSideFilePreview() || !anchor) return;
120064
120264
  const request = ++filePreviewRequest.current;
120065
120265
  resolveReferencedFile(path).then((info) => {
120066
120266
  if (filePreviewRequest.current !== request) return;
120067
120267
  if (!info) return;
120068
120268
  clearFilePreviewCloseTimer();
120069
- setFilePreview({
120269
+ setFloatingPreview({
120070
120270
  ...info,
120071
120271
  line: line || 0,
120072
- pinned: false
120272
+ anchor
120073
120273
  });
120074
120274
  setFilePreviewError("");
120075
120275
  });
@@ -120078,7 +120278,7 @@ function ChatPanel({ threads, onBack, showBackButton }) {
120078
120278
  filePreviewRequest.current += 1;
120079
120279
  clearFilePreviewCloseTimer();
120080
120280
  filePreviewCloseTimer.current = window.setTimeout(() => {
120081
- setFilePreview((current) => current?.pinned ? current : null);
120281
+ setFloatingPreview(null);
120082
120282
  }, 250);
120083
120283
  }, [clearFilePreviewCloseTimer]);
120084
120284
  const openReferencedFile = (0, import_react.useCallback)((path, line) => {
@@ -120088,11 +120288,12 @@ function ChatPanel({ threads, onBack, showBackButton }) {
120088
120288
  return;
120089
120289
  }
120090
120290
  if (supportsSideFilePreview()) {
120291
+ filePreviewRequest.current += 1;
120091
120292
  clearFilePreviewCloseTimer();
120293
+ setFloatingPreview(null);
120092
120294
  setFilePreview({
120093
120295
  ...info,
120094
- line: line || 0,
120095
- pinned: true
120296
+ line: line || 0
120096
120297
  });
120097
120298
  setFilePreviewError("");
120098
120299
  return;
@@ -120117,8 +120318,6 @@ function ChatPanel({ threads, onBack, showBackButton }) {
120117
120318
  showError
120118
120319
  ]);
120119
120320
  function closeFilePreview() {
120120
- filePreviewRequest.current += 1;
120121
- clearFilePreviewCloseTimer();
120122
120321
  setFilePreview(null);
120123
120322
  setFilePreviewError("");
120124
120323
  }
@@ -120209,372 +120408,380 @@ function ChatPanel({ threads, onBack, showBackButton }) {
120209
120408
  children: "Select an agent to start chatting"
120210
120409
  })]
120211
120410
  });
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
- ]
120411
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
120412
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120413
+ className: "flex h-full min-w-0",
120414
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120415
+ className: "flex h-full min-w-0 flex-1 flex-col",
120416
+ children: [
120417
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120418
+ className: "flex items-center justify-between px-3 md:px-4 py-2.5 md:py-3 border-b border-border shrink-0",
120419
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120420
+ className: "flex items-center gap-2 md:gap-2.5 min-w-0",
120421
+ children: [
120422
+ showBackButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120423
+ variant: "ghost",
120424
+ size: "icon-sm",
120425
+ onClick: onBack,
120426
+ className: "shrink-0 -ml-1",
120427
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowLeft, { className: "w-4 h-4" })
120428
+ }),
120429
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
120430
+ type: "button",
120431
+ className: "flex items-center gap-2 md:gap-2.5 min-w-0 hover:opacity-80 transition-opacity",
120432
+ onClick: () => agent && openAgentDetail(agent),
120433
+ disabled: !agent,
120434
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120435
+ className: "relative shrink-0",
120436
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentTypeIcon, { agent }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusDot, {
120437
+ agent,
120438
+ now,
120439
+ className: "absolute -bottom-0.5 -right-0.5 w-2 h-2"
120440
+ })]
120441
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120442
+ className: "min-w-0 text-left",
120443
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
120444
+ className: "text-sm font-medium truncate",
120445
+ children: agent ? displayName(agent) : selectedInboxThread
120446
+ }), agent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
120447
+ className: "text-xs text-muted-foreground truncate",
120448
+ children: [
120449
+ blockedState ? `blocked: ${blockedState.label}` : agent.status,
120450
+ agent.machine && ` · ${agent.machine}`,
120451
+ typeof agent.meta?.cwd === "string" && agent.meta.cwd && ` · ${shortPath$1(agent.meta.cwd, 1)}`
120452
+ ]
120453
+ })]
120253
120454
  })]
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" })
120455
+ }),
120456
+ agent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentRuntimeChips, {
120457
+ agent,
120458
+ compact: true,
120459
+ className: "hidden md:flex shrink-0"
120460
+ }),
120461
+ agent?.context && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextRing, { utilization: agent.context.utilization }),
120462
+ thread?.attention.unread ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
120463
+ className: "bg-red-500/20 text-red-400 text-xs shrink-0 hidden sm:flex",
120464
+ children: [thread.attention.unread, " unread"]
120465
+ }) : null
120466
+ ]
120467
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
120468
+ className: "flex items-center gap-0.5 md:gap-1 shrink-0",
120469
+ children: agent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
120470
+ canOpenTerminal && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120471
+ variant: "ghost",
120472
+ size: "icon-sm",
120473
+ className: "hidden sm:inline-flex",
120474
+ disabled: terminalOpening,
120475
+ title: "Terminal",
120476
+ onClick: () => void handleOpenTerminal(),
120477
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Terminal, { className: "w-3.5 h-3.5" })
120478
+ }),
120479
+ canCompact && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120480
+ variant: "ghost",
120481
+ size: "icon-sm",
120482
+ className: "hidden sm:inline-flex",
120483
+ title: "Compact",
120484
+ onClick: () => openConfirm("Compact Agent", `Compact context for ${displayName(agent)}?`, () => doAgentAction(agent, "compact")),
120485
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minimize2, { className: "w-3.5 h-3.5" })
120486
+ }),
120487
+ canClearContext && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120488
+ variant: "ghost",
120489
+ size: "icon-sm",
120490
+ className: "hidden sm:inline-flex",
120491
+ title: "Clear context",
120492
+ onClick: () => openConfirm("Clear Context", `Clear context for ${displayName(agent)}?`, () => doAgentAction(agent, "clearContext")),
120493
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eraser, { className: "w-3.5 h-3.5" })
120494
+ }),
120495
+ canShutdown && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120496
+ variant: "ghost",
120497
+ size: "icon-sm",
120498
+ className: "hidden sm:inline-flex",
120499
+ title: "Shutdown",
120500
+ onClick: () => openConfirm("Shutdown Agent", `Shutdown ${displayName(agent)}?`, () => doAgentAction(agent, "shutdown")),
120501
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Power, { className: "w-3.5 h-3.5" })
120502
+ }),
120503
+ agent && typeof agent.meta?.cwd === "string" && agent.meta.cwd && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120504
+ variant: "ghost",
120505
+ size: "icon-sm",
120506
+ className: "hidden sm:inline-flex",
120507
+ title: `Open ${agent.meta.cwd} in Files`,
120508
+ onClick: () => void openFilesForAgent(agent),
120509
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderOpen, { className: "w-3.5 h-3.5" })
120510
+ }),
120511
+ agent && thread && thread.messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120512
+ variant: "ghost",
120513
+ size: "icon-sm",
120514
+ className: "hidden sm:inline-flex",
120515
+ title: "Fork — spawn new agent with this chat history",
120516
+ onClick: () => forkFromAgent(agent.id, thread.messages),
120517
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFork, { className: "w-3.5 h-3.5" })
120518
+ }),
120519
+ thread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120520
+ variant: "ghost",
120521
+ size: "icon-sm",
120522
+ className: "hidden sm:inline-flex",
120523
+ title: "Mark unread",
120524
+ onClick: () => markInboxThreadUnread(selectedInboxThread),
120525
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailX, { className: "w-3.5 h-3.5" })
120526
+ }),
120527
+ thread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120528
+ variant: "ghost",
120529
+ size: "icon-sm",
120530
+ className: "hidden sm:inline-flex",
120531
+ title: "Mark read",
120532
+ onClick: () => markInboxThreadRead(thread.peer, thread.messages),
120533
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailOpen, { className: "w-3.5 h-3.5" })
120534
+ }),
120535
+ exportableThread && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120536
+ variant: "ghost",
120537
+ size: "icon-sm",
120538
+ className: "hidden sm:inline-flex",
120539
+ title: "Export thread",
120540
+ onClick: () => exportThread({
120541
+ ...exportableThread,
120542
+ importedHistory
120543
+ }, "json"),
120544
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "w-3.5 h-3.5" })
120545
+ }),
120546
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenu, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DropdownMenuTrigger, {
120547
+ asChild: true,
120548
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120549
+ variant: "ghost",
120550
+ size: "icon-sm",
120551
+ className: "sm:hidden",
120552
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Ellipsis, { className: "w-3.5 h-3.5" })
120553
+ })
120554
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuContent, {
120555
+ align: "end",
120556
+ children: [
120557
+ canOpenTerminal && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120558
+ disabled: terminalOpening,
120559
+ onClick: () => void handleOpenTerminal(),
120560
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Terminal, { className: "w-3.5 h-3.5" }), "Terminal"]
120561
+ }),
120562
+ canCompact && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120563
+ onClick: () => openConfirm("Compact Agent", `Compact context for ${displayName(agent)}?`, () => doAgentAction(agent, "compact")),
120564
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minimize2, { className: "w-3.5 h-3.5" }), "Compact"]
120565
+ }),
120566
+ canClearContext && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120567
+ onClick: () => openConfirm("Clear Context", `Clear context for ${displayName(agent)}?`, () => doAgentAction(agent, "clearContext")),
120568
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eraser, { className: "w-3.5 h-3.5" }), "Clear Context"]
120569
+ }),
120570
+ canShutdown && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120571
+ onClick: () => openConfirm("Shutdown Agent", `Shutdown ${displayName(agent)}?`, () => doAgentAction(agent, "shutdown")),
120572
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Power, { className: "w-3.5 h-3.5" }), "Shutdown"]
120573
+ }),
120574
+ agent && typeof agent.meta?.cwd === "string" && agent.meta.cwd && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120575
+ onClick: () => void openFilesForAgent(agent),
120576
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderOpen, { className: "w-3.5 h-3.5" }), "Open Files"]
120577
+ }),
120578
+ agent && thread && thread.messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120579
+ onClick: () => forkFromAgent(agent.id, thread.messages),
120580
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFork, { className: "w-3.5 h-3.5" }), "Fork"]
120581
+ }),
120582
+ (canOpenTerminal || canCompact || canClearContext || canShutdown) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DropdownMenuSeparator, {}),
120583
+ thread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120584
+ onClick: () => markInboxThreadUnread(selectedInboxThread),
120585
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailX, { className: "w-3.5 h-3.5" }), "Mark Unread"]
120586
+ }),
120587
+ thread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120588
+ onClick: () => markInboxThreadRead(thread.peer, thread.messages),
120589
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MailOpen, { className: "w-3.5 h-3.5" }), "Mark Read"]
120590
+ }),
120591
+ exportableThread && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenuItem, {
120592
+ onClick: () => exportThread({
120593
+ ...exportableThread,
120594
+ importedHistory
120595
+ }, "json"),
120596
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "w-3.5 h-3.5" }), "Download"]
120597
+ })
120598
+ ]
120599
+ })] })
120600
+ ] })
120601
+ })]
120602
+ }),
120603
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
120604
+ ref: pinnedScroll.ref,
120605
+ onScroll: pinnedScroll.onScroll,
120606
+ className: "flex-1 overflow-y-auto px-3 md:px-4 py-3 md:py-4",
120607
+ style: { minHeight: 0 },
120608
+ children: timeline.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120609
+ className: "flex flex-col items-center justify-center h-full text-center",
120610
+ 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", {
120611
+ className: "text-xs text-muted-foreground",
120612
+ children: "No messages yet"
120613
+ })]
120614
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
120615
+ timeline.map((entry) => {
120616
+ if (entry.type === "message") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageBubble, {
120617
+ msg: entry.msg,
120618
+ peer: selectedInboxThread,
120619
+ onOpenReferencedPath: openReferencedFile,
120620
+ onPreviewReferencedPath: previewReferencedFile,
120621
+ onPreviewReferencedPathEnd: scheduleCloseReferencedFilePreview
120622
+ }, entry.msg.id);
120623
+ if (entry.type === "import-boundary") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImportedHistoryMarker, { history: entry.history }, `import-${entry.history.id}`);
120624
+ if (entry.type === "imported-message") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImportedMessageBubble, {
120625
+ entry: entry.entry,
120626
+ sourceLabel: entry.history.sourceAgentLabel || entry.history.sourcePeerId
120627
+ }, `import-${entry.history.id}-${entry.entry.originalMessageId}-${entry.entry.position}`);
120628
+ if (entry.type === "status") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusMarker, { event: entry.event }, entry.event.id);
120629
+ if (entry.type === "date") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DateSeparator, { date: entry.date }, `d-${entry.date}`);
120630
+ if (entry.type === "created") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreatedMarker, { timestamp: entry.timestamp }, "created");
120631
+ return null;
120318
120632
  }),
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" })
120633
+ pendingApproval && agent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PermissionRequestBubble, {
120634
+ agentId: agent.id,
120635
+ approval: pendingApproval
120326
120636
  }),
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" })
120637
+ agent?.status === "busy" && !pendingApproval && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BusyIndicator, { blockedLabel: blockedState?.label })
120638
+ ] })
120639
+ }),
120640
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120641
+ 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"),
120642
+ onDragOver: (e) => {
120643
+ e.preventDefault();
120644
+ setDragActive(true);
120645
+ },
120646
+ onDragLeave: () => setDragActive(false),
120647
+ onDrop: (e) => {
120648
+ e.preventDefault();
120649
+ setDragActive(false);
120650
+ uploadFiles(e.dataTransfer.files);
120651
+ },
120652
+ children: [
120653
+ pendingAttachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
120654
+ className: "mb-2 grid gap-2 sm:grid-cols-2",
120655
+ children: pendingAttachments.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PendingAttachmentPreview, {
120656
+ item,
120657
+ onRemove: () => removePendingAttachment(item.id)
120658
+ }, item.id))
120334
120659
  }),
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" })
120660
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
120661
+ ref: fileInputRef,
120662
+ type: "file",
120663
+ multiple: true,
120664
+ className: "hidden",
120665
+ onChange: (e) => {
120666
+ if (e.target.files) uploadFiles(e.target.files);
120667
+ e.currentTarget.value = "";
120668
+ }
120345
120669
  }),
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",
120670
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120671
+ className: "hidden md:flex items-end gap-2",
120356
120672
  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"]
120673
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120674
+ variant: "ghost",
120675
+ size: "icon",
120676
+ title: "Attach files",
120677
+ disabled: chatSending,
120678
+ onClick: () => fileInputRef.current?.click(),
120679
+ className: "shrink-0 mb-0.5 rounded-xl h-[42px] w-[42px]",
120680
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Paperclip, { className: "w-4 h-4" })
120386
120681
  }),
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"]
120682
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoGrowTextarea, {
120683
+ value: draft,
120684
+ onChange: (e) => setReplyDraft(selectedInboxThread, e.target.value),
120685
+ onKeyDown: handleKeyDown,
120686
+ onPaste: handlePaste,
120687
+ placeholder: `Message ${agent ? displayName(agent) : selectedInboxThread}…`,
120688
+ className: "flex-1"
120390
120689
  }),
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"]
120690
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120691
+ size: "icon",
120692
+ disabled: !draft.trim() && readyAttachments.length === 0 || hasPendingUploads || chatSending,
120693
+ onClick: handleSend,
120694
+ className: "shrink-0 mb-0.5 rounded-xl h-[42px] w-[42px]",
120695
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Send, { className: "w-4 h-4" })
120397
120696
  })
120398
120697
  ]
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, {
120698
+ }),
120699
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120700
+ className: "md:hidden space-y-2",
120701
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AutoGrowTextarea, {
120483
120702
  value: draft,
120484
120703
  onChange: (e) => setReplyDraft(selectedInboxThread, e.target.value),
120485
120704
  onKeyDown: handleKeyDown,
120486
120705
  onPaste: handlePaste,
120487
120706
  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" })
120707
+ className: "w-full"
120708
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120709
+ className: "flex items-center justify-between",
120710
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120711
+ variant: "ghost",
120712
+ size: "icon",
120713
+ title: "Attach files",
120714
+ disabled: chatSending,
120715
+ onClick: () => fileInputRef.current?.click(),
120716
+ className: "rounded-xl h-9 w-9",
120717
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Paperclip, { className: "w-4 h-4" })
120718
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120719
+ size: "icon",
120720
+ disabled: !draft.trim() && readyAttachments.length === 0 || hasPendingUploads || chatSending,
120721
+ onClick: handleSend,
120722
+ className: "rounded-xl h-9 w-9",
120723
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Send, { className: "w-4 h-4" })
120724
+ })]
120524
120725
  })]
120525
- })]
120726
+ }),
120727
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
120728
+ className: "text-xs text-muted-foreground mt-1.5 hidden md:block",
120729
+ children: "Enter to send · Shift+Enter for newline"
120730
+ })
120731
+ ]
120732
+ })
120733
+ ]
120734
+ }), filePreview && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
120735
+ className: "hidden h-full w-[min(44vw,720px)] min-w-[360px] shrink-0 flex-col border-l border-border bg-background xl:flex",
120736
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
120737
+ className: "flex h-10 shrink-0 items-center gap-2 border-b border-border px-3",
120738
+ children: [
120739
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
120740
+ className: "min-w-0 flex-1 text-xs font-medium text-muted-foreground",
120741
+ children: "File preview"
120526
120742
  }),
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"
120743
+ filePreviewError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
120744
+ className: "max-w-[18rem] truncate text-xs text-red-400",
120745
+ children: filePreviewError
120746
+ }),
120747
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
120748
+ variant: "ghost",
120749
+ size: "icon-sm",
120750
+ title: "Close preview",
120751
+ onClick: closeFilePreview,
120752
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" })
120530
120753
  })
120531
120754
  ]
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" })
120755
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
120756
+ className: "min-h-0 flex-1",
120757
+ children: filePreview.type === "directory" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectoryContent, {
120758
+ orchestratorId: filePreview.orchestratorId,
120759
+ selectedPath: filePreview.path,
120760
+ onReadError: setFilePreviewError
120761
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileContent, {
120762
+ orchestratorId: filePreview.orchestratorId,
120763
+ selectedPath: filePreview.path,
120764
+ line: filePreview.line,
120765
+ onReadError: setFilePreviewError
120555
120766
  })
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
- })
120767
+ })]
120569
120768
  })]
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
- })] });
120769
+ }),
120770
+ floatingPreview && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FloatingFilePreview, {
120771
+ preview: floatingPreview,
120772
+ error: filePreviewError,
120773
+ onReadError: setFilePreviewError,
120774
+ onMouseEnter: clearFilePreviewCloseTimer,
120775
+ onMouseLeave: scheduleCloseReferencedFilePreview
120776
+ }),
120777
+ terminalTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalDialog, {
120778
+ open: terminalOpen,
120779
+ onOpenChange: handleCloseTerminal,
120780
+ orchestratorId: terminalTarget.orchestratorId,
120781
+ session: terminalTarget.session,
120782
+ interactive: terminalTarget.interactive || canWriteTerminal
120783
+ })
120784
+ ] });
120578
120785
  }
120579
120786
  function ChatView() {
120580
120787
  const threads = useAllInboxThreads();
@@ -121582,6 +121789,8 @@ function ManagedAgentRow({ agent, orch }) {
121582
121789
  function OrchestratorCard({ orch }) {
121583
121790
  const now = useNow();
121584
121791
  const orchestratorAction = useRelayStore((s) => s.orchestratorAction);
121792
+ const upgradeOrchestrator = useRelayStore((s) => s.upgradeOrchestrator);
121793
+ const fleetTarget = useRelayStore((s) => s.stats.version);
121585
121794
  const openOrchestratorSpawnFor = useRelayStore((s) => s.openOrchestratorSpawnFor);
121586
121795
  const openFilesAt = useRelayStore((s) => s.openFilesAt);
121587
121796
  const deleteOrchestrator = useRelayStore((s) => s.deleteOrchestrator);
@@ -121590,6 +121799,10 @@ function OrchestratorCard({ orch }) {
121590
121799
  const healthClass = orchestratorHealthClass(orch);
121591
121800
  const online = orch.status === "online";
121592
121801
  const packageVersion = orch.package?.version || orch.version;
121802
+ const upgrade = orch.upgrade;
121803
+ const upgrading = upgrade?.status === "pending";
121804
+ const driftAvailable = online && !!orch.version && !!fleetTarget && orch.version !== fleetTarget;
121805
+ const canUpgrade = online && !upgrading && (driftAvailable || upgrade?.status === "failed");
121593
121806
  const contractEntries = Object.entries(orch.contracts || {}).filter(([, value]) => typeof value === "number");
121594
121807
  const providerStatus = orch.providerStatus || orch.providers.map((provider) => ({
121595
121808
  name: provider,
@@ -121642,6 +121855,27 @@ function OrchestratorCard({ orch }) {
121642
121855
  " v",
121643
121856
  packageVersion
121644
121857
  ] }),
121858
+ upgrading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
121859
+ className: "text-[10px] bg-amber-500/10 text-amber-400 border-amber-500/20 gap-1",
121860
+ children: [
121861
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleArrowUp, { className: "w-3 h-3 animate-pulse" }),
121862
+ "upgrading → v",
121863
+ upgrade.desiredVersion
121864
+ ]
121865
+ }),
121866
+ !upgrading && upgrade?.status === "failed" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
121867
+ className: "text-[10px] bg-red-500/10 text-red-400 border-red-500/20 gap-1",
121868
+ title: upgrade.error,
121869
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "w-3 h-3" }), "upgrade failed"]
121870
+ }),
121871
+ !upgrading && driftAvailable && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
121872
+ className: "text-[10px] bg-blue-500/10 text-blue-400 border-blue-500/20",
121873
+ children: [
121874
+ "→ v",
121875
+ fleetTarget,
121876
+ " available"
121877
+ ]
121878
+ }),
121645
121879
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
121646
121880
  className: "ml-auto",
121647
121881
  children: timeAgo(now, orch.lastSeen)
@@ -121733,6 +121967,15 @@ function OrchestratorCard({ orch }) {
121733
121967
  onClick: () => refreshOrchestratorProviders(orch.id),
121734
121968
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCw, { className: "w-3 h-3" }), "Refresh providers"]
121735
121969
  }),
121970
+ (canUpgrade || upgrading) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
121971
+ size: "sm",
121972
+ variant: "outline",
121973
+ disabled: upgrading,
121974
+ className: "h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 border-blue-500/30 disabled:opacity-60",
121975
+ title: upgrading ? `Upgrading to v${upgrade.desiredVersion}…` : `Upgrade to v${fleetTarget}`,
121976
+ onClick: () => upgradeOrchestrator(orch.id),
121977
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleArrowUp, { className: `w-3 h-3 ${upgrading ? "animate-pulse" : ""}` }), upgrading ? "Upgrading…" : "Upgrade"]
121978
+ }),
121736
121979
  online && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
121737
121980
  size: "sm",
121738
121981
  variant: "outline",
@@ -121817,12 +122060,27 @@ var LIVE_STATUSES = new Set([
121817
122060
  "merge_planned",
121818
122061
  "cleanup_requested"
121819
122062
  ]);
122063
+ var GIT_STATE_STATUSES = new Set([
122064
+ "active",
122065
+ "ready",
122066
+ "conflict",
122067
+ "review_requested",
122068
+ "merge_planned"
122069
+ ]);
122070
+ var MERGEABLE_STATUSES = new Set([
122071
+ "active",
122072
+ "ready",
122073
+ "review_requested",
122074
+ "merge_planned",
122075
+ "conflict"
122076
+ ]);
121820
122077
  var STATUS_CLASS$1 = {
121821
122078
  active: "bg-blue-500/10 text-blue-400 border-blue-500/20",
121822
122079
  ready: "bg-emerald-500/10 text-emerald-400 border-emerald-500/20",
121823
122080
  conflict: "bg-red-500/10 text-red-400 border-red-500/20",
121824
122081
  review_requested: "bg-yellow-500/10 text-yellow-400 border-yellow-500/20",
121825
122082
  merge_planned: "bg-indigo-500/10 text-indigo-400 border-indigo-500/20",
122083
+ merged: "bg-violet-500/10 text-violet-400 border-violet-500/20",
121826
122084
  abandoned: "bg-zinc-500/10 text-zinc-400 border-zinc-500/20",
121827
122085
  cleanup_requested: "bg-orange-500/10 text-orange-400 border-orange-500/20",
121828
122086
  cleaned: "bg-zinc-500/10 text-zinc-400 border-zinc-500/20"
@@ -121833,6 +122091,7 @@ var STATUS_LABEL = {
121833
122091
  conflict: "conflict",
121834
122092
  review_requested: "review",
121835
122093
  merge_planned: "merge planned",
122094
+ merged: "merged",
121836
122095
  abandoned: "abandoned",
121837
122096
  cleanup_requested: "cleanup",
121838
122097
  cleaned: "cleaned"
@@ -121844,9 +122103,11 @@ var STATUS_ORDER = {
121844
122103
  merge_planned: 3,
121845
122104
  active: 4,
121846
122105
  cleanup_requested: 5,
121847
- abandoned: 6,
121848
- cleaned: 7
122106
+ merged: 6,
122107
+ abandoned: 7,
122108
+ cleaned: 8
121849
122109
  };
122110
+ var TERMINAL_STATUSES = new Set(["cleaned", "merged"]);
121850
122111
  function shortPath(path) {
121851
122112
  const parts = path.split("/").filter(Boolean);
121852
122113
  if (parts.length <= 3) return path || "-";
@@ -121881,20 +122142,35 @@ function groupWorkspaces(workspaces) {
121881
122142
  }
121882
122143
  function filterWorkspaces(workspaces, filter) {
121883
122144
  if (filter === "all") return workspaces;
121884
- if (filter === "cleaned") return workspaces.filter((workspace) => workspace.status === "cleaned");
121885
- return workspaces.filter((workspace) => workspace.status !== "cleaned");
122145
+ if (filter === "cleaned") return workspaces.filter((workspace) => TERMINAL_STATUSES.has(workspace.status));
122146
+ return workspaces.filter((workspace) => !TERMINAL_STATUSES.has(workspace.status));
121886
122147
  }
121887
- function WorkspaceActions({ workspace }) {
122148
+ function WorkspaceActions({ workspace, expanded, onToggleDetails }) {
121888
122149
  const workspaceAction = useRelayStore((s) => s.workspaceAction);
122150
+ const purgeWorkspace = useRelayStore((s) => s.purgeWorkspace);
122151
+ const fetchWorkspaceMergePreview = useRelayStore((s) => s.fetchWorkspaceMergePreview);
121889
122152
  const openFilesAt = useRelayStore((s) => s.openFilesAt);
121890
- const disabled = workspace.status === "cleaned" || workspace.status === "abandoned" || workspace.status === "cleanup_requested";
122153
+ const terminal = workspace.status === "cleaned" || workspace.status === "merged" || workspace.status === "abandoned";
122154
+ const disabled = terminal || workspace.status === "cleanup_requested";
121891
122155
  const openPath = workspace.worktreePath || workspace.sourceCwd || workspace.repoRoot;
122156
+ const mergeable = workspace.mode === "isolated" && Boolean(workspace.worktreePath) && MERGEABLE_STATUSES.has(workspace.status);
121892
122157
  async function copyPath() {
121893
122158
  await navigator.clipboard?.writeText(openPath);
121894
122159
  }
122160
+ async function merge() {
122161
+ await fetchWorkspaceMergePreview(workspace.id);
122162
+ await workspaceAction(workspace.id, "merge");
122163
+ }
121895
122164
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
121896
122165
  className: "flex flex-wrap justify-end gap-1.5",
121897
122166
  children: [
122167
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
122168
+ size: "icon-sm",
122169
+ variant: "ghost",
122170
+ title: expanded ? "Hide details" : "Show diff & timeline",
122171
+ onClick: onToggleDetails,
122172
+ 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" })
122173
+ }),
121898
122174
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
121899
122175
  size: "icon-sm",
121900
122176
  variant: "ghost",
@@ -121933,108 +122209,477 @@ function WorkspaceActions({ workspace }) {
121933
122209
  title: "Mark merge planned",
121934
122210
  disabled: disabled || workspace.status === "merge_planned",
121935
122211
  onClick: () => void workspaceAction(workspace.id, "merge-plan"),
122212
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Flag, { className: "h-3.5 w-3.5" })
122213
+ }),
122214
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
122215
+ size: "icon-sm",
122216
+ variant: "default",
122217
+ title: "Merge & land work",
122218
+ disabled: !mergeable,
122219
+ onClick: () => void merge(),
121936
122220
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitMerge, { className: "h-3.5 w-3.5" })
121937
122221
  }),
121938
122222
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
121939
122223
  size: "icon-sm",
121940
122224
  variant: "outline",
121941
- title: "Request cleanup",
122225
+ title: "Request cleanup (removes the worktree on the host)",
121942
122226
  disabled: workspace.status === "cleaned" || workspace.status === "cleanup_requested",
121943
122227
  onClick: () => void workspaceAction(workspace.id, "cleanup"),
121944
122228
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" })
122229
+ }),
122230
+ terminal && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
122231
+ size: "icon-sm",
122232
+ variant: "ghost",
122233
+ title: "Purge record (clears the row, does not touch disk)",
122234
+ onClick: () => void purgeWorkspace(workspace.id),
122235
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" })
121945
122236
  })
121946
122237
  ]
121947
122238
  });
121948
122239
  }
121949
- function WorkspaceRow({ workspace }) {
122240
+ function MergePreviewHint({ workspace, ahead }) {
122241
+ const preview = useRelayStore((s) => s.workspaceMergePreview[workspace.id]);
122242
+ const fetchWorkspaceMergePreview = useRelayStore((s) => s.fetchWorkspaceMergePreview);
122243
+ const eligible = ahead > 0 && MERGEABLE_STATUSES.has(workspace.status);
122244
+ (0, import_react.useEffect)(() => {
122245
+ if (eligible && preview === void 0) fetchWorkspaceMergePreview(workspace.id);
122246
+ }, [
122247
+ eligible,
122248
+ preview,
122249
+ workspace.id,
122250
+ fetchWorkspaceMergePreview
122251
+ ]);
122252
+ if (!eligible || preview === void 0 || preview.available === false) return null;
122253
+ if (preview.conflict) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122254
+ className: "flex items-center gap-0.5 text-amber-400",
122255
+ title: `Merging into ${preview.baseRef || "base"} would conflict — resolve before merging`,
122256
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-3 w-3" }), "conflict"]
122257
+ });
122258
+ if (preview.conflict === false) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122259
+ className: "flex items-center gap-0.5 text-emerald-400",
122260
+ title: `Clean to merge via ${preview.strategy === "pr" ? "PR" : "rebase + fast-forward"} into ${preview.baseRef || "base"}`,
122261
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3 w-3" }), preview.strategy === "pr" ? "PR ready" : "clean"]
122262
+ });
122263
+ return null;
122264
+ }
122265
+ function GitState({ workspace }) {
121950
122266
  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;
122267
+ const gitState = useRelayStore((s) => s.workspaceGitState[workspace.id]);
122268
+ const fetchWorkspaceGitState = useRelayStore((s) => s.fetchWorkspaceGitState);
122269
+ const eligible = workspace.mode === "isolated" && Boolean(workspace.worktreePath) && GIT_STATE_STATUSES.has(workspace.status);
122270
+ (0, import_react.useEffect)(() => {
122271
+ if (eligible && gitState === void 0) fetchWorkspaceGitState(workspace.id);
122272
+ }, [
122273
+ eligible,
122274
+ gitState,
122275
+ workspace.id,
122276
+ fetchWorkspaceGitState
122277
+ ]);
122278
+ if (!eligible) return null;
122279
+ const refresh = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
122280
+ size: "icon-sm",
122281
+ variant: "ghost",
122282
+ className: "h-5 w-5",
122283
+ title: "Refresh git state",
122284
+ onClick: () => void fetchWorkspaceGitState(workspace.id),
122285
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "h-3 w-3" })
122286
+ });
122287
+ if (gitState === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122288
+ className: "flex items-center gap-1 text-[11px] text-muted-foreground",
122289
+ children: "Loading git state…"
122290
+ });
122291
+ if (gitState.available === false) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122292
+ className: "flex items-center gap-1 text-[11px] text-muted-foreground",
122293
+ title: gitState.reason,
122294
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "git state unavailable" }), refresh]
122295
+ });
122296
+ if (gitState.missing) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122297
+ className: "flex items-center gap-1 text-[11px] text-muted-foreground",
122298
+ children: ["worktree gone ", refresh]
122299
+ });
122300
+ if (gitState.error) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122301
+ className: "flex items-center gap-1 text-[11px] text-red-400",
122302
+ title: gitState.error,
122303
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "git error" }), refresh]
122304
+ });
122305
+ const ahead = gitState.ahead ?? 0;
122306
+ const behind = gitState.behind ?? 0;
122307
+ const dirty = gitState.dirtyCount ?? 0;
122308
+ const clean = ahead === 0 && dirty === 0;
122309
+ const commit = gitState.lastCommit;
121955
122310
  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)]",
122311
+ className: "space-y-0.5",
122312
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122313
+ className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px]",
122314
+ children: [clean ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122315
+ className: "text-muted-foreground",
122316
+ children: "no unmerged work"
122317
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
122318
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122319
+ className: ahead > 0 ? "flex items-center text-emerald-400" : "flex items-center text-muted-foreground",
122320
+ title: `${ahead} commit(s) ahead of base`,
122321
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUp, { className: "h-3 w-3" }), ahead]
122322
+ }),
122323
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122324
+ className: behind > 0 ? "flex items-center text-amber-400" : "flex items-center text-muted-foreground",
122325
+ title: `${behind} commit(s) behind base`,
122326
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDown, { className: "h-3 w-3" }), behind]
122327
+ }),
122328
+ dirty > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122329
+ className: "flex items-center text-orange-400",
122330
+ title: `${dirty} uncommitted change(s)`,
122331
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilePen, { className: "h-3 w-3" }), dirty]
122332
+ }),
122333
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MergePreviewHint, {
122334
+ workspace,
122335
+ ahead
122336
+ })
122337
+ ] }), refresh]
122338
+ }), commit && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122339
+ className: "flex min-w-0 items-center gap-1 text-[11px] text-muted-foreground",
122340
+ title: `${commit.sha.slice(0, 8)} — ${commit.message}`,
122341
+ children: [
122342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitCommitHorizontal, { className: "h-3 w-3 shrink-0" }),
122343
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122344
+ className: "truncate",
122345
+ children: commit.message || commit.sha.slice(0, 8)
122346
+ }),
122347
+ commit.at ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122348
+ className: "shrink-0 opacity-70",
122349
+ children: ["· ", timeAgo(now, commit.at)]
122350
+ }) : null
122351
+ ]
122352
+ })]
122353
+ });
122354
+ }
122355
+ function WorkspaceTimeline({ workspace }) {
122356
+ const now = useNow();
122357
+ const mergedAt = typeof workspace.metadata?.mergedAt === "number" ? workspace.metadata.mergedAt : void 0;
122358
+ const steps = [
122359
+ {
122360
+ label: "created",
122361
+ at: workspace.createdAt
122362
+ },
122363
+ {
122364
+ label: "ready",
122365
+ at: workspace.readyAt
122366
+ },
122367
+ {
122368
+ label: "merged",
122369
+ at: mergedAt
122370
+ },
122371
+ {
122372
+ label: "cleaned",
122373
+ at: workspace.cleanedAt
122374
+ }
122375
+ ].filter((step) => typeof step.at === "number" && step.at > 0);
122376
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122377
+ className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-muted-foreground",
122378
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122379
+ className: "flex items-center gap-1 font-medium text-foreground",
122380
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Clock, { className: "h-3 w-3" }), "Timeline"]
122381
+ }), steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122382
+ className: "flex items-center gap-1",
122383
+ children: [
122384
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122385
+ className: "opacity-40",
122386
+ children: "→"
122387
+ }),
122388
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122389
+ className: "text-foreground",
122390
+ children: step.label
122391
+ }),
122392
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122393
+ title: new Date(step.at).toLocaleString(),
122394
+ children: timeAgo(now, step.at)
122395
+ })
122396
+ ]
122397
+ }, step.label))]
122398
+ });
122399
+ }
122400
+ function diffLineClass(line) {
122401
+ if (line.startsWith("+") && !line.startsWith("+++")) return "text-emerald-400";
122402
+ if (line.startsWith("-") && !line.startsWith("---")) return "text-red-400";
122403
+ if (line.startsWith("@@")) return "text-cyan-400";
122404
+ if (line.startsWith("diff ") || line.startsWith("index ") || line.startsWith("+++") || line.startsWith("---")) return "text-muted-foreground";
122405
+ return "";
122406
+ }
122407
+ function WorkspaceDiffView({ workspace }) {
122408
+ const diff = useRelayStore((s) => s.workspaceDiff[workspace.id]);
122409
+ const fetchWorkspaceDiff = useRelayStore((s) => s.fetchWorkspaceDiff);
122410
+ const eligible = workspace.mode === "isolated" && Boolean(workspace.worktreePath);
122411
+ (0, import_react.useEffect)(() => {
122412
+ if (eligible && diff === void 0) fetchWorkspaceDiff(workspace.id);
122413
+ }, [
122414
+ eligible,
122415
+ diff,
122416
+ workspace.id,
122417
+ fetchWorkspaceDiff
122418
+ ]);
122419
+ if (!eligible) return null;
122420
+ if (diff === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122421
+ className: "text-[11px] text-muted-foreground",
122422
+ children: "Loading diff…"
122423
+ });
122424
+ if (diff.available === false) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122425
+ className: "text-[11px] text-muted-foreground",
122426
+ children: ["Diff unavailable", diff.reason ? `: ${diff.reason}` : ""]
122427
+ });
122428
+ if (diff.missing) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122429
+ className: "text-[11px] text-muted-foreground",
122430
+ children: "Worktree no longer on disk"
122431
+ });
122432
+ if (diff.error) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122433
+ className: "text-[11px] text-red-400",
122434
+ children: ["Diff error: ", diff.error]
122435
+ });
122436
+ if (!diff.files.length) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122437
+ className: "text-[11px] text-muted-foreground",
122438
+ children: ["No committed changes against ", diff.baseRef || "base"]
122439
+ });
122440
+ const refresh = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
122441
+ size: "icon-sm",
122442
+ variant: "ghost",
122443
+ className: "h-5 w-5",
122444
+ title: "Refresh diff",
122445
+ onClick: () => void fetchWorkspaceDiff(workspace.id),
122446
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "h-3 w-3" })
122447
+ });
122448
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122449
+ className: "space-y-1",
121957
122450
  children: [
121958
122451
  /* @__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
122452
+ className: "flex items-center gap-2 text-[11px] font-medium",
122453
+ children: [
122454
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileDiff, { className: "h-3 w-3" }),
122455
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
122456
+ diff.files.length,
122457
+ " file",
122458
+ diff.files.length === 1 ? "" : "s",
122459
+ " vs ",
122460
+ diff.baseRef || "base"
122461
+ ] }),
122462
+ refresh
122463
+ ]
122464
+ }),
122465
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
122466
+ className: "space-y-0.5 text-[11px]",
122467
+ children: diff.files.map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
122468
+ className: "flex items-center gap-2 font-mono",
122469
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122470
+ className: "truncate",
122471
+ title: file.path,
122472
+ children: file.path
122473
+ }), file.binary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122474
+ className: "shrink-0 text-muted-foreground",
122475
+ children: "binary"
122476
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122477
+ className: "shrink-0",
122478
+ children: [
122479
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122480
+ className: "text-emerald-400",
122481
+ children: ["+", file.additions ?? 0]
122482
+ }),
122483
+ " ",
122484
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
122485
+ className: "text-red-400",
122486
+ children: ["−", file.deletions ?? 0]
122487
+ })
122488
+ ]
121966
122489
  })]
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
- })]
122490
+ }, file.path))
121987
122491
  }),
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
122492
+ diff.patch && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("pre", {
122493
+ className: "max-h-80 overflow-auto rounded border border-border bg-muted/30 p-2 text-[10.5px] leading-relaxed",
122494
+ children: [diff.patch.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122495
+ className: diffLineClass(line),
122496
+ children: line || " "
122497
+ }, i)), diff.truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122498
+ className: "mt-1 text-muted-foreground",
122499
+ children: " patch truncated"
121998
122500
  })]
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",
122501
+ })
122502
+ ]
122503
+ });
122504
+ }
122505
+ function WorkspaceDetails({ workspace }) {
122506
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122507
+ className: "space-y-3 border-t border-dashed border-border bg-muted/20 px-3 py-3",
122508
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceTimeline, { workspace }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceDiffView, { workspace })]
122509
+ });
122510
+ }
122511
+ function OrphanPanel() {
122512
+ const orphans = useRelayStore((s) => s.workspaceOrphans);
122513
+ const fetchWorkspaceOrphans = useRelayStore((s) => s.fetchWorkspaceOrphans);
122514
+ const reclaimWorkspaceOrphan = useRelayStore((s) => s.reclaimWorkspaceOrphan);
122515
+ (0, import_react.useEffect)(() => {
122516
+ fetchWorkspaceOrphans();
122517
+ }, [fetchWorkspaceOrphans]);
122518
+ if (!orphans.length) return null;
122519
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
122520
+ className: "border-amber-500/30",
122521
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardHeader, {
122522
+ className: "px-4 py-3",
122523
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122524
+ className: "flex items-center gap-2",
122002
122525
  children: [
122003
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122004
- className: "text-muted-foreground",
122005
- children: "Owner"
122526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PackageOpen, { className: "h-4 w-4 text-amber-400" }),
122527
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardTitle, {
122528
+ className: "text-sm font-medium",
122529
+ children: "Orphaned worktrees"
122006
122530
  }),
122007
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122008
- className: "truncate",
122009
- title: workspace.ownerAgentId,
122010
- children: agentLabel(owner, workspace.ownerPolicyName || workspace.ownerAgentId)
122531
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
122532
+ variant: "outline",
122533
+ className: "border-amber-500/30 text-amber-400 text-[10px]",
122534
+ children: orphans.length
122011
122535
  }),
122536
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
122537
+ size: "icon-sm",
122538
+ variant: "ghost",
122539
+ className: "ml-auto h-6 w-6",
122540
+ title: "Rescan",
122541
+ onClick: () => void fetchWorkspaceOrphans(),
122542
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "h-3.5 w-3.5" })
122543
+ })
122544
+ ]
122545
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
122546
+ className: "mt-1 text-xs text-muted-foreground",
122547
+ children: "Agent worktrees on disk with no live workspace. Reclaim removes them from the host."
122548
+ })]
122549
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
122550
+ className: "p-0",
122551
+ children: orphans.map((orphan) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122552
+ className: "flex items-center gap-3 border-t border-border px-4 py-2 text-xs",
122553
+ children: [
122554
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitBranch, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
122012
122555
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122013
- className: "text-muted-foreground",
122014
- children: "Steward"
122556
+ className: "truncate font-medium",
122557
+ title: orphan.branch,
122558
+ children: orphan.branch || "(detached)"
122015
122559
  }),
122016
122560
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122017
- className: "truncate",
122018
- title: workspace.stewardAgentId,
122019
- children: agentLabel(steward, workspace.stewardAgentId)
122561
+ className: "truncate font-mono text-muted-foreground",
122562
+ title: orphan.worktreePath,
122563
+ children: shortPath(orphan.worktreePath)
122020
122564
  }),
122021
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122022
- className: "text-muted-foreground",
122023
- children: "Updated"
122565
+ orphan.hadTerminalRow && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
122566
+ variant: "outline",
122567
+ className: "text-[10px]",
122568
+ children: "cleanup failed"
122024
122569
  }),
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
- })] })
122570
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
122571
+ size: "sm",
122572
+ variant: "outline",
122573
+ className: "ml-auto h-7 text-xs",
122574
+ onClick: () => void reclaimWorkspaceOrphan(orphan),
122575
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArchiveRestore, { className: "mr-1 h-3.5 w-3.5" }), "Reclaim"]
122576
+ })
122034
122577
  ]
122035
- }),
122036
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceActions, { workspace })
122037
- ]
122578
+ }, orphan.worktreePath))
122579
+ })]
122580
+ });
122581
+ }
122582
+ function WorkspaceRow({ workspace }) {
122583
+ const now = useNow();
122584
+ const [expanded, setExpanded] = (0, import_react.useState)(false);
122585
+ const agentsById = useRelayStore((s) => s.agentsById);
122586
+ const owner = workspace.ownerAgentId ? agentsById[workspace.ownerAgentId] : void 0;
122587
+ const steward = workspace.stewardAgentId ? agentsById[workspace.stewardAgentId] : void 0;
122588
+ const path = workspace.worktreePath || workspace.sourceCwd || workspace.repoRoot;
122589
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122590
+ className: "border-t border-border",
122591
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122592
+ 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)]",
122593
+ children: [
122594
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122595
+ className: "min-w-0 space-y-1",
122596
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122597
+ className: "flex min-w-0 items-center gap-2",
122598
+ 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", {
122599
+ className: "truncate font-medium",
122600
+ title: workspace.branch || workspace.id,
122601
+ children: workspace.branch || workspace.id
122602
+ })]
122603
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122604
+ className: "flex flex-wrap gap-1",
122605
+ children: [
122606
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
122607
+ variant: "outline",
122608
+ className: `text-[10px] ${workspace.mode === "isolated" ? "border-sky-500/30 text-sky-400" : "border-zinc-500/30 text-zinc-400"}`,
122609
+ children: workspace.mode
122610
+ }),
122611
+ workspace.requestedMode && workspace.requestedMode !== workspace.mode && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
122612
+ variant: "outline",
122613
+ className: "text-[10px]",
122614
+ children: ["requested ", workspace.requestedMode]
122615
+ }),
122616
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
122617
+ variant: "outline",
122618
+ className: `text-[10px] ${statusTone(workspace.status)}`,
122619
+ children: STATUS_LABEL[workspace.status] || workspace.status
122620
+ })
122621
+ ]
122622
+ })]
122623
+ }),
122624
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122625
+ className: "min-w-0 space-y-1",
122626
+ children: [
122627
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122628
+ className: "truncate font-mono text-xs",
122629
+ title: path,
122630
+ children: shortPath(path)
122631
+ }),
122632
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122633
+ className: "truncate text-xs text-muted-foreground",
122634
+ title: workspace.sourceCwd,
122635
+ children: workspace.sourceCwd
122636
+ }),
122637
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitState, { workspace })
122638
+ ]
122639
+ }),
122640
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
122641
+ className: "grid grid-cols-[4.5rem_minmax(0,1fr)] gap-x-2 gap-y-1 text-xs",
122642
+ children: [
122643
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122644
+ className: "text-muted-foreground",
122645
+ children: "Owner"
122646
+ }),
122647
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122648
+ className: "truncate",
122649
+ title: workspace.ownerAgentId,
122650
+ children: agentLabel(owner, workspace.ownerPolicyName || workspace.ownerAgentId)
122651
+ }),
122652
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122653
+ className: "text-muted-foreground",
122654
+ children: "Steward"
122655
+ }),
122656
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122657
+ className: "truncate",
122658
+ title: workspace.stewardAgentId,
122659
+ children: agentLabel(steward, workspace.stewardAgentId)
122660
+ }),
122661
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122662
+ className: "text-muted-foreground",
122663
+ children: "Updated"
122664
+ }),
122665
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: timeAgo(now, workspace.updatedAt) }),
122666
+ workspace.baseRef && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122667
+ className: "text-muted-foreground",
122668
+ children: "Base"
122669
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
122670
+ className: "truncate",
122671
+ title: workspace.baseSha,
122672
+ children: workspace.baseRef
122673
+ })] })
122674
+ ]
122675
+ }),
122676
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceActions, {
122677
+ workspace,
122678
+ expanded,
122679
+ onToggleDetails: () => setExpanded((value) => !value)
122680
+ })
122681
+ ]
122682
+ }), expanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceDetails, { workspace })]
122038
122683
  });
122039
122684
  }
122040
122685
  function RepoGroup({ repoRoot, workspaces }) {
@@ -122092,17 +122737,17 @@ function WorkspacesView() {
122092
122737
  const isolatedCount = workspaces.filter((item) => item.mode === "isolated").length;
122093
122738
  const readyCount = workspaces.filter((item) => item.status === "ready" || item.status === "review_requested" || item.status === "merge_planned").length;
122094
122739
  const conflictCount = workspaces.filter((item) => item.status === "conflict").length;
122095
- const cleanedCount = workspaces.filter((item) => item.status === "cleaned").length;
122740
+ const doneCount = workspaces.filter((item) => TERMINAL_STATUSES.has(item.status)).length;
122096
122741
  const filters = [
122097
122742
  {
122098
122743
  key: "active",
122099
122744
  label: "Active",
122100
- count: workspaces.length - cleanedCount
122745
+ count: workspaces.length - doneCount
122101
122746
  },
122102
122747
  {
122103
122748
  key: "cleaned",
122104
- label: "Cleaned",
122105
- count: cleanedCount
122749
+ label: "Done",
122750
+ count: doneCount
122106
122751
  },
122107
122752
  {
122108
122753
  key: "all",
@@ -122144,6 +122789,7 @@ function WorkspacesView() {
122144
122789
  ]
122145
122790
  })]
122146
122791
  }),
122792
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OrphanPanel, {}),
122147
122793
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
122148
122794
  className: "flex flex-wrap items-center gap-2",
122149
122795
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -125120,6 +125766,7 @@ function blankForm(orchestratorId = "") {
125120
125766
  ifNoMatch: "fail",
125121
125767
  cwd: "",
125122
125768
  approvalMode: "guarded",
125769
+ workspaceMode: "inherit",
125123
125770
  keepAlive: false,
125124
125771
  budgetMinutes: "",
125125
125772
  warningMinutes: "",
@@ -125158,6 +125805,7 @@ function automationToForm(automation) {
125158
125805
  ifNoMatch: policy.mode === "existing_agent" ? policy.ifNoMatch || "fail" : "fail",
125159
125806
  cwd: policy.mode === "on_demand_agent" ? policy.cwd || "" : "",
125160
125807
  approvalMode: policy.mode === "on_demand_agent" ? policy.approvalMode || "guarded" : "guarded",
125808
+ workspaceMode: policy.mode === "on_demand_agent" ? policy.workspaceMode || "inherit" : "inherit",
125161
125809
  keepAlive: policy.mode === "on_demand_agent" ? Boolean(policy.keepAlive) : false,
125162
125810
  budgetMinutes: policy.mode === "on_demand_agent" && policy.runtimeBudget ? String(Math.round(policy.runtimeBudget.maxRuntimeMs / 6e4)) : "",
125163
125811
  warningMinutes: policy.mode === "on_demand_agent" && policy.runtimeBudget?.warnAtMs !== void 0 ? String(Math.round(policy.runtimeBudget.warnAtMs / 6e4)) : "",
@@ -125195,6 +125843,7 @@ function formToInput(form) {
125195
125843
  profile: form.profile || void 0,
125196
125844
  cwd: form.cwd.trim() || void 0,
125197
125845
  approvalMode: form.approvalMode,
125846
+ workspaceMode: form.workspaceMode,
125198
125847
  keepAlive: form.keepAlive,
125199
125848
  runtimeBudget
125200
125849
  };
@@ -125799,6 +126448,28 @@ function AutomationEditor({ form, selected, saving, orchestrators, agentProfiles
125799
126448
  children: profile.name
125800
126449
  }, profile.name))]
125801
126450
  })
126451
+ }),
126452
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field$1, {
126453
+ label: "Workspace",
126454
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
126455
+ className: "h-9 w-full rounded-md border border-input bg-background px-3 text-sm",
126456
+ value: form.workspaceMode,
126457
+ onChange: (e) => onChange({ workspaceMode: e.target.value }),
126458
+ children: [
126459
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
126460
+ value: "inherit",
126461
+ children: "inherit (default → isolated worktree)"
126462
+ }),
126463
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
126464
+ value: "shared",
126465
+ children: "shared (run in the repo, commit to its branch)"
126466
+ }),
126467
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
126468
+ value: "isolated",
126469
+ children: "isolated (fresh git worktree per run)"
126470
+ })
126471
+ ]
126472
+ })
125802
126473
  })
125803
126474
  ]
125804
126475
  }),
@@ -150319,10 +150990,6 @@ if ("serviceWorker" in navigator) {
150319
150990
  inset-block: calc(var(--spacing) * 0);
150320
150991
  }
150321
150992
 
150322
- .-top-3 {
150323
- top: calc(var(--spacing) * -3);
150324
- }
150325
-
150326
150993
  .top-0 {
150327
150994
  top: calc(var(--spacing) * 0);
150328
150995
  }
@@ -150363,6 +151030,14 @@ if ("serviceWorker" in navigator) {
150363
151030
  bottom: calc(var(--spacing) * -.5);
150364
151031
  }
150365
151032
 
151033
+ .-bottom-2\.5 {
151034
+ bottom: calc(var(--spacing) * -2.5);
151035
+ }
151036
+
151037
+ .bottom-full {
151038
+ bottom: 100%;
151039
+ }
151040
+
150366
151041
  .left-0 {
150367
151042
  left: calc(var(--spacing) * 0);
150368
151043
  }
@@ -150998,6 +151673,10 @@ if ("serviceWorker" in navigator) {
150998
151673
  max-width: var(--container-2xl);
150999
151674
  }
151000
151675
 
151676
+ .max-w-\[12rem\] {
151677
+ max-width: 12rem;
151678
+ }
151679
+
151001
151680
  .max-w-\[18rem\] {
151002
151681
  max-width: 18rem;
151003
151682
  }
@@ -151406,6 +152085,10 @@ if ("serviceWorker" in navigator) {
151406
152085
  column-gap: calc(var(--spacing) * 4);
151407
152086
  }
151408
152087
 
152088
+ .gap-y-0\.5 {
152089
+ row-gap: calc(var(--spacing) * .5);
152090
+ }
152091
+
151409
152092
  .gap-y-1 {
151410
152093
  row-gap: calc(var(--spacing) * 1);
151411
152094
  }
@@ -151590,6 +152273,16 @@ if ("serviceWorker" in navigator) {
151590
152273
  }
151591
152274
  }
151592
152275
 
152276
+ .border-amber-500\/20 {
152277
+ border-color: #f99c0033;
152278
+ }
152279
+
152280
+ @supports (color: color-mix(in lab, red, red)) {
152281
+ .border-amber-500\/20 {
152282
+ border-color: color-mix(in oklab, var(--color-amber-500) 20%, transparent);
152283
+ }
152284
+ }
152285
+
151593
152286
  .border-amber-500\/25 {
151594
152287
  border-color: #f99c0040;
151595
152288
  }
@@ -151912,6 +152605,16 @@ if ("serviceWorker" in navigator) {
151912
152605
  border-color: #0000;
151913
152606
  }
151914
152607
 
152608
+ .border-violet-500\/20 {
152609
+ border-color: #8d54ff33;
152610
+ }
152611
+
152612
+ @supports (color: color-mix(in lab, red, red)) {
152613
+ .border-violet-500\/20 {
152614
+ border-color: color-mix(in oklab, var(--color-violet-500) 20%, transparent);
152615
+ }
152616
+ }
152617
+
151915
152618
  .border-violet-500\/30 {
151916
152619
  border-color: #8d54ff4d;
151917
152620
  }
@@ -152890,6 +153593,10 @@ if ("serviceWorker" in navigator) {
152890
153593
  font-size: 9px;
152891
153594
  }
152892
153595
 
153596
+ .text-\[10\.5px\] {
153597
+ font-size: 10.5px;
153598
+ }
153599
+
152893
153600
  .text-\[10px\] {
152894
153601
  font-size: 10px;
152895
153602
  }
@@ -153124,6 +153831,16 @@ if ("serviceWorker" in navigator) {
153124
153831
  }
153125
153832
  }
153126
153833
 
153834
+ .text-muted-foreground\/70 {
153835
+ color: var(--muted-foreground);
153836
+ }
153837
+
153838
+ @supports (color: color-mix(in lab, red, red)) {
153839
+ .text-muted-foreground\/70 {
153840
+ color: color-mix(in oklab, var(--muted-foreground) 70%, transparent);
153841
+ }
153842
+ }
153843
+
153127
153844
  .text-muted-foreground\/80 {
153128
153845
  color: var(--muted-foreground);
153129
153846
  }
@@ -153330,6 +154047,10 @@ if ("serviceWorker" in navigator) {
153330
154047
  opacity: .6;
153331
154048
  }
153332
154049
 
154050
+ .opacity-70 {
154051
+ opacity: .7;
154052
+ }
154053
+
153333
154054
  .opacity-80 {
153334
154055
  opacity: .8;
153335
154056
  }
@@ -154029,6 +154750,10 @@ if ("serviceWorker" in navigator) {
154029
154750
  opacity: .5;
154030
154751
  }
154031
154752
 
154753
+ .disabled\:opacity-60:disabled {
154754
+ opacity: .6;
154755
+ }
154756
+
154032
154757
  .disabled\:opacity-70:disabled {
154033
154758
  opacity: .7;
154034
154759
  }