@ai-matrx/coding-sessions 0.1.81 → 0.1.85

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.
@@ -4,10 +4,10 @@
4
4
  import {
5
5
  useCallback as useCallback2,
6
6
  useContext as useContext3,
7
- useEffect as useEffect3,
8
- useMemo as useMemo3,
9
- useRef as useRef2,
10
- useState as useState5
7
+ useEffect as useEffect4,
8
+ useMemo as useMemo4,
9
+ useRef as useRef3,
10
+ useState as useState6
11
11
  } from "react";
12
12
  import {
13
13
  ChatComposer,
@@ -16,7 +16,7 @@ import {
16
16
  } from "@ai-matrx/chat/react";
17
17
  import { createExternalThreadSource as createExternalThreadSource2 } from "@ai-matrx/chat/external-store";
18
18
  import {
19
- Button as Button2,
19
+ Button as Button3,
20
20
  Dialog,
21
21
  DropdownMenu as DropdownMenu2,
22
22
  DropdownMenuContent as DropdownMenuContent2,
@@ -26,9 +26,9 @@ import {
26
26
  DialogFooter,
27
27
  DialogHeader,
28
28
  DialogTitle,
29
- Input,
30
- Textarea,
31
- cn as cn4
29
+ Input as Input2,
30
+ Textarea as Textarea2,
31
+ cn as cn5
32
32
  } from "@ai-matrx/design-system";
33
33
  import { formatCount, formatUsd } from "@ai-matrx/kit/format";
34
34
 
@@ -52,6 +52,21 @@ function formatUntil(until) {
52
52
  if (Number.isNaN(ms)) return until;
53
53
  return new Date(ms).toLocaleString(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
54
54
  }
55
+ var MODEL_UNAVAILABLE = [
56
+ /model is not supported when using codex/i,
57
+ /\bmodel[\s:'"`][^.\n]{0,80}\b(?:not supported|does not exist|not available|not found)\b/i,
58
+ /\bmodel_not_found\b/i,
59
+ /issue with the selected model/i,
60
+ /may not exist or you may not have access to it/i
61
+ ];
62
+ var MODEL_UNAVAILABLE_LABEL = "Model not available on this account";
63
+ function isModelUnavailable(text) {
64
+ const trimmed = (text ?? "").trim();
65
+ return trimmed !== "" && MODEL_UNAVAILABLE.some((re) => re.test(trimmed));
66
+ }
67
+ function runErrorLabel(text) {
68
+ return isModelUnavailable(text) ? MODEL_UNAVAILABLE_LABEL : text;
69
+ }
55
70
 
56
71
  // src/tool-labels.ts
57
72
  var BUILTIN = {
@@ -474,14 +489,20 @@ var SpinnerIcon = ({ size = 16, className }) => /* @__PURE__ */ jsxs(
474
489
  ]
475
490
  }
476
491
  );
477
- function ProviderMark({ provider, size = 18 }) {
492
+ var CLAUDE_MARK = "m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z";
493
+ var OPENAI_MARK = "M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z";
494
+ function ProviderMark({ provider, size = 16 }) {
478
495
  return /* @__PURE__ */ jsx(
479
- "span",
496
+ "svg",
480
497
  {
481
498
  className: `cs-provider-mark cs-provider-mark--${provider}`,
482
- style: { width: size, height: size, fontSize: Math.round(size * 0.58) },
499
+ width: size,
500
+ height: size,
501
+ viewBox: "0 0 24 24",
502
+ fill: "currentColor",
483
503
  "aria-hidden": "true",
484
- children: provider === "claude" ? "C" : "X"
504
+ "data-provider-mark": provider,
505
+ children: /* @__PURE__ */ jsx("path", { d: provider === "claude" ? CLAUDE_MARK : OPENAI_MARK })
485
506
  }
486
507
  );
487
508
  }
@@ -878,10 +899,230 @@ function ModelPicker(props) {
878
899
  ] });
879
900
  }
880
901
 
881
- // src/react/sidebar.tsx
882
- import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState4 } from "react";
902
+ // src/react/agent-field.tsx
903
+ import { useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState4 } from "react";
904
+ import { deriveRunInputs } from "@ai-matrx/agents";
905
+ import {
906
+ createAgentCatalog
907
+ } from "@ai-matrx/agents/catalog";
908
+ import { AgentCatalogProvider, AgentListDropdown } from "@ai-matrx/agents/catalog/react";
909
+ import { humanizeContextKey } from "@ai-matrx/agents/context";
883
910
  import {
884
911
  Button,
912
+ Input,
913
+ Select,
914
+ SelectContent,
915
+ SelectItem,
916
+ SelectTrigger,
917
+ SelectValue,
918
+ Textarea,
919
+ TooltipProvider,
920
+ cn as cn3
921
+ } from "@ai-matrx/design-system";
922
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
923
+ var SIGNED_OUT_AGENTS = "Sign in to AI Matrx to use your agents";
924
+ var LATEST = "latest";
925
+ function bridgedClient(transport) {
926
+ const call = (request) => {
927
+ const run = () => transport.call("agentCatalogRpc", request).then((result) => ({
928
+ data: result.data,
929
+ error: result.error ? {
930
+ message: result.error.message,
931
+ ...result.error.code ? { code: result.error.code } : {},
932
+ details: result.error.details ?? null,
933
+ hint: result.error.hint ?? null
934
+ } : null,
935
+ count: result.count ?? null
936
+ }));
937
+ return {
938
+ then: (onOk, onErr) => run().then(onOk, onErr),
939
+ range: (from, to) => call({ ...request, range: [from, to] }),
940
+ order: (column, options) => call({ ...request, order: { column, ascending: options?.ascending !== false } })
941
+ };
942
+ };
943
+ return {
944
+ rpc: (fn, args, options) => call({ fn, ...args ? { args } : {}, ...options?.count ? { count: options.count } : {} })
945
+ };
946
+ }
947
+ function useAgentAccess(transport, open) {
948
+ const [access, setAccess] = useState4(null);
949
+ useEffect2(() => {
950
+ if (!open) return;
951
+ let alive = true;
952
+ transport.call("agentAccess").then((next) => alive && setAccess(next)).catch(() => alive && setAccess({ signedIn: false, userId: null, organizationId: null, configured: false }));
953
+ return () => {
954
+ alive = false;
955
+ };
956
+ }, [transport, open]);
957
+ return access;
958
+ }
959
+ function useCatalog(transport, userId, onError) {
960
+ const report = useRef(onError);
961
+ report.current = onError;
962
+ return useMemo2(() => {
963
+ if (!userId) return null;
964
+ return createAgentCatalog({
965
+ client: bridgedClient(transport),
966
+ identity: { requireUserId: () => userId, getUserId: () => userId },
967
+ catalogId: `coding-sessions:${userId}`,
968
+ // A failed catalogue read shows at the field, never only in the console.
969
+ errorSink: (event) => {
970
+ console.error(`[coding-sessions] agent catalogue: ${event.code}: ${event.message}`);
971
+ if (event.code === "list_read_failed") report.current("Couldn't load your agents. Reopen to retry.");
972
+ }
973
+ });
974
+ }, [transport, userId]);
975
+ }
976
+ function asRunInputVariables(defs) {
977
+ return defs.flatMap((def) => typeof def.name === "string" ? [def] : []);
978
+ }
979
+ function AgentField(props) {
980
+ const access = useAgentAccess(props.transport, props.open);
981
+ const [details, setDetails] = useState4(null);
982
+ const [problem, setProblem] = useState4(null);
983
+ const catalog = useCatalog(props.transport, access?.signedIn ? access.userId : null, setProblem);
984
+ const agentId = props.value?.agentId ?? null;
985
+ useEffect2(() => {
986
+ setDetails(null);
987
+ setProblem(null);
988
+ if (!agentId) return;
989
+ let alive = true;
990
+ props.transport.call("agentDetails", agentId).then((next) => alive && setDetails(next)).catch((error) => alive && setProblem(error instanceof Error ? error.message : String(error)));
991
+ return () => {
992
+ alive = false;
993
+ };
994
+ }, [agentId, props.transport]);
995
+ const { onDetails } = props;
996
+ useEffect2(() => {
997
+ onDetails?.(details);
998
+ }, [details, onDetails]);
999
+ const inputs = useMemo2(() => deriveRunInputs(asRunInputVariables(details?.variables ?? []), humanizeContextKey), [details]);
1000
+ if (access === null) return /* @__PURE__ */ jsx5("div", { className: "cs-skeleton h-9 rounded-lg" });
1001
+ if (!access.signedIn || !catalog) {
1002
+ return /* @__PURE__ */ jsx5("p", { className: "text-[12.5px] text-muted-foreground", children: SIGNED_OUT_AGENTS });
1003
+ }
1004
+ const setVariable = (name, value) => {
1005
+ if (!props.value) return;
1006
+ props.onChange({ ...props.value, variables: { ...props.value.variables ?? {}, [name]: value } });
1007
+ };
1008
+ return /* @__PURE__ */ jsxs5("div", { className: "space-y-3", children: [
1009
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
1010
+ /* @__PURE__ */ jsx5(TooltipProvider, { children: /* @__PURE__ */ jsx5(AgentCatalogProvider, { catalog, children: /* @__PURE__ */ jsx5(
1011
+ AgentListDropdown,
1012
+ {
1013
+ consumerId: "coding-sessions-new-session",
1014
+ activeAgentId: agentId,
1015
+ label: details?.name ?? (agentId ? "Loading\u2026" : "None"),
1016
+ onSelect: (id) => props.onChange({ agentId: id, versionId: null, variables: {} })
1017
+ }
1018
+ ) }) }),
1019
+ agentId ? /* @__PURE__ */ jsx5(Button, { type: "button", size: "sm", variant: "ghost", onClick: () => props.onChange(null), children: "Remove" }) : null
1020
+ ] }),
1021
+ problem ? /* @__PURE__ */ jsx5("p", { className: "text-[12px] text-destructive", children: problem }) : null,
1022
+ details && props.value ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
1023
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
1024
+ /* @__PURE__ */ jsx5("span", { className: "w-[72px] shrink-0 text-[12px] text-muted-foreground", children: "Version" }),
1025
+ /* @__PURE__ */ jsxs5(
1026
+ Select,
1027
+ {
1028
+ value: props.value.versionId ?? LATEST,
1029
+ onValueChange: (next) => props.value && props.onChange({ ...props.value, versionId: next === LATEST ? null : next }),
1030
+ children: [
1031
+ /* @__PURE__ */ jsx5(SelectTrigger, { className: "h-8 w-[200px] text-[12.5px]", "aria-label": "Agent version", children: /* @__PURE__ */ jsx5(SelectValue, {}) }),
1032
+ /* @__PURE__ */ jsxs5(SelectContent, { children: [
1033
+ /* @__PURE__ */ jsx5(SelectItem, { value: LATEST, children: details.latestVersionNumber !== null ? `Latest (v${details.latestVersionNumber})` : "Latest" }),
1034
+ details.versions.map((v) => /* @__PURE__ */ jsxs5(SelectItem, { value: v.id, children: [
1035
+ "v",
1036
+ v.versionNumber
1037
+ ] }, v.id))
1038
+ ] })
1039
+ ]
1040
+ }
1041
+ )
1042
+ ] }),
1043
+ inputs.map((input) => {
1044
+ const raw = props.value?.variables?.[input.name];
1045
+ const value = typeof raw === "string" ? raw : "";
1046
+ const id = `cs-agent-var-${input.name}`;
1047
+ const invalid = props.missing === input.name;
1048
+ return /* @__PURE__ */ jsxs5("div", { className: "space-y-1", children: [
1049
+ /* @__PURE__ */ jsxs5("label", { htmlFor: id, className: "text-[12px] font-medium", children: [
1050
+ input.label,
1051
+ input.required ? /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground", children: " \xB7 required" }) : null
1052
+ ] }),
1053
+ input.options && input.options.length > 0 ? /* @__PURE__ */ jsxs5(Select, { value, onValueChange: (next) => setVariable(input.name, next), children: [
1054
+ /* @__PURE__ */ jsx5(SelectTrigger, { id, className: "h-8 text-[12.5px]", "aria-invalid": invalid || void 0, children: /* @__PURE__ */ jsx5(SelectValue, { placeholder: "Choose\u2026" }) }),
1055
+ /* @__PURE__ */ jsx5(SelectContent, { children: input.options.map((option) => /* @__PURE__ */ jsx5(SelectItem, { value: option, children: option }, option)) })
1056
+ ] }) : input.variable.customComponent?.type === "textarea" ? /* @__PURE__ */ jsx5(
1057
+ Textarea,
1058
+ {
1059
+ id,
1060
+ rows: 2,
1061
+ value,
1062
+ onChange: (e) => setVariable(input.name, e.target.value),
1063
+ placeholder: input.hint ?? "",
1064
+ "aria-invalid": invalid || void 0
1065
+ }
1066
+ ) : /* @__PURE__ */ jsx5(
1067
+ Input,
1068
+ {
1069
+ id,
1070
+ value,
1071
+ onChange: (e) => setVariable(input.name, e.target.value),
1072
+ placeholder: input.hint ?? "",
1073
+ "aria-invalid": invalid || void 0
1074
+ }
1075
+ ),
1076
+ invalid ? /* @__PURE__ */ jsx5("p", { className: "text-[12px] text-destructive", children: "Fill this in to use the agent" }) : null
1077
+ ] }, input.name);
1078
+ })
1079
+ ] }) : null
1080
+ ] });
1081
+ }
1082
+ function missingRequiredVariable(details, selection) {
1083
+ if (!details || !selection) return null;
1084
+ for (const input of deriveRunInputs(asRunInputVariables(details.variables), humanizeContextKey)) {
1085
+ if (!input.required) continue;
1086
+ const value = selection.variables?.[input.name];
1087
+ if (typeof value !== "string" || !value.trim()) return input.name;
1088
+ }
1089
+ return null;
1090
+ }
1091
+ var PART_LABEL = {
1092
+ instructions: "Instructions",
1093
+ skills: "Skills",
1094
+ tools: "Tools"
1095
+ };
1096
+ function AgentChip({ agent }) {
1097
+ const parts = agent.loaded.map(
1098
+ (part) => part.part === "instructions" ? `${PART_LABEL.instructions} ${part.loaded === 1 ? "\u2713" : "\u2014"}` : `${PART_LABEL[part.part]} ${part.loaded}/${part.total}`
1099
+ );
1100
+ const missing = agent.unavailable.slice(0, 6).map((u) => `${u.name}: ${u.reason}`);
1101
+ const more = agent.unavailable.length > 6 ? [`+${agent.unavailable.length - 6} more`] : [];
1102
+ const complete = agent.loaded.every((part) => part.loaded === part.total);
1103
+ return /* @__PURE__ */ jsxs5(
1104
+ "span",
1105
+ {
1106
+ className: cn3("cs-agent-chip", !complete && "cs-agent-chip--partial"),
1107
+ title: missing.length ? [...missing, ...more].join("\n") : "Everything loaded",
1108
+ "data-testid": "cs-agent-chip",
1109
+ children: [
1110
+ /* @__PURE__ */ jsxs5("span", { className: "font-medium text-foreground", children: [
1111
+ agent.name,
1112
+ agent.versionNumber !== null ? ` v${agent.versionNumber}` : ""
1113
+ ] }),
1114
+ " ",
1115
+ "\xB7 ",
1116
+ parts.join(" \xB7 ")
1117
+ ]
1118
+ }
1119
+ );
1120
+ }
1121
+
1122
+ // src/react/sidebar.tsx
1123
+ import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState5 } from "react";
1124
+ import {
1125
+ Button as Button2,
885
1126
  ContextMenu,
886
1127
  ContextMenuContent,
887
1128
  ContextMenuTrigger,
@@ -893,9 +1134,9 @@ import {
893
1134
  DropdownMenuRadioItem,
894
1135
  DropdownMenuSeparator as DropdownMenuSeparator2,
895
1136
  DropdownMenuTrigger,
896
- cn as cn3
1137
+ cn as cn4
897
1138
  } from "@ai-matrx/design-system";
898
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1139
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
899
1140
  function readLocal(key, allowed, fallback) {
900
1141
  try {
901
1142
  const value = localStorage.getItem(key);
@@ -911,23 +1152,23 @@ function writeLocal(key, value) {
911
1152
  }
912
1153
  }
913
1154
  function SectionLabel({ children, action }) {
914
- return /* @__PURE__ */ jsxs5("div", { className: "flex h-8 items-center justify-between px-3 pt-3", children: [
915
- /* @__PURE__ */ jsx5("span", { className: "text-[11px] font-medium uppercase tracking-[0.06em] text-muted-foreground", children }),
1155
+ return /* @__PURE__ */ jsxs6("div", { "data-cs-section-label": true, className: "flex h-8 items-center justify-between px-3 pt-3", children: [
1156
+ /* @__PURE__ */ jsx6("span", { className: "text-[12px] font-medium text-muted-foreground", children }),
916
1157
  action
917
1158
  ] });
918
1159
  }
919
1160
  function GroupLabel({ children }) {
920
- return /* @__PURE__ */ jsx5("div", { className: "truncate px-4 pb-0.5 pt-2.5 text-[11px] font-medium text-muted-foreground/80", children });
1161
+ return /* @__PURE__ */ jsx6("div", { className: "truncate px-4 pb-0.5 pt-2.5 text-[12px] font-medium text-muted-foreground", children });
921
1162
  }
922
1163
  function RenameInput(props) {
923
- const [value, setValue] = useState4(props.initial);
924
- const done = useRef(false);
1164
+ const [value, setValue] = useState5(props.initial);
1165
+ const done = useRef2(false);
925
1166
  const finish = (title) => {
926
1167
  if (done.current) return;
927
1168
  done.current = true;
928
1169
  props.onDone(title);
929
1170
  };
930
- return /* @__PURE__ */ jsx5(
1171
+ return /* @__PURE__ */ jsx6(
931
1172
  "input",
932
1173
  {
933
1174
  autoFocus: true,
@@ -944,11 +1185,16 @@ function RenameInput(props) {
944
1185
  }
945
1186
  );
946
1187
  }
1188
+ function entryTarget(entry) {
1189
+ if (entry.kind === "session" && entry.session) return `#s/${entry.session.id}`;
1190
+ if (entry.providerSessionId) return `#d/${entry.provider}/${entry.providerSessionId}`;
1191
+ return "";
1192
+ }
947
1193
  function Row(props) {
948
1194
  const client = useCodingSessionsClient();
949
1195
  const show = useToastShow();
950
- const [renaming, setRenaming] = useState4(false);
951
- const [menuOpen, setMenuOpen] = useState4(false);
1196
+ const [renaming, setRenaming] = useState5(false);
1197
+ const [menuOpen, setMenuOpen] = useState5(false);
952
1198
  const { entry } = props;
953
1199
  const rename = (title) => {
954
1200
  setRenaming(false);
@@ -958,14 +1204,20 @@ function Row(props) {
958
1204
  (error) => show(`The new name didn't save: ${error instanceof Error ? error.message : String(error)}`)
959
1205
  );
960
1206
  };
961
- return /* @__PURE__ */ jsxs5(ContextMenu, { children: [
962
- /* @__PURE__ */ jsx5(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
1207
+ return /* @__PURE__ */ jsxs6(ContextMenu, { children: [
1208
+ /* @__PURE__ */ jsx6(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
963
1209
  "div",
964
1210
  {
965
- className: cn3("cs-row group", props.active && "cs-row--active", menuOpen && "cs-row--menu"),
1211
+ className: cn4("cs-row group", props.active && "cs-row--active", menuOpen && "cs-row--menu"),
966
1212
  "data-hidden": entry.hidden || void 0,
1213
+ "data-cs-row": entry.key,
1214
+ "data-cs-target": entryTarget(entry),
1215
+ "data-cs-provider": entry.provider,
1216
+ "data-cs-title": entry.title,
1217
+ "data-cs-live": props.live ? "true" : void 0,
1218
+ "data-cs-active": props.active ? "true" : void 0,
967
1219
  children: [
968
- /* @__PURE__ */ jsx5(
1220
+ /* @__PURE__ */ jsx6(
969
1221
  "button",
970
1222
  {
971
1223
  type: "button",
@@ -977,39 +1229,39 @@ function Row(props) {
977
1229
  (${entry.originalTitle})` : entry.title
978
1230
  }
979
1231
  ),
980
- /* @__PURE__ */ jsx5("span", { className: "pointer-events-none mt-0.5 shrink-0", children: props.live ? /* @__PURE__ */ jsx5(SpinnerIcon, { size: 16, className: "text-primary" }) : /* @__PURE__ */ jsx5(ProviderMark, { provider: entry.provider, size: 16 }) }),
981
- /* @__PURE__ */ jsxs5("span", { className: "cs-row__body", children: [
982
- renaming ? /* @__PURE__ */ jsx5("span", { className: "pointer-events-auto relative z-10 block", children: /* @__PURE__ */ jsx5(RenameInput, { initial: entry.title, onDone: rename }) }) : /* @__PURE__ */ jsxs5("span", { className: "flex items-center gap-1", children: [
983
- /* @__PURE__ */ jsx5("span", { className: "min-w-0 truncate text-[13px] font-medium leading-5", children: entry.title }),
984
- entry.pinned ? /* @__PURE__ */ jsx5(PinIcon, { size: 11, className: "shrink-0 text-muted-foreground", "aria-label": "Pinned" }) : null
1232
+ /* @__PURE__ */ jsx6("span", { className: "pointer-events-none mt-0.5 shrink-0", children: props.live ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 16, className: "text-primary" }) : /* @__PURE__ */ jsx6(ProviderMark, { provider: entry.provider, size: 16 }) }),
1233
+ /* @__PURE__ */ jsxs6("span", { className: "cs-row__body", children: [
1234
+ renaming ? /* @__PURE__ */ jsx6("span", { className: "pointer-events-auto relative z-10 block", children: /* @__PURE__ */ jsx6(RenameInput, { initial: entry.title, onDone: rename }) }) : /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-1", children: [
1235
+ /* @__PURE__ */ jsx6("span", { className: "min-w-0 truncate text-[13px] font-medium leading-5", children: entry.title }),
1236
+ entry.pinned ? /* @__PURE__ */ jsx6(PinIcon, { size: 11, className: "shrink-0 text-muted-foreground", "aria-label": "Pinned" }) : null
985
1237
  ] }),
986
- /* @__PURE__ */ jsx5("span", { className: "block truncate text-[11.5px] leading-4 text-muted-foreground", children: props.meta }),
987
- props.snippet ? /* @__PURE__ */ jsx5("span", { className: "cs-row__snippet", children: props.snippet }) : null
1238
+ /* @__PURE__ */ jsx6("span", { className: "block truncate text-[11.5px] leading-4 text-muted-foreground", children: props.meta }),
1239
+ props.snippet ? /* @__PURE__ */ jsx6("span", { className: "cs-row__snippet", children: props.snippet }) : null
988
1240
  ] }),
989
- renaming ? null : /* @__PURE__ */ jsxs5("span", { className: "cs-row__actions", children: [
1241
+ renaming ? null : /* @__PURE__ */ jsxs6("span", { className: "cs-row__actions", children: [
990
1242
  props.takeover,
991
- /* @__PURE__ */ jsxs5(DropdownMenu, { open: menuOpen, onOpenChange: setMenuOpen, children: [
992
- /* @__PURE__ */ jsx5(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx5("button", { type: "button", className: "cs-icon-button", "aria-label": `More for ${entry.title}`, title: "More", children: /* @__PURE__ */ jsx5(MoreIcon, { size: 15 }) }) }),
993
- /* @__PURE__ */ jsx5(DropdownMenuContent, { align: "start", className: "w-60", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx5(ChatMenuItems, { entry, variant: "dropdown", onRename: () => setRenaming(true) }) })
1243
+ /* @__PURE__ */ jsxs6(DropdownMenu, { open: menuOpen, onOpenChange: setMenuOpen, children: [
1244
+ /* @__PURE__ */ jsx6(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-icon-button", "aria-label": `More for ${entry.title}`, title: "More", children: /* @__PURE__ */ jsx6(MoreIcon, { size: 15 }) }) }),
1245
+ /* @__PURE__ */ jsx6(DropdownMenuContent, { align: "start", className: "w-60", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx6(ChatMenuItems, { entry, variant: "dropdown", onRename: () => setRenaming(true) }) })
994
1246
  ] })
995
1247
  ] })
996
1248
  ]
997
1249
  }
998
1250
  ) }),
999
- /* @__PURE__ */ jsx5(ContextMenuContent, { className: "w-60", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx5(ChatMenuItems, { entry, variant: "context", onRename: () => setRenaming(true) }) })
1251
+ /* @__PURE__ */ jsx6(ContextMenuContent, { className: "w-60", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx6(ChatMenuItems, { entry, variant: "context", onRename: () => setRenaming(true) }) })
1000
1252
  ] });
1001
1253
  }
1002
1254
  function SidebarSkeleton() {
1003
- return /* @__PURE__ */ jsx5("div", { className: "space-y-1.5 px-3 py-2", "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx5("div", { className: "cs-skeleton h-9 rounded-lg" }, i)) });
1255
+ return /* @__PURE__ */ jsx6("div", { className: "space-y-1.5 px-3 py-2", "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx6("div", { className: "cs-skeleton h-9 rounded-lg" }, i)) });
1004
1256
  }
1005
1257
  function Highlight({ text, query }) {
1006
1258
  const q = query.trim().toLowerCase();
1007
1259
  if (!q) return text;
1008
1260
  const at = text.toLowerCase().indexOf(q);
1009
1261
  if (at < 0) return text;
1010
- return /* @__PURE__ */ jsxs5(Fragment3, { children: [
1262
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1011
1263
  text.slice(0, at),
1012
- /* @__PURE__ */ jsx5("mark", { className: "cs-mark", children: text.slice(at, at + q.length) }),
1264
+ /* @__PURE__ */ jsx6("mark", { className: "cs-mark", children: text.slice(at, at + q.length) }),
1013
1265
  text.slice(at + q.length)
1014
1266
  ] });
1015
1267
  }
@@ -1024,8 +1276,8 @@ var EMPTY_SEARCH = {
1024
1276
  };
1025
1277
  function useContentSearch(query) {
1026
1278
  const client = useCodingSessionsClient();
1027
- const [state, setState] = useState4(EMPTY_SEARCH);
1028
- const latest = useRef(query);
1279
+ const [state, setState] = useState5(EMPTY_SEARCH);
1280
+ const latest = useRef2(query);
1029
1281
  latest.current = query;
1030
1282
  const run = useCallback(
1031
1283
  async (q, cursor, append) => {
@@ -1049,7 +1301,7 @@ function useContentSearch(query) {
1049
1301
  },
1050
1302
  [client]
1051
1303
  );
1052
- useEffect2(() => {
1304
+ useEffect3(() => {
1053
1305
  const q = query.trim();
1054
1306
  if (q.length < 2) {
1055
1307
  setState(EMPTY_SEARCH);
@@ -1078,19 +1330,19 @@ function Sidebar(props) {
1078
1330
  const client = useCodingSessionsClient();
1079
1331
  const state = useCodingSessionsState();
1080
1332
  const now = useMinuteClock();
1081
- const [query, setQuery] = useState4("");
1333
+ const [query, setQuery] = useState5("");
1082
1334
  const [search, searchMore] = useContentSearch(query);
1083
- const [groupMode, setGroupMode] = useState4(() => readLocal("coding-sessions.group", ["date", "folder"], "date"));
1084
- const [showHidden, setShowHidden] = useState4(false);
1085
- const [takingOver, setTakingOver] = useState4(null);
1086
- const [takeoverError, setTakeoverError] = useState4(null);
1335
+ const [groupMode, setGroupMode] = useState5(() => readLocal("coding-sessions.group", ["date", "folder"], "date"));
1336
+ const [showHidden, setShowHidden] = useState5(false);
1337
+ const [takingOver, setTakingOver] = useState5(null);
1338
+ const [takeoverError, setTakeoverError] = useState5(null);
1087
1339
  const prefs = state.preferences;
1088
1340
  const sessions = state.sessions.data;
1089
1341
  const isLive = (id) => {
1090
1342
  const run = state.runs[id];
1091
1343
  return run !== void 0 && !isTerminalRunStatus(run.status);
1092
1344
  };
1093
- const { ours, others, hiddenCount } = useMemo2(() => {
1345
+ const { ours, others, hiddenCount } = useMemo3(() => {
1094
1346
  const oursList = sessions.map((s) => sessionEntry(s, prefs));
1095
1347
  const known = new Set(sessions.map((s) => s.providerSessionId).filter(Boolean));
1096
1348
  const othersList = state.discovered.data.filter((d) => !known.has(d.providerSessionId)).map((d) => discoveredEntry(d, prefs));
@@ -1130,8 +1382,8 @@ function Sidebar(props) {
1130
1382
  let meta;
1131
1383
  if (live) meta = `${PROVIDER_LABEL[entry.provider]} is working\u2026`;
1132
1384
  else if (d?.activeElsewhere)
1133
- meta = /* @__PURE__ */ jsxs5("span", { className: "cs-live-elsewhere", children: [
1134
- /* @__PURE__ */ jsx5("span", { className: "cs-live-dot", "aria-hidden": "true" }),
1385
+ meta = /* @__PURE__ */ jsxs6("span", { className: "cs-live-elsewhere", children: [
1386
+ /* @__PURE__ */ jsx6("span", { className: "cs-live-dot", "aria-hidden": "true" }),
1135
1387
  "Running in ",
1136
1388
  PROVIDER_LABEL[entry.provider]
1137
1389
  ] });
@@ -1140,8 +1392,8 @@ function Sidebar(props) {
1140
1392
  const where = entry.cwd ? prettyPath2(entry.cwd) : "unknown folder";
1141
1393
  meta = `${status}${entry.kind === "discovered" ? `${PROVIDER_LABEL[entry.provider]} \xB7 ` : ""}${groupMode === "folder" && !extra ? "" : `${where} \xB7 `}${relativeTime(entry.updatedAt, now)}`;
1142
1394
  }
1143
- return /* @__PURE__ */ jsxs5("div", { children: [
1144
- /* @__PURE__ */ jsx5(
1395
+ return /* @__PURE__ */ jsxs6("div", { children: [
1396
+ /* @__PURE__ */ jsx6(
1145
1397
  Row,
1146
1398
  {
1147
1399
  entry,
@@ -1150,7 +1402,7 @@ function Sidebar(props) {
1150
1402
  live,
1151
1403
  meta,
1152
1404
  snippet: extra?.snippet,
1153
- takeover: d?.cwd ? /* @__PURE__ */ jsxs5(
1405
+ takeover: d?.cwd ? /* @__PURE__ */ jsxs6(
1154
1406
  "button",
1155
1407
  {
1156
1408
  type: "button",
@@ -1159,18 +1411,18 @@ function Sidebar(props) {
1159
1411
  title: d.activeElsewhere ? d.activeElsewhere.message : "Continue this chat here",
1160
1412
  disabled: takingOver === d.providerSessionId,
1161
1413
  children: [
1162
- takingOver === d.providerSessionId ? /* @__PURE__ */ jsx5(SpinnerIcon, { size: 11 }) : null,
1414
+ takingOver === d.providerSessionId ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 11 }) : null,
1163
1415
  "Take over"
1164
1416
  ]
1165
1417
  }
1166
1418
  ) : null
1167
1419
  }
1168
1420
  ),
1169
- takeoverError && d && takeoverError.id === d.providerSessionId ? /* @__PURE__ */ jsx5("p", { className: "mx-4 mb-1 text-[11.5px] text-destructive", children: takeoverError.message }) : null
1421
+ takeoverError && d && takeoverError.id === d.providerSessionId ? /* @__PURE__ */ jsx6("p", { className: "mx-4 mb-1 text-[11.5px] text-destructive", children: takeoverError.message }) : null
1170
1422
  ] }, entry.key);
1171
1423
  };
1172
- const renderGroups = (entries) => groupEntries(entries, groupMode, now).map((group) => /* @__PURE__ */ jsxs5("div", { role: "group", "aria-label": group.label, children: [
1173
- /* @__PURE__ */ jsx5(GroupLabel, { children: group.label }),
1424
+ const renderGroups = (entries) => groupEntries(entries, groupMode, now).map((group) => /* @__PURE__ */ jsxs6("div", { role: "group", "aria-label": group.label, children: [
1425
+ /* @__PURE__ */ jsx6(GroupLabel, { children: group.label }),
1174
1426
  group.entries.map((e) => renderEntry(e))
1175
1427
  ] }, group.label));
1176
1428
  const searching = query.trim().length > 0;
@@ -1187,60 +1439,60 @@ function Sidebar(props) {
1187
1439
  props.onFound(hitToDiscovered(hit));
1188
1440
  props.select({ kind: "discovered", provider: hit.provider, id: hit.providerSessionId });
1189
1441
  };
1190
- const searchBody = /* @__PURE__ */ jsxs5(Fragment3, { children: [
1191
- /* @__PURE__ */ jsx5(SectionLabel, { children: "Chats" }),
1192
- titleMatches.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "px-4 py-1 text-[12px] text-muted-foreground", children: "No listed chat has that in its name or folder." }) : titleMatches.map((e) => renderEntry(e, { query })),
1193
- /* @__PURE__ */ jsx5(SectionLabel, { children: "In conversations" }),
1194
- query.trim().length < 2 ? /* @__PURE__ */ jsx5("p", { className: "px-4 py-1 text-[12px] text-muted-foreground", children: "Type at least two letters to search what was said." }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
1442
+ const searchBody = /* @__PURE__ */ jsxs6(Fragment4, { children: [
1443
+ /* @__PURE__ */ jsx6(SectionLabel, { children: "Chats" }),
1444
+ titleMatches.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "px-4 py-1 text-[12px] text-muted-foreground", children: "No listed chat has that in its name or folder." }) : titleMatches.map((e) => renderEntry(e, { query })),
1445
+ /* @__PURE__ */ jsx6(SectionLabel, { children: "In conversations" }),
1446
+ query.trim().length < 2 ? /* @__PURE__ */ jsx6("p", { className: "px-4 py-1 text-[12px] text-muted-foreground", children: "Type at least two letters to search what was said." }) : /* @__PURE__ */ jsxs6(Fragment4, { children: [
1195
1447
  contentHits.map((hit) => {
1196
1448
  const known = allByKey.get(chatKey(hit.provider, hit.providerSessionId));
1197
1449
  const entry = known ?? discoveredEntry(hitToDiscovered(hit), prefs);
1198
- return /* @__PURE__ */ jsx5("div", { onClickCapture: known ? void 0 : () => props.onFound(hitToDiscovered(hit)), children: renderEntry(entry, {
1450
+ return /* @__PURE__ */ jsx6("div", { onClickCapture: known ? void 0 : () => props.onFound(hitToDiscovered(hit)), children: renderEntry(entry, {
1199
1451
  query,
1200
- snippet: hit.snippet ? /* @__PURE__ */ jsx5(Highlight, { text: hit.snippet, query }) : void 0
1452
+ snippet: hit.snippet ? /* @__PURE__ */ jsx6(Highlight, { text: hit.snippet, query }) : void 0
1201
1453
  }) }, `hit:${entry.key}`);
1202
1454
  }),
1203
- /* @__PURE__ */ jsx5("div", { className: "px-4 py-2 text-[11.5px] leading-4 text-muted-foreground", role: "status", "aria-live": "polite", children: search.error ? /* @__PURE__ */ jsxs5("span", { className: "text-destructive", children: [
1455
+ /* @__PURE__ */ jsx6("div", { className: "px-4 py-2 text-[11.5px] leading-4 text-muted-foreground", role: "status", "aria-live": "polite", children: search.error ? /* @__PURE__ */ jsxs6("span", { className: "text-destructive", children: [
1204
1456
  "Search stopped: ",
1205
1457
  search.error
1206
- ] }) : search.loading ? /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1.5", children: [
1207
- /* @__PURE__ */ jsx5(SpinnerIcon, { size: 12 }),
1458
+ ] }) : search.loading ? /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center gap-1.5", children: [
1459
+ /* @__PURE__ */ jsx6(SpinnerIcon, { size: 12 }),
1208
1460
  " Searching your chats\u2026"
1209
- ] }) : search.query ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
1461
+ ] }) : search.query ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1210
1462
  contentHits.length === 0 && search.hits.length === 0 ? "Nothing found. " : null,
1211
1463
  search.nextCursor === null ? `Searched all ${search.total.toLocaleString()} chats on this computer.` : `Searched the ${search.scanned.toLocaleString()} most recent of ${search.total.toLocaleString()} chats.`,
1212
- search.nextCursor !== null ? /* @__PURE__ */ jsx5("button", { type: "button", className: "cs-link ml-1", onClick: searchMore, children: "Search older chats" }) : null
1464
+ search.nextCursor !== null ? /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-link ml-1", onClick: searchMore, children: "Search older chats" }) : null
1213
1465
  ] }) : null })
1214
1466
  ] })
1215
1467
  ] });
1216
- const listBody = /* @__PURE__ */ jsxs5(Fragment3, { children: [
1217
- pinned.length > 0 ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
1218
- /* @__PURE__ */ jsx5(SectionLabel, { children: "Pinned" }),
1468
+ const listBody = /* @__PURE__ */ jsxs6(Fragment4, { children: [
1469
+ pinned.length > 0 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1470
+ /* @__PURE__ */ jsx6(SectionLabel, { children: "Pinned" }),
1219
1471
  pinned.map((e) => renderEntry(e))
1220
1472
  ] }) : null,
1221
- running.length > 0 ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
1222
- /* @__PURE__ */ jsx5(SectionLabel, { children: "Running" }),
1473
+ running.length > 0 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1474
+ /* @__PURE__ */ jsx6(SectionLabel, { children: "Running" }),
1223
1475
  running.map((e) => renderEntry(e))
1224
1476
  ] }) : null,
1225
- /* @__PURE__ */ jsx5(SectionLabel, { children: "Recent" }),
1226
- state.sessions.loading && state.sessions.loadedAt === null ? /* @__PURE__ */ jsx5(SidebarSkeleton, {}) : state.sessions.error ? /* @__PURE__ */ jsx5("p", { className: "px-4 py-1 text-[12px] text-destructive", children: state.sessions.error }) : recent.length === 0 ? running.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "px-4 py-1 text-[12px] leading-5 text-muted-foreground", children: "Sessions you start or take over here will appear here." }) : null : recent.map((e) => renderEntry(e)),
1227
- /* @__PURE__ */ jsx5(
1477
+ /* @__PURE__ */ jsx6(SectionLabel, { children: "Recent" }),
1478
+ state.sessions.loading && state.sessions.loadedAt === null ? /* @__PURE__ */ jsx6(SidebarSkeleton, {}) : state.sessions.error ? /* @__PURE__ */ jsx6("p", { className: "px-4 py-1 text-[12px] text-destructive", children: state.sessions.error }) : recent.length === 0 ? running.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "px-4 py-1 text-[12px] leading-5 text-muted-foreground", children: "Sessions you start or take over here will appear here." }) : null : recent.map((e) => renderEntry(e)),
1479
+ /* @__PURE__ */ jsx6(
1228
1480
  SectionLabel,
1229
1481
  {
1230
- action: /* @__PURE__ */ jsxs5("span", { className: "flex items-center gap-0.5", children: [
1231
- /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
1232
- /* @__PURE__ */ jsx5(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx5("button", { type: "button", className: "cs-icon-button cs-icon-button--text", "aria-label": "How to list your other chats", children: groupMode === "date" ? "By date" : "By folder" }) }),
1233
- /* @__PURE__ */ jsxs5(DropdownMenuContent, { align: "end", className: "w-52", children: [
1234
- /* @__PURE__ */ jsx5(DropdownMenuLabel, { children: "Group your other chats" }),
1235
- /* @__PURE__ */ jsxs5(DropdownMenuRadioGroup, { value: groupMode, onValueChange: (v) => setMode(v), children: [
1236
- /* @__PURE__ */ jsx5(DropdownMenuRadioItem, { value: "date", children: "By date" }),
1237
- /* @__PURE__ */ jsx5(DropdownMenuRadioItem, { value: "folder", children: "By folder" })
1482
+ action: /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-0.5", children: [
1483
+ /* @__PURE__ */ jsxs6(DropdownMenu, { children: [
1484
+ /* @__PURE__ */ jsx6(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-icon-button cs-icon-button--text", "aria-label": "How to list your other chats", children: groupMode === "date" ? "By date" : "By folder" }) }),
1485
+ /* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "end", className: "w-52", children: [
1486
+ /* @__PURE__ */ jsx6(DropdownMenuLabel, { children: "Group your other chats" }),
1487
+ /* @__PURE__ */ jsxs6(DropdownMenuRadioGroup, { value: groupMode, onValueChange: (v) => setMode(v), children: [
1488
+ /* @__PURE__ */ jsx6(DropdownMenuRadioItem, { value: "date", children: "By date" }),
1489
+ /* @__PURE__ */ jsx6(DropdownMenuRadioItem, { value: "folder", children: "By folder" })
1238
1490
  ] }),
1239
- /* @__PURE__ */ jsx5(DropdownMenuSeparator2, {}),
1240
- /* @__PURE__ */ jsx5(DropdownMenuItem2, { onSelect: () => setShowHidden((v) => !v), children: showHidden ? "Leave hidden chats out" : `Show hidden chats${hiddenCount ? ` (${hiddenCount})` : ""}` })
1491
+ /* @__PURE__ */ jsx6(DropdownMenuSeparator2, {}),
1492
+ /* @__PURE__ */ jsx6(DropdownMenuItem2, { onSelect: () => setShowHidden((v) => !v), children: showHidden ? "Leave hidden chats out" : `Show hidden chats${hiddenCount ? ` (${hiddenCount})` : ""}` })
1241
1493
  ] })
1242
1494
  ] }),
1243
- /* @__PURE__ */ jsx5(
1495
+ /* @__PURE__ */ jsx6(
1244
1496
  "button",
1245
1497
  {
1246
1498
  type: "button",
@@ -1248,17 +1500,17 @@ function Sidebar(props) {
1248
1500
  onClick: () => void client.refreshDiscovered(),
1249
1501
  "aria-label": "Look again for your other chats",
1250
1502
  title: "Look again",
1251
- children: state.discovered.loading ? /* @__PURE__ */ jsx5(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx5(RefreshIcon, { size: 13 })
1503
+ children: state.discovered.loading ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx6(RefreshIcon, { size: 13 })
1252
1504
  }
1253
1505
  )
1254
1506
  ] }),
1255
1507
  children: "Your other chats"
1256
1508
  }
1257
1509
  ),
1258
- state.discovered.loading && state.discovered.loadedAt === null ? /* @__PURE__ */ jsx5(SidebarSkeleton, {}) : state.discovered.error ? /* @__PURE__ */ jsx5("p", { className: "px-4 py-1 text-[12px] text-destructive", children: state.discovered.error }) : otherList.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "px-4 py-1 text-[12px] leading-5 text-muted-foreground", children: others.length > 0 ? "Every chat found here is pinned or hidden." : "No other Claude Code or Codex chats were found on this computer." }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
1510
+ state.discovered.loading && state.discovered.loadedAt === null ? /* @__PURE__ */ jsx6(SidebarSkeleton, {}) : state.discovered.error ? /* @__PURE__ */ jsx6("p", { className: "px-4 py-1 text-[12px] text-destructive", children: state.discovered.error }) : otherList.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "px-4 py-1 text-[12px] leading-5 text-muted-foreground", children: others.length > 0 ? "Every chat found here is pinned or hidden." : "No other Claude Code or Codex chats were found on this computer." }) : /* @__PURE__ */ jsxs6(Fragment4, { children: [
1259
1511
  renderGroups(otherList),
1260
- state.discovered.data.length >= state.discoveredLimit ? /* @__PURE__ */ jsx5("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxs5(
1261
- Button,
1512
+ state.discovered.data.length >= state.discoveredLimit ? /* @__PURE__ */ jsx6("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxs6(
1513
+ Button2,
1262
1514
  {
1263
1515
  variant: "ghost",
1264
1516
  size: "sm",
@@ -1266,32 +1518,32 @@ function Sidebar(props) {
1266
1518
  onClick: () => void client.showMoreDiscovered(),
1267
1519
  disabled: state.discovered.loading,
1268
1520
  children: [
1269
- state.discovered.loading ? /* @__PURE__ */ jsx5(SpinnerIcon, { size: 13 }) : null,
1521
+ state.discovered.loading ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : null,
1270
1522
  "Show older chats"
1271
1523
  ]
1272
1524
  }
1273
1525
  ) }) : null
1274
1526
  ] }),
1275
- showHidden ? null : hiddenCount > 0 ? /* @__PURE__ */ jsxs5("button", { type: "button", className: "cs-link mx-4 mt-3 text-[11.5px]", onClick: () => setShowHidden(true), children: [
1527
+ showHidden ? null : hiddenCount > 0 ? /* @__PURE__ */ jsxs6("button", { type: "button", className: "cs-link mx-4 mt-3 text-[11.5px]", onClick: () => setShowHidden(true), children: [
1276
1528
  hiddenCount,
1277
1529
  " hidden ",
1278
1530
  hiddenCount === 1 ? "chat" : "chats",
1279
1531
  " \u2014 show"
1280
1532
  ] }) : null
1281
1533
  ] });
1282
- return /* @__PURE__ */ jsxs5(
1534
+ return /* @__PURE__ */ jsxs6(
1283
1535
  "aside",
1284
1536
  {
1285
- className: "cs-sidebar flex h-full shrink-0 flex-col border-r border-border bg-muted/30",
1537
+ className: "cs-sidebar flex h-full shrink-0 flex-col border-r border-border bg-sidebar-background",
1286
1538
  style: { width: props.width },
1287
1539
  "aria-label": "Sessions",
1288
1540
  children: [
1289
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-2 px-4 pb-2 pt-3.5", children: [
1290
- /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-center gap-2", children: [
1291
- /* @__PURE__ */ jsx5("span", { className: "cs-app-mark", "aria-hidden": "true" }),
1292
- /* @__PURE__ */ jsx5("span", { className: "truncate text-[14px] font-semibold tracking-[-0.01em]", children: "Coding sessions" })
1541
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2 px-4 pb-2 pt-3.5", children: [
1542
+ /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 items-center gap-2", children: [
1543
+ /* @__PURE__ */ jsx6("span", { className: "cs-app-mark", "aria-hidden": "true" }),
1544
+ /* @__PURE__ */ jsx6("span", { className: "truncate text-[14px] font-semibold tracking-[-0.01em]", children: "Coding sessions" })
1293
1545
  ] }),
1294
- /* @__PURE__ */ jsx5(
1546
+ /* @__PURE__ */ jsx6(
1295
1547
  "button",
1296
1548
  {
1297
1549
  type: "button",
@@ -1299,19 +1551,19 @@ function Sidebar(props) {
1299
1551
  onClick: props.onCollapse,
1300
1552
  "aria-label": "Hide the sidebar (\u2318B)",
1301
1553
  title: "Hide sidebar \u2318B",
1302
- children: /* @__PURE__ */ jsx5(SidebarIcon, { size: 15 })
1554
+ children: /* @__PURE__ */ jsx6(SidebarIcon, { size: 15 })
1303
1555
  }
1304
1556
  )
1305
1557
  ] }),
1306
- /* @__PURE__ */ jsxs5("div", { className: "space-y-1.5 px-3 pb-1", children: [
1307
- /* @__PURE__ */ jsxs5(Button, { className: "w-full justify-start gap-2", variant: "outline", size: "sm", onClick: props.onNew, children: [
1308
- /* @__PURE__ */ jsx5(PlusIcon, { size: 15 }),
1558
+ /* @__PURE__ */ jsxs6("div", { className: "space-y-1.5 px-3 pb-1", children: [
1559
+ /* @__PURE__ */ jsxs6(Button2, { className: "w-full justify-start gap-2", variant: "outline", size: "sm", onClick: props.onNew, children: [
1560
+ /* @__PURE__ */ jsx6(PlusIcon, { size: 15 }),
1309
1561
  "New session",
1310
- /* @__PURE__ */ jsx5("kbd", { className: "cs-kbd ml-auto", children: "\u2325\u2318N" })
1562
+ /* @__PURE__ */ jsx6("kbd", { className: "cs-kbd ml-auto", children: "\u2325\u2318N" })
1311
1563
  ] }),
1312
- /* @__PURE__ */ jsxs5("div", { className: "cs-search", children: [
1313
- /* @__PURE__ */ jsx5(SearchIcon, { size: 14, className: "cs-search__icon" }),
1314
- /* @__PURE__ */ jsx5(
1564
+ /* @__PURE__ */ jsxs6("div", { className: "cs-search", children: [
1565
+ /* @__PURE__ */ jsx6(SearchIcon, { size: 14, className: "cs-search__icon" }),
1566
+ /* @__PURE__ */ jsx6(
1315
1567
  "input",
1316
1568
  {
1317
1569
  ref: props.searchRef,
@@ -1337,10 +1589,10 @@ function Sidebar(props) {
1337
1589
  className: "cs-search__input"
1338
1590
  }
1339
1591
  ),
1340
- query ? /* @__PURE__ */ jsx5("button", { type: "button", className: "cs-icon-button cs-search__clear", onClick: () => setQuery(""), "aria-label": "Clear search", children: /* @__PURE__ */ jsx5(CloseIcon, { size: 13 }) }) : /* @__PURE__ */ jsx5("kbd", { className: "cs-search__kbd", children: "\u2318K" })
1592
+ query ? /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-icon-button cs-search__clear", onClick: () => setQuery(""), "aria-label": "Clear search", children: /* @__PURE__ */ jsx6(CloseIcon, { size: 13 }) }) : /* @__PURE__ */ jsx6("kbd", { className: "cs-search__kbd", children: "\u2318K" })
1341
1593
  ] })
1342
1594
  ] }),
1343
- /* @__PURE__ */ jsx5("nav", { className: "min-h-0 flex-1 overflow-y-auto pb-3", children: searching ? searchBody : listBody }),
1595
+ /* @__PURE__ */ jsx6("nav", { className: "min-h-0 flex-1 overflow-y-auto pb-3", children: searching ? searchBody : listBody }),
1344
1596
  props.footer
1345
1597
  ]
1346
1598
  }
@@ -1507,14 +1759,15 @@ function createTranscriptBuilder() {
1507
1759
  }));
1508
1760
  return;
1509
1761
  case "error": {
1510
- const said = current?.message.parts.some((p) => p.type === "error" && p.message.trim() === item.text.trim());
1762
+ const text = runErrorLabel(item.text);
1763
+ const said = current?.message.parts.some((p) => p.type === "error" && p.message.trim() === text.trim());
1511
1764
  if (said) return;
1512
1765
  upsertPart(item.id, () => ({
1513
1766
  type: "error",
1514
1767
  errorType: "provider",
1515
1768
  code: null,
1516
- message: item.text,
1517
- userMessage: item.text,
1769
+ message: text,
1770
+ userMessage: text,
1518
1771
  recoverable: true,
1519
1772
  remedy: null
1520
1773
  }));
@@ -1932,13 +2185,13 @@ function firstInvalidField(errors) {
1932
2185
  }
1933
2186
 
1934
2187
  // src/react/app.tsx
1935
- import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2188
+ import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1936
2189
  function CodingSessionsProvider({ transport, children }) {
1937
- const [client] = useState5(() => new CodingSessionsClient(transport));
1938
- useEffect3(() => {
2190
+ const [client] = useState6(() => new CodingSessionsClient(transport));
2191
+ useEffect4(() => {
1939
2192
  if (transport.status().state === "open") void client.refreshAll();
1940
2193
  }, [client, transport]);
1941
- return /* @__PURE__ */ jsx6(CodingSessionsContext.Provider, { value: client, children });
2194
+ return /* @__PURE__ */ jsx7(CodingSessionsContext.Provider, { value: client, children });
1942
2195
  }
1943
2196
  function readHash() {
1944
2197
  if (typeof location === "undefined") return { kind: "none" };
@@ -1961,8 +2214,8 @@ function readTheme() {
1961
2214
  }
1962
2215
  }
1963
2216
  function useTheme() {
1964
- const [choice, setChoice] = useState5(readTheme);
1965
- useEffect3(() => {
2217
+ const [choice, setChoice] = useState6(readTheme);
2218
+ useEffect4(() => {
1966
2219
  const media = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
1967
2220
  const apply = () => {
1968
2221
  const dark = choice === "dark" || choice === "system" && media?.matches === true;
@@ -1992,8 +2245,8 @@ var RUN_LABEL = {
1992
2245
  function RunPill({ run }) {
1993
2246
  if (!run) return null;
1994
2247
  const live = !isTerminalRunStatus(run.status);
1995
- return /* @__PURE__ */ jsxs6("span", { className: cn4("cs-pill", `cs-pill--${run.status}`), children: [
1996
- live ? /* @__PURE__ */ jsx6("span", { className: "cs-pill__dot", "aria-hidden": "true" }) : null,
2248
+ return /* @__PURE__ */ jsxs7("span", { className: cn5("cs-pill", `cs-pill--${run.status}`), children: [
2249
+ live ? /* @__PURE__ */ jsx7("span", { className: "cs-pill__dot", "aria-hidden": "true" }) : null,
1997
2250
  RUN_LABEL[run.status]
1998
2251
  ] });
1999
2252
  }
@@ -2001,17 +2254,17 @@ function ConnectionBanner() {
2001
2254
  const { connection } = useCodingSessionsState();
2002
2255
  if (connection.state === "open") return null;
2003
2256
  const closed = connection.state === "closed";
2004
- return /* @__PURE__ */ jsxs6(
2257
+ return /* @__PURE__ */ jsxs7(
2005
2258
  "div",
2006
2259
  {
2007
2260
  role: "status",
2008
- className: cn4(
2261
+ className: cn5(
2009
2262
  "flex items-center gap-2 border-b px-4 py-2 text-[13px]",
2010
2263
  closed ? "border-destructive/30 bg-destructive/10 text-destructive" : "border-border bg-muted/60 text-muted-foreground"
2011
2264
  ),
2012
2265
  children: [
2013
- closed ? /* @__PURE__ */ jsx6(AlertIcon, { size: 15 }) : /* @__PURE__ */ jsx6(SpinnerIcon, { size: 14 }),
2014
- /* @__PURE__ */ jsx6("span", { children: closed ? connection.reason : "Connecting to the coding sessions host\u2026" })
2266
+ closed ? /* @__PURE__ */ jsx7(AlertIcon, { size: 15 }) : /* @__PURE__ */ jsx7(SpinnerIcon, { size: 14 }),
2267
+ /* @__PURE__ */ jsx7("span", { children: closed ? connection.reason : "Connecting to the coding sessions host\u2026" })
2015
2268
  ]
2016
2269
  }
2017
2270
  );
@@ -2021,22 +2274,22 @@ function ProvidersFooter(props) {
2021
2274
  const client = useCodingSessionsClient();
2022
2275
  const next = { system: "light", light: "dark", dark: "system" };
2023
2276
  const themeLabel = { system: "Match system", light: "Light", dark: "Dark" };
2024
- return /* @__PURE__ */ jsx6("div", { className: "border-t border-border px-3 py-2.5", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5", children: [
2025
- /* @__PURE__ */ jsx6("div", { className: "flex min-w-0 flex-1 flex-wrap gap-1.5", children: state.providers.loading && state.providers.loadedAt === null ? /* @__PURE__ */ jsx6("span", { className: "text-[11.5px] text-muted-foreground", children: "Checking Claude Code and Codex\u2026" }) : state.providers.data.map((p) => /* @__PURE__ */ jsxs6(
2277
+ return /* @__PURE__ */ jsx7("div", { className: "border-t border-border px-3 py-2.5", children: /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5", children: [
2278
+ /* @__PURE__ */ jsx7("div", { className: "flex min-w-0 flex-1 flex-wrap gap-1.5", children: state.providers.loading && state.providers.loadedAt === null ? /* @__PURE__ */ jsx7("span", { className: "text-[11.5px] text-muted-foreground", children: "Checking Claude Code and Codex\u2026" }) : state.providers.data.map((p) => /* @__PURE__ */ jsxs7(
2026
2279
  "span",
2027
2280
  {
2028
- className: cn4("cs-provider-chip", p.ready ? "" : "cs-provider-chip--problem"),
2029
- title: p.problem ? `${p.problem} ${p.fix ?? ""}` : `${p.label}${p.plan ? ` \xB7 ${p.plan}` : ""}`,
2281
+ className: cn5("cs-provider-chip", p.ready ? "" : "cs-provider-chip--problem"),
2282
+ title: p.problem ? `${p.problem} ${p.fix ?? ""}` : [binaryWords(p) ?? p.label, p.plan, newerWords(p)].filter(Boolean).join(" \xB7 "),
2030
2283
  children: [
2031
- /* @__PURE__ */ jsx6(ProviderMark, { provider: p.provider, size: 13 }),
2284
+ /* @__PURE__ */ jsx7(ProviderMark, { provider: p.provider, size: 13 }),
2032
2285
  p.label,
2033
- p.lastProblem ? /* @__PURE__ */ jsx6("span", { className: "cs-provider-chip__note", children: p.lastProblem.kind === "signed-out" ? "\xB7 sign in again" : `\xB7 limit${formatUntil(p.lastProblem.until) ? ` until ${formatUntil(p.lastProblem.until)}` : ""}` }) : null,
2034
- p.ready ? /* @__PURE__ */ jsx6(CheckIcon, { size: 12 }) : /* @__PURE__ */ jsx6(AlertIcon, { size: 12 })
2286
+ p.lastProblem ? /* @__PURE__ */ jsx7("span", { className: "cs-provider-chip__note", children: p.lastProblem.kind === "signed-out" ? "\xB7 sign in again" : `\xB7 limit${formatUntil(p.lastProblem.until) ? ` until ${formatUntil(p.lastProblem.until)}` : ""}` }) : null,
2287
+ p.ready ? /* @__PURE__ */ jsx7(CheckIcon, { size: 12 }) : /* @__PURE__ */ jsx7(AlertIcon, { size: 12 })
2035
2288
  ]
2036
2289
  },
2037
2290
  p.provider
2038
2291
  )) }),
2039
- /* @__PURE__ */ jsx6(
2292
+ /* @__PURE__ */ jsx7(
2040
2293
  "button",
2041
2294
  {
2042
2295
  type: "button",
@@ -2044,11 +2297,11 @@ function ProvidersFooter(props) {
2044
2297
  onClick: () => void client.refreshProviders(),
2045
2298
  "aria-label": "Check Claude Code and Codex again",
2046
2299
  title: "Check again",
2047
- children: state.providers.loading ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx6(RefreshIcon, { size: 13 })
2300
+ children: state.providers.loading ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx7(RefreshIcon, { size: 13 })
2048
2301
  }
2049
2302
  ),
2050
2303
  props.extra,
2051
- /* @__PURE__ */ jsx6(
2304
+ /* @__PURE__ */ jsx7(
2052
2305
  "button",
2053
2306
  {
2054
2307
  type: "button",
@@ -2056,14 +2309,14 @@ function ProvidersFooter(props) {
2056
2309
  onClick: () => props.setTheme(next[props.theme]),
2057
2310
  "aria-label": `Theme: ${themeLabel[props.theme]}. Switch to ${themeLabel[next[props.theme]]}.`,
2058
2311
  title: `Theme: ${themeLabel[props.theme]}`,
2059
- children: props.theme === "system" ? /* @__PURE__ */ jsx6(MonitorIcon, { size: 14 }) : props.theme === "light" ? /* @__PURE__ */ jsx6(SunIcon, { size: 14 }) : /* @__PURE__ */ jsx6(MoonIcon, { size: 14 })
2312
+ children: props.theme === "system" ? /* @__PURE__ */ jsx7(MonitorIcon, { size: 14 }) : props.theme === "light" ? /* @__PURE__ */ jsx7(SunIcon, { size: 14 }) : /* @__PURE__ */ jsx7(MoonIcon, { size: 14 })
2060
2313
  }
2061
2314
  )
2062
2315
  ] }) });
2063
2316
  }
2064
2317
  function useNotifier() {
2065
2318
  const show = useContext3(ToastContext);
2066
- return useMemo3(
2319
+ return useMemo4(
2067
2320
  () => ({
2068
2321
  notify(event) {
2069
2322
  show(event.message);
@@ -2074,8 +2327,8 @@ function useNotifier() {
2074
2327
  }
2075
2328
  function useLiveElsewhere(provider, providerSessionId, initial = null) {
2076
2329
  const client = useCodingSessionsClient();
2077
- const [state, setState] = useState5(initial);
2078
- useEffect3(() => {
2330
+ const [state, setState] = useState6(initial);
2331
+ useEffect4(() => {
2079
2332
  if (!provider || !providerSessionId) {
2080
2333
  setState(null);
2081
2334
  return;
@@ -2095,8 +2348,8 @@ function useLiveElsewhere(provider, providerSessionId, initial = null) {
2095
2348
  }
2096
2349
  function useSessionUsage(sessionId, lastRunKey) {
2097
2350
  const client = useCodingSessionsClient();
2098
- const [usage, setUsage] = useState5(null);
2099
- useEffect3(() => {
2351
+ const [usage, setUsage] = useState6(null);
2352
+ useEffect4(() => {
2100
2353
  let cancelled = false;
2101
2354
  void client.transport.call("listRuns", sessionId).then((runs) => {
2102
2355
  if (cancelled) return;
@@ -2117,18 +2370,18 @@ function useSessionUsage(sessionId, lastRunKey) {
2117
2370
  return usage;
2118
2371
  }
2119
2372
  function HeaderMenu(props) {
2120
- return /* @__PURE__ */ jsxs6(DropdownMenu2, { children: [
2121
- /* @__PURE__ */ jsx6(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-icon-button", "aria-label": "More for this chat", title: "More", children: /* @__PURE__ */ jsx6(MoreIcon, { size: 16 }) }) }),
2122
- /* @__PURE__ */ jsx6(DropdownMenuContent2, { align: "end", className: "w-64", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx6(ChatMenuItems, { entry: props.entry, variant: "dropdown", onRename: props.onRename }) })
2373
+ return /* @__PURE__ */ jsxs7(DropdownMenu2, { children: [
2374
+ /* @__PURE__ */ jsx7(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx7("button", { type: "button", className: "cs-icon-button", "aria-label": "More for this chat", title: "More", children: /* @__PURE__ */ jsx7(MoreIcon, { size: 16 }) }) }),
2375
+ /* @__PURE__ */ jsx7(DropdownMenuContent2, { align: "end", className: "w-64", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx7(ChatMenuItems, { entry: props.entry, variant: "dropdown", onRename: props.onRename }) })
2123
2376
  ] });
2124
2377
  }
2125
2378
  function HeaderTitle(props) {
2126
2379
  const client = useCodingSessionsClient();
2127
2380
  const show = useContext3(ToastContext);
2128
- const [value, setValue] = useState5(props.entry.title);
2129
- useEffect3(() => setValue(props.entry.title), [props.entry.title, props.renaming]);
2130
- const inputRef = useRef2(null);
2131
- useEffect3(() => {
2381
+ const [value, setValue] = useState6(props.entry.title);
2382
+ useEffect4(() => setValue(props.entry.title), [props.entry.title, props.renaming]);
2383
+ const inputRef = useRef3(null);
2384
+ useEffect4(() => {
2132
2385
  if (!props.renaming) return;
2133
2386
  const timer = setTimeout(() => {
2134
2387
  const input = inputRef.current;
@@ -2140,7 +2393,7 @@ function HeaderTitle(props) {
2140
2393
  return () => clearTimeout(timer);
2141
2394
  }, [props.renaming]);
2142
2395
  if (!props.renaming) {
2143
- return /* @__PURE__ */ jsx6(
2396
+ return /* @__PURE__ */ jsx7(
2144
2397
  "h1",
2145
2398
  {
2146
2399
  className: "truncate text-[15px] font-semibold leading-5 tracking-[-0.01em]",
@@ -2157,7 +2410,7 @@ function HeaderTitle(props) {
2157
2410
  const next = title === "" || title === props.entry.originalTitle ? null : title;
2158
2411
  client.setPreference(props.entry.key, { title: next }).catch((error) => show(`The new name didn't save: ${error instanceof Error ? error.message : String(error)}`));
2159
2412
  };
2160
- return /* @__PURE__ */ jsx6(
2413
+ return /* @__PURE__ */ jsx7(
2161
2414
  "input",
2162
2415
  {
2163
2416
  ref: inputRef,
@@ -2176,11 +2429,18 @@ function HeaderTitle(props) {
2176
2429
  );
2177
2430
  }
2178
2431
  function LongChatNote(props) {
2179
- return /* @__PURE__ */ jsxs6("p", { className: "mx-auto mt-3 flex items-center gap-2 text-[12px] text-muted-foreground", children: [
2432
+ return /* @__PURE__ */ jsxs7("p", { className: "mx-auto mt-3 flex items-center gap-2 text-[12px] text-muted-foreground", children: [
2180
2433
  "This chat is very long \u2014 showing its most recent part.",
2181
- /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-link", onClick: props.onEarlier, disabled: props.loading, children: props.loading ? "Reading\u2026" : "Show earlier" })
2434
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "cs-link", onClick: props.onEarlier, disabled: props.loading, children: props.loading ? "Reading\u2026" : "Show earlier" })
2182
2435
  ] });
2183
2436
  }
2437
+ function binaryWords(p) {
2438
+ if (!p.version) return null;
2439
+ return `${p.label} ${p.version}${p.binary ? ` \xB7 ${p.binary.sourceLabel}` : ""}`;
2440
+ }
2441
+ function newerWords(p) {
2442
+ return p.binary?.newer ? `Newer: ${p.binary.newer.version} ${p.binary.newer.sourceLabel}` : null;
2443
+ }
2184
2444
  function SessionView({ session, changesOpen, setChangesOpen }) {
2185
2445
  const client = useCodingSessionsClient();
2186
2446
  const state = useCodingSessionsState();
@@ -2192,8 +2452,9 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
2192
2452
  const provider = state.providers.data.find((p) => p.provider === session.provider) ?? null;
2193
2453
  const blocked = provider && (!provider.installed || !provider.loggedIn) ? provider : null;
2194
2454
  const limited = !blocked && provider?.lastProblem ? provider : null;
2195
- const [stopping, setStopping] = useState5(false);
2196
- const [renaming, setRenaming] = useState5(false);
2455
+ const modelRefused = run?.status === "failed" && isModelUnavailable(run.error);
2456
+ const [stopping, setStopping] = useState6(false);
2457
+ const [renaming, setRenaming] = useState6(false);
2197
2458
  const elsewhere = useLiveElsewhere(
2198
2459
  session.origin === "takeover" && !live ? session.provider : null,
2199
2460
  session.providerSessionId
@@ -2202,7 +2463,7 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
2202
2463
  const messages = transcript.thread.getSnapshot().messages;
2203
2464
  const files = useChangedFiles(messages);
2204
2465
  const usage = useSessionUsage(session.id, `${run?.runId ?? ""}:${run?.status ?? ""}`);
2205
- useEffect3(() => {
2466
+ useEffect4(() => {
2206
2467
  if (!live) setStopping(false);
2207
2468
  }, [live]);
2208
2469
  const stop = async () => {
@@ -2215,16 +2476,16 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
2215
2476
  };
2216
2477
  const usageWords = usage ? `${formatCount(usage.tokens, { style: "compact" })} tokens${usage.cost !== null ? ` \xB7 ${formatUsd(usage.cost)}` : ""}` : null;
2217
2478
  const usageTitle = usage ? `${formatCount(usage.tokens)} tokens over ${usage.runs} ${usage.runs === 1 ? "message" : "messages"} sent from here.` + (usage.cost !== null ? usage.billing === "subscription" ? ` ${formatUsd(usage.cost)} is what this would cost at API prices \u2014 it's covered by your ${provider?.plan ?? ""} plan.`.replace(" ", " ") : ` Billed ${formatUsd(usage.cost)} to your API key.` : "") : "";
2218
- return /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 flex-1", children: [
2219
- /* @__PURE__ */ jsxs6("section", { className: "flex min-w-0 flex-1 flex-col", "aria-label": entry.title, children: [
2220
- /* @__PURE__ */ jsxs6("header", { className: "flex items-center gap-3 border-b border-border px-5 py-2.5", children: [
2221
- /* @__PURE__ */ jsx6(ProviderMark, { provider: session.provider, size: 22 }),
2222
- /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1", children: [
2223
- /* @__PURE__ */ jsx6(HeaderTitle, { entry, renaming, setRenaming }),
2224
- /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 items-center gap-1 text-[12px] leading-5 text-muted-foreground", children: [
2225
- /* @__PURE__ */ jsx6("span", { className: "shrink-0", children: PROVIDER_LABEL[session.provider] }),
2226
- /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\xB7" }),
2227
- /* @__PURE__ */ jsx6(
2479
+ return /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1", children: [
2480
+ /* @__PURE__ */ jsxs7("section", { className: "flex min-w-0 flex-1 flex-col", "aria-label": entry.title, children: [
2481
+ /* @__PURE__ */ jsxs7("header", { className: "flex flex-wrap items-center gap-2 border-b border-border px-5 pt-2.5 pb-2.5", children: [
2482
+ /* @__PURE__ */ jsx7(ProviderMark, { provider: session.provider, size: 22 }),
2483
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1 overflow-hidden", children: [
2484
+ /* @__PURE__ */ jsx7(HeaderTitle, { entry, renaming, setRenaming }),
2485
+ /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 items-center gap-1 text-[12px] leading-5 text-muted-foreground", children: [
2486
+ /* @__PURE__ */ jsx7("span", { className: "shrink-0", children: PROVIDER_LABEL[session.provider] }),
2487
+ /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xB7" }),
2488
+ /* @__PURE__ */ jsx7(
2228
2489
  ModelPicker,
2229
2490
  {
2230
2491
  status: provider,
@@ -2232,85 +2493,105 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
2232
2493
  onChange: setOptions
2233
2494
  }
2234
2495
  ),
2235
- /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\xB7" }),
2236
- /* @__PURE__ */ jsx6(FolderIcon, { size: 12, className: "shrink-0" }),
2237
- /* @__PURE__ */ jsx6("span", { className: "min-w-[4rem] truncate", title: session.cwd, children: prettyPath2(session.cwd) }),
2238
- usageWords ? /* @__PURE__ */ jsxs6("span", { className: "shrink-0", title: usageTitle, children: [
2496
+ /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xB7" }),
2497
+ /* @__PURE__ */ jsx7(FolderIcon, { size: 12, className: "shrink-0" }),
2498
+ /* @__PURE__ */ jsx7("span", { className: "min-w-[4rem] truncate", title: session.cwd, children: prettyPath2(session.cwd) }),
2499
+ usageWords ? /* @__PURE__ */ jsxs7("span", { className: "shrink-0", title: usageTitle, children: [
2239
2500
  "\xB7 ",
2240
2501
  usageWords
2241
2502
  ] }) : null
2242
2503
  ] })
2243
2504
  ] }),
2244
- /* @__PURE__ */ jsxs6(
2505
+ session.agent ? /* @__PURE__ */ jsx7(AgentChip, { agent: session.agent }) : null,
2506
+ /* @__PURE__ */ jsxs7(
2245
2507
  "button",
2246
2508
  {
2247
2509
  type: "button",
2248
- className: cn4("cs-chip-button", changesOpen && "cs-chip-button--on"),
2510
+ className: cn5("cs-chip-button", changesOpen && "cs-chip-button--on"),
2249
2511
  onClick: () => setChangesOpen(!changesOpen),
2250
2512
  "aria-pressed": changesOpen,
2251
2513
  title: "Files this chat changed",
2252
2514
  children: [
2253
- /* @__PURE__ */ jsx6(FileIcon, { size: 13 }),
2515
+ /* @__PURE__ */ jsx7(FileIcon, { size: 13 }),
2254
2516
  files.length > 0 ? `${files.length} ${files.length === 1 ? "file" : "files"} changed` : "Changes"
2255
2517
  ]
2256
2518
  }
2257
2519
  ),
2258
- /* @__PURE__ */ jsx6(RunPill, { run }),
2259
- live ? /* @__PURE__ */ jsxs6(Button2, { variant: "outline", size: "sm", onClick: () => void stop(), disabled: stopping, className: "gap-1.5", title: "Stop Esc", children: [
2260
- stopping ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx6(StopIcon, { size: 13 }),
2520
+ /* @__PURE__ */ jsx7(RunPill, { run }),
2521
+ live ? /* @__PURE__ */ jsxs7(Button3, { variant: "outline", size: "sm", onClick: () => void stop(), disabled: stopping, className: "gap-1.5", title: "Stop Esc", children: [
2522
+ stopping ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx7(StopIcon, { size: 13 }),
2261
2523
  stopping ? "Stopping\u2026" : "Stop"
2262
2524
  ] }) : null,
2263
- /* @__PURE__ */ jsx6(HeaderMenu, { entry, onRename: () => setRenaming(true) })
2525
+ /* @__PURE__ */ jsx7(HeaderMenu, { entry, onRename: () => setRenaming(true) })
2264
2526
  ] }),
2265
- /* @__PURE__ */ jsx6("div", { className: "mx-chat flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsxs6(ChatProvider, { thread: transcript.thread, ports: { notifier, toolLabel: friendlyToolName }, children: [
2266
- /* @__PURE__ */ jsx6("div", { className: "min-h-0 flex-1 overflow-hidden", children: transcript.state.loading ? /* @__PURE__ */ jsxs6("div", { className: "flex h-full items-center justify-center gap-2 text-[13px] text-muted-foreground", children: [
2267
- /* @__PURE__ */ jsx6(SpinnerIcon, { size: 15 }),
2527
+ /* @__PURE__ */ jsx7("div", { className: "mx-chat flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsxs7(ChatProvider, { thread: transcript.thread, ports: { notifier, toolLabel: friendlyToolName }, children: [
2528
+ /* @__PURE__ */ jsx7("div", { className: "min-h-0 flex-1 overflow-hidden", children: transcript.state.loading ? /* @__PURE__ */ jsxs7("div", { className: "flex h-full items-center justify-center gap-2 text-[13px] text-muted-foreground", children: [
2529
+ /* @__PURE__ */ jsx7(SpinnerIcon, { size: 15 }),
2268
2530
  " Loading the conversation\u2026"
2269
- ] }) : /* @__PURE__ */ jsxs6("div", { className: "flex h-full flex-col", children: [
2270
- transcript.state.unavailable ? /* @__PURE__ */ jsx6("p", { className: "mx-auto mt-4 max-w-[720px] rounded-lg border border-border bg-muted/50 px-4 py-2.5 text-[13px] text-muted-foreground", children: transcript.state.unavailable }) : null,
2271
- transcript.state.truncated ? /* @__PURE__ */ jsx6(
2531
+ ] }) : /* @__PURE__ */ jsxs7("div", { className: "flex h-full flex-col", children: [
2532
+ transcript.state.unavailable ? /* @__PURE__ */ jsx7("p", { className: "mx-auto mt-4 max-w-[720px] rounded-lg border border-border bg-muted/50 px-4 py-2.5 text-[13px] text-muted-foreground", children: transcript.state.unavailable }) : null,
2533
+ transcript.state.truncated ? /* @__PURE__ */ jsx7(
2272
2534
  LongChatNote,
2273
2535
  {
2274
2536
  loading: transcript.state.loadingEarlier === true,
2275
2537
  onEarlier: () => void transcript.loadEarlier()
2276
2538
  }
2277
2539
  ) : null,
2278
- messages.length === 0 && !live ? /* @__PURE__ */ jsx6("div", { className: "flex flex-1 items-center justify-center text-[13px] text-muted-foreground", children: session.origin === "takeover" ? "You've taken over this chat. Send a message to continue it." : "Nothing here yet." }) : /* @__PURE__ */ jsx6(ChatMessageList, { className: "min-h-0 flex-1", label: `Conversation: ${entry.title}` })
2540
+ messages.length === 0 && !live ? /* @__PURE__ */ jsx7("div", { className: "flex flex-1 items-center justify-center text-[13px] text-muted-foreground", children: session.origin === "takeover" ? "You've taken over this chat. Send a message to continue it." : "Nothing here yet." }) : /* @__PURE__ */ jsx7(ChatMessageList, { className: "min-h-0 flex-1", label: `Conversation: ${entry.title}` })
2279
2541
  ] }) }),
2280
- /* @__PURE__ */ jsxs6("div", { className: "mx-auto w-full max-w-[820px] px-4 pb-4", children: [
2281
- limited ? /* @__PURE__ */ jsxs6("div", { className: "mb-2 flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]", children: [
2282
- /* @__PURE__ */ jsx6(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2283
- /* @__PURE__ */ jsxs6("span", { children: [
2542
+ /* @__PURE__ */ jsxs7("div", { className: "mx-auto w-full max-w-[820px] px-4 pb-4", children: [
2543
+ limited ? /* @__PURE__ */ jsxs7("div", { className: "mb-2 flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]", children: [
2544
+ /* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2545
+ /* @__PURE__ */ jsxs7("span", { children: [
2284
2546
  limited.problem,
2285
2547
  " ",
2286
2548
  limited.fix
2287
2549
  ] })
2288
2550
  ] }) : null,
2289
- blocked ? /* @__PURE__ */ jsxs6("div", { className: "mb-2 flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]", children: [
2290
- /* @__PURE__ */ jsx6(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2291
- /* @__PURE__ */ jsxs6("span", { children: [
2551
+ modelRefused && !blocked ? /* @__PURE__ */ jsxs7(
2552
+ "div",
2553
+ {
2554
+ className: "mb-2 flex items-center gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]",
2555
+ role: "alert",
2556
+ children: [
2557
+ /* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "shrink-0 text-warning" }),
2558
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate", title: run?.error ?? void 0, children: MODEL_UNAVAILABLE_LABEL }),
2559
+ /* @__PURE__ */ jsx7(
2560
+ ModelPicker,
2561
+ {
2562
+ status: provider,
2563
+ value: { model: session.model, effort: session.effort ?? null },
2564
+ onChange: setOptions
2565
+ }
2566
+ )
2567
+ ]
2568
+ }
2569
+ ) : null,
2570
+ blocked ? /* @__PURE__ */ jsxs7("div", { className: "mb-2 flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]", children: [
2571
+ /* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2572
+ /* @__PURE__ */ jsxs7("span", { children: [
2292
2573
  blocked.problem,
2293
2574
  " ",
2294
2575
  blocked.fix
2295
2576
  ] })
2296
2577
  ] }) : null,
2297
- /* @__PURE__ */ jsx6("div", { className: "cs-activity", role: "status", "aria-live": "polite", "data-idle": live ? void 0 : true, children: live ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
2298
- /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }),
2299
- /* @__PURE__ */ jsx6("span", { className: "truncate", children: run?.status === "starting" ? `Starting ${PROVIDER_LABEL[session.provider]}\u2026` : transcript.activity ?? "Thinking\u2026" }),
2300
- /* @__PURE__ */ jsx6("span", { className: "ml-auto shrink-0 text-[11px] opacity-70", children: "Esc to stop" })
2578
+ /* @__PURE__ */ jsx7("div", { className: "cs-activity", role: "status", "aria-live": "polite", "data-idle": live ? void 0 : true, children: live ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
2579
+ /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }),
2580
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: run?.status === "starting" ? `Starting ${PROVIDER_LABEL[session.provider]}\u2026` : transcript.activity ?? "Thinking\u2026" }),
2581
+ /* @__PURE__ */ jsx7("span", { className: "ml-auto shrink-0 text-[11px] opacity-70", children: "Esc to stop" })
2301
2582
  ] }) : null }),
2302
- elsewhere ? /* @__PURE__ */ jsxs6("div", { className: "mb-2 flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]", children: [
2303
- /* @__PURE__ */ jsx6(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2304
- /* @__PURE__ */ jsxs6("span", { children: [
2583
+ elsewhere ? /* @__PURE__ */ jsxs7("div", { className: "mb-2 flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]", children: [
2584
+ /* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2585
+ /* @__PURE__ */ jsxs7("span", { children: [
2305
2586
  elsewhere.message,
2306
2587
  " A message sent here would put a second agent on the same chat."
2307
2588
  ] })
2308
2589
  ] }) : null,
2309
- session.queued.length > 0 ? /* @__PURE__ */ jsx6("ul", { className: "mb-2 space-y-1.5", "aria-label": "Queued messages", children: session.queued.map((text, index) => /* @__PURE__ */ jsxs6("li", { className: "cs-queued", children: [
2310
- /* @__PURE__ */ jsx6("span", { className: "cs-queued__label", children: "Queued \xB7 sends when this run finishes" }),
2311
- /* @__PURE__ */ jsx6("span", { className: "cs-queued__text", children: text })
2590
+ session.queued.length > 0 ? /* @__PURE__ */ jsx7("ul", { className: "mb-2 space-y-1.5", "aria-label": "Queued messages", children: session.queued.map((text, index) => /* @__PURE__ */ jsxs7("li", { className: "cs-queued", children: [
2591
+ /* @__PURE__ */ jsx7("span", { className: "cs-queued__label", children: "Queued \xB7 sends when this run finishes" }),
2592
+ /* @__PURE__ */ jsx7("span", { className: "cs-queued__text", children: text })
2312
2593
  ] }, `${index}-${text.slice(0, 16)}`)) }) : null,
2313
- /* @__PURE__ */ jsx6(
2594
+ /* @__PURE__ */ jsx7(
2314
2595
  ChatComposer,
2315
2596
  {
2316
2597
  placeholder: `Message ${PROVIDER_LABEL[session.provider]}\u2026`,
@@ -2321,14 +2602,14 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
2321
2602
  ] })
2322
2603
  ] }) })
2323
2604
  ] }),
2324
- changesOpen ? /* @__PURE__ */ jsx6(ChangesPanel, { files, cwd: session.cwd, truncated: transcript.state.truncated, onClose: () => setChangesOpen(false) }) : null
2605
+ changesOpen ? /* @__PURE__ */ jsx7(ChangesPanel, { files, cwd: session.cwd, truncated: transcript.state.truncated, onClose: () => setChangesOpen(false) }) : null
2325
2606
  ] });
2326
2607
  }
2327
2608
  function usePreviewThread(id, onSend) {
2328
- const ref = useRef2({ messages: [], listeners: /* @__PURE__ */ new Set() });
2329
- const send = useRef2(onSend);
2609
+ const ref = useRef3({ messages: [], listeners: /* @__PURE__ */ new Set() });
2610
+ const send = useRef3(onSend);
2330
2611
  send.current = onSend;
2331
- const thread = useMemo3(
2612
+ const thread = useMemo4(
2332
2613
  () => createExternalThreadSource2({
2333
2614
  getSnapshot: () => ({ messages: ref.current.messages, status: "idle", conversationId: id }),
2334
2615
  subscribe: (listener) => {
@@ -2353,13 +2634,13 @@ function DiscoveredView(props) {
2353
2634
  const state = useCodingSessionsState();
2354
2635
  const show = useContext3(ToastContext);
2355
2636
  const now = useMinuteClock();
2356
- const [preview, setPreview] = useState5({ loading: true, messages: [], unavailable: null, truncated: false });
2357
- const [busy, setBusy] = useState5(false);
2358
- const [error, setError] = useState5(null);
2359
- const [confirming, setConfirming] = useState5(false);
2360
- const [renaming, setRenaming] = useState5(false);
2361
- const [maxBytes, setMaxBytes] = useState5(void 0);
2362
- const [readingEarlier, setReadingEarlier] = useState5(false);
2637
+ const [preview, setPreview] = useState6({ loading: true, messages: [], unavailable: null, truncated: false });
2638
+ const [busy, setBusy] = useState6(false);
2639
+ const [error, setError] = useState6(null);
2640
+ const [confirming, setConfirming] = useState6(false);
2641
+ const [renaming, setRenaming] = useState6(false);
2642
+ const [maxBytes, setMaxBytes] = useState6(void 0);
2643
+ const [readingEarlier, setReadingEarlier] = useState6(false);
2363
2644
  const elsewhere = useLiveElsewhere(props.provider, props.id, props.session?.activeElsewhere ?? null);
2364
2645
  const files = useChangedFiles(preview.messages);
2365
2646
  const d = props.session;
@@ -2369,7 +2650,7 @@ function DiscoveredView(props) {
2369
2650
  d?.cwd ? `This chat is read-only until you take it over. Press Take over to continue it here.` : "This chat is read-only here: it doesn't record its folder, so it can't be continued."
2370
2651
  )
2371
2652
  );
2372
- useEffect3(() => {
2653
+ useEffect4(() => {
2373
2654
  let cancelled = false;
2374
2655
  const read = (first) => client.readPreview(props.provider, props.id, maxBytes).then((next) => {
2375
2656
  if (cancelled) return;
@@ -2408,26 +2689,26 @@ function DiscoveredView(props) {
2408
2689
  setBusy(false);
2409
2690
  }
2410
2691
  };
2411
- return /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 flex-1", children: [
2412
- /* @__PURE__ */ jsxs6("section", { className: "flex min-w-0 flex-1 flex-col", "aria-label": entry.title, children: [
2413
- /* @__PURE__ */ jsxs6("header", { className: "flex items-center gap-3 border-b border-border px-5 py-3", children: [
2414
- /* @__PURE__ */ jsx6(ProviderMark, { provider: props.provider, size: 22 }),
2415
- /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1", children: [
2416
- /* @__PURE__ */ jsx6(HeaderTitle, { entry, renaming, setRenaming }),
2417
- /* @__PURE__ */ jsxs6("p", { className: "flex items-center gap-1.5 truncate text-[12px] leading-4 text-muted-foreground", children: [
2418
- /* @__PURE__ */ jsx6("span", { children: PROVIDER_LABEL[props.provider] }),
2419
- d?.cwd ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
2420
- /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\xB7" }),
2421
- /* @__PURE__ */ jsx6(FolderIcon, { size: 12 }),
2422
- /* @__PURE__ */ jsx6("span", { className: "truncate", title: d.cwd, children: prettyPath2(d.cwd) })
2692
+ return /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1", children: [
2693
+ /* @__PURE__ */ jsxs7("section", { className: "flex min-w-0 flex-1 flex-col", "aria-label": entry.title, children: [
2694
+ /* @__PURE__ */ jsxs7("header", { className: "flex flex-wrap items-center gap-2 border-b border-border px-5 pt-2.5 pb-2.5", children: [
2695
+ /* @__PURE__ */ jsx7(ProviderMark, { provider: props.provider, size: 22 }),
2696
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
2697
+ /* @__PURE__ */ jsx7(HeaderTitle, { entry, renaming, setRenaming }),
2698
+ /* @__PURE__ */ jsxs7("p", { className: "flex items-center gap-1.5 truncate text-[12px] leading-4 text-muted-foreground", children: [
2699
+ /* @__PURE__ */ jsx7("span", { children: PROVIDER_LABEL[props.provider] }),
2700
+ d?.cwd ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
2701
+ /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xB7" }),
2702
+ /* @__PURE__ */ jsx7(FolderIcon, { size: 12 }),
2703
+ /* @__PURE__ */ jsx7("span", { className: "truncate", title: d.cwd, children: prettyPath2(d.cwd) })
2423
2704
  ] }) : null,
2424
- d ? /* @__PURE__ */ jsxs6("span", { children: [
2705
+ d ? /* @__PURE__ */ jsxs7("span", { children: [
2425
2706
  "\xB7 last active ",
2426
2707
  relativeTime(d.updatedAt, now)
2427
2708
  ] }) : null
2428
2709
  ] })
2429
2710
  ] }),
2430
- files.length > 0 ? /* @__PURE__ */ jsxs6(
2711
+ files.length > 0 ? /* @__PURE__ */ jsxs7(
2431
2712
  "button",
2432
2713
  {
2433
2714
  type: "button",
@@ -2436,13 +2717,13 @@ function DiscoveredView(props) {
2436
2717
  "aria-pressed": props.changesOpen,
2437
2718
  title: "Files this chat changed",
2438
2719
  children: [
2439
- /* @__PURE__ */ jsx6(FileIcon, { size: 13 }),
2720
+ /* @__PURE__ */ jsx7(FileIcon, { size: 13 }),
2440
2721
  `${files.length} ${files.length === 1 ? "file" : "files"} changed`
2441
2722
  ]
2442
2723
  }
2443
2724
  ) : null,
2444
- d?.cwd ? /* @__PURE__ */ jsxs6(
2445
- Button2,
2725
+ d?.cwd ? /* @__PURE__ */ jsxs7(
2726
+ Button3,
2446
2727
  {
2447
2728
  size: "sm",
2448
2729
  variant: elsewhere ? "outline" : "default",
@@ -2451,44 +2732,44 @@ function DiscoveredView(props) {
2451
2732
  className: "gap-1.5",
2452
2733
  title: elsewhere ? elsewhere.message : void 0,
2453
2734
  children: [
2454
- busy ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : elsewhere ? /* @__PURE__ */ jsx6(AlertIcon, { size: 14, className: "text-warning" }) : /* @__PURE__ */ jsx6(HandoffIcon, { size: 14 }),
2735
+ busy ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : elsewhere ? /* @__PURE__ */ jsx7(AlertIcon, { size: 14, className: "text-warning" }) : /* @__PURE__ */ jsx7(HandoffIcon, { size: 14 }),
2455
2736
  elsewhere ? "Take over anyway\u2026" : "Take over"
2456
2737
  ]
2457
2738
  }
2458
2739
  ) : null,
2459
- d ? /* @__PURE__ */ jsx6(HeaderMenu, { entry, onRename: () => setRenaming(true) }) : null
2740
+ d ? /* @__PURE__ */ jsx7(HeaderMenu, { entry, onRename: () => setRenaming(true) }) : null
2460
2741
  ] }),
2461
- elsewhere ? /* @__PURE__ */ jsxs6("div", { role: "status", className: "flex items-start gap-2 border-b border-warning/40 bg-warning/10 px-5 py-2.5 text-[13px]", children: [
2462
- /* @__PURE__ */ jsx6(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2463
- /* @__PURE__ */ jsxs6("span", { children: [
2464
- /* @__PURE__ */ jsx6("span", { className: "font-medium", children: elsewhere.message }),
2742
+ elsewhere ? /* @__PURE__ */ jsxs7("div", { role: "status", className: "flex items-start gap-2 border-b border-warning/40 bg-warning/10 px-5 py-2.5 text-[13px]", children: [
2743
+ /* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
2744
+ /* @__PURE__ */ jsxs7("span", { children: [
2745
+ /* @__PURE__ */ jsx7("span", { className: "font-medium", children: elsewhere.message }),
2465
2746
  " Taking it over now would put two agents on the same chat, and they could overwrite each other's work. Finish or stop it there first if you can. This preview follows it as it runs."
2466
2747
  ] })
2467
2748
  ] }) : null,
2468
- /* @__PURE__ */ jsx6(Dialog, { open: confirming, onOpenChange: setConfirming, children: /* @__PURE__ */ jsxs6(DialogContent, { className: "max-w-[460px]", children: [
2469
- /* @__PURE__ */ jsxs6(DialogHeader, { children: [
2470
- /* @__PURE__ */ jsxs6(DialogTitle, { children: [
2749
+ /* @__PURE__ */ jsx7(Dialog, { open: confirming, onOpenChange: setConfirming, children: /* @__PURE__ */ jsxs7(DialogContent, { className: "max-w-[460px]", children: [
2750
+ /* @__PURE__ */ jsxs7(DialogHeader, { children: [
2751
+ /* @__PURE__ */ jsxs7(DialogTitle, { children: [
2471
2752
  "This chat is running right now in ",
2472
2753
  PROVIDER_LABEL[props.provider]
2473
2754
  ] }),
2474
- /* @__PURE__ */ jsxs6(DialogDescription, { children: [
2755
+ /* @__PURE__ */ jsxs7(DialogDescription, { children: [
2475
2756
  elsewhere?.message,
2476
2757
  " If you take it over, two agents will work in the same conversation at once and may overwrite each other's changes."
2477
2758
  ] })
2478
2759
  ] }),
2479
- /* @__PURE__ */ jsxs6(DialogFooter, { children: [
2480
- /* @__PURE__ */ jsx6(Button2, { variant: "ghost", onClick: () => setConfirming(false), children: "Cancel" }),
2481
- /* @__PURE__ */ jsx6(Button2, { variant: "destructive", onClick: () => void takeover(), children: "Take over anyway" })
2760
+ /* @__PURE__ */ jsxs7(DialogFooter, { children: [
2761
+ /* @__PURE__ */ jsx7(Button3, { variant: "ghost", onClick: () => setConfirming(false), children: "Cancel" }),
2762
+ /* @__PURE__ */ jsx7(Button3, { variant: "destructive", onClick: () => void takeover(), children: "Take over anyway" })
2482
2763
  ] })
2483
2764
  ] }) }),
2484
- error ? /* @__PURE__ */ jsx6("p", { className: "border-b border-destructive/30 bg-destructive/10 px-5 py-2 text-[13px] text-destructive", children: error }) : null,
2485
- d && !d.cwd ? /* @__PURE__ */ jsx6("p", { className: "border-b border-border bg-muted/50 px-5 py-2 text-[13px] text-muted-foreground", children: "This chat doesn't record which folder it ran in, so it can't be continued from here." }) : null,
2486
- /* @__PURE__ */ jsxs6("div", { className: "mx-chat flex min-h-0 flex-1 flex-col", children: [
2487
- preview.loading ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-1 items-center justify-center gap-2 text-[13px] text-muted-foreground", children: [
2488
- /* @__PURE__ */ jsx6(SpinnerIcon, { size: 15 }),
2765
+ error ? /* @__PURE__ */ jsx7("p", { className: "border-b border-destructive/30 bg-destructive/10 px-5 py-2 text-[13px] text-destructive", children: error }) : null,
2766
+ d && !d.cwd ? /* @__PURE__ */ jsx7("p", { className: "border-b border-border bg-muted/50 px-5 py-2 text-[13px] text-muted-foreground", children: "This chat doesn't record which folder it ran in, so it can't be continued from here." }) : null,
2767
+ /* @__PURE__ */ jsxs7("div", { className: "mx-chat flex min-h-0 flex-1 flex-col", children: [
2768
+ preview.loading ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 items-center justify-center gap-2 text-[13px] text-muted-foreground", children: [
2769
+ /* @__PURE__ */ jsx7(SpinnerIcon, { size: 15 }),
2489
2770
  " Reading this chat\u2026"
2490
- ] }) : preview.unavailable ? /* @__PURE__ */ jsx6("div", { className: "flex flex-1 items-center justify-center px-6 text-center text-[13px] text-muted-foreground", children: preview.unavailable }) : /* @__PURE__ */ jsxs6(ChatProvider, { thread, ports: { notifier, toolLabel: friendlyToolName }, children: [
2491
- preview.truncated ? /* @__PURE__ */ jsx6(
2771
+ ] }) : preview.unavailable ? /* @__PURE__ */ jsx7("div", { className: "flex flex-1 items-center justify-center px-6 text-center text-[13px] text-muted-foreground", children: preview.unavailable }) : /* @__PURE__ */ jsxs7(ChatProvider, { thread, ports: { notifier, toolLabel: friendlyToolName }, children: [
2772
+ preview.truncated ? /* @__PURE__ */ jsx7(
2492
2773
  LongChatNote,
2493
2774
  {
2494
2775
  loading: readingEarlier,
@@ -2498,14 +2779,14 @@ function DiscoveredView(props) {
2498
2779
  }
2499
2780
  }
2500
2781
  ) : null,
2501
- /* @__PURE__ */ jsx6(ChatMessageList, { className: "min-h-0 flex-1", label: "Chat preview" })
2782
+ /* @__PURE__ */ jsx7(ChatMessageList, { className: "min-h-0 flex-1", label: "Chat preview" })
2502
2783
  ] }),
2503
- d?.cwd ? /* @__PURE__ */ jsxs6("div", { className: "border-t border-border bg-muted/30 px-5 py-3 text-center text-[13px] text-muted-foreground", children: [
2784
+ d?.cwd ? /* @__PURE__ */ jsxs7("div", { className: "border-t border-border bg-muted/30 px-5 py-3 text-center text-[13px] text-muted-foreground", children: [
2504
2785
  "This chat was started in ",
2505
2786
  PROVIDER_LABEL[props.provider],
2506
2787
  ".",
2507
2788
  " ",
2508
- /* @__PURE__ */ jsx6("button", { type: "button", className: "font-medium text-foreground underline-offset-4 hover:underline", onClick: requestTakeover, children: "Take it over" }),
2789
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "font-medium text-foreground underline-offset-4 hover:underline", onClick: requestTakeover, children: "Take it over" }),
2509
2790
  " ",
2510
2791
  "to continue it here \u2014 it stays in your ",
2511
2792
  PROVIDER_LABEL[props.provider],
@@ -2513,70 +2794,73 @@ function DiscoveredView(props) {
2513
2794
  ] }) : null
2514
2795
  ] })
2515
2796
  ] }),
2516
- props.changesOpen && files.length > 0 ? /* @__PURE__ */ jsx6(ChangesPanel, { files, cwd: d?.cwd ?? null, truncated: preview.truncated, onClose: () => props.setChangesOpen(false) }) : null
2797
+ props.changesOpen && files.length > 0 ? /* @__PURE__ */ jsx7(ChangesPanel, { files, cwd: d?.cwd ?? null, truncated: preview.truncated, onClose: () => props.setChangesOpen(false) }) : null
2517
2798
  ] });
2518
2799
  }
2519
2800
  function ProviderCard(props) {
2520
2801
  const ready = props.status.ready;
2521
- return /* @__PURE__ */ jsxs6(
2802
+ return /* @__PURE__ */ jsxs7(
2522
2803
  "button",
2523
2804
  {
2524
2805
  type: "button",
2525
2806
  onClick: props.onSelect,
2526
2807
  "aria-pressed": props.selected,
2527
- className: cn4(
2808
+ className: cn5(
2528
2809
  "flex flex-1 flex-col gap-1.5 rounded-xl border px-3.5 py-3 text-left transition-colors",
2529
2810
  props.selected ? "border-primary bg-primary/5 ring-1 ring-primary" : "border-border hover:bg-accent/50"
2530
2811
  ),
2531
2812
  children: [
2532
- /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-2", children: [
2533
- /* @__PURE__ */ jsx6(ProviderMark, { provider: props.status.provider, size: 18 }),
2534
- /* @__PURE__ */ jsx6("span", { className: "text-[13.5px] font-semibold", children: props.status.label })
2813
+ /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-2", children: [
2814
+ /* @__PURE__ */ jsx7(ProviderMark, { provider: props.status.provider, size: 18 }),
2815
+ /* @__PURE__ */ jsx7("span", { className: "text-[13.5px] font-semibold", children: props.status.label })
2535
2816
  ] }),
2536
- ready ? /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-1 text-[12px] text-success", children: [
2537
- /* @__PURE__ */ jsx6(CheckIcon, { size: 13 }),
2817
+ ready ? /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-1 text-[12px] text-success", children: [
2818
+ /* @__PURE__ */ jsx7(CheckIcon, { size: 13 }),
2538
2819
  props.status.billing === "subscription" ? `Signed in${props.status.plan ? ` \xB7 ${props.status.plan} plan` : ""}` : "Signed in with an API key (billed per use)"
2539
- ] }) : /* @__PURE__ */ jsxs6("span", { className: "flex items-start gap-1 text-[12px] leading-4 text-warning", children: [
2540
- /* @__PURE__ */ jsx6(AlertIcon, { size: 13, className: "mt-px shrink-0" }),
2820
+ ] }) : /* @__PURE__ */ jsxs7("span", { className: "flex items-start gap-1 text-[12px] leading-4 text-warning", children: [
2821
+ /* @__PURE__ */ jsx7(AlertIcon, { size: 13, className: "mt-px shrink-0" }),
2541
2822
  props.status.problem
2542
2823
  ] }),
2543
- props.status.quota.filter((w) => w.usedPercent !== null).length > 0 ? /* @__PURE__ */ jsx6("span", { className: "text-[11.5px] leading-4 text-muted-foreground", children: props.status.quota.filter((w) => w.usedPercent !== null).map((w) => `${w.label}: ${w.usedPercent}% used`).join(" \xB7 ") }) : null
2824
+ props.status.quota.filter((w) => w.usedPercent !== null).length > 0 ? /* @__PURE__ */ jsx7("span", { className: "text-[11.5px] leading-4 text-muted-foreground", children: props.status.quota.filter((w) => w.usedPercent !== null).map((w) => `${w.label}: ${w.usedPercent}% used`).join(" \xB7 ") }) : null
2544
2825
  ]
2545
2826
  }
2546
2827
  );
2547
2828
  }
2548
2829
  function FieldError({ id, children }) {
2549
- return /* @__PURE__ */ jsxs6("p", { id, role: "alert", className: "flex items-start gap-1.5 text-[12.5px] leading-5 text-destructive", children: [
2550
- /* @__PURE__ */ jsx6(AlertIcon, { size: 14, className: "mt-0.5 shrink-0" }),
2551
- /* @__PURE__ */ jsx6("span", { children })
2830
+ return /* @__PURE__ */ jsxs7("p", { id, role: "alert", className: "flex items-start gap-1.5 text-[12.5px] leading-5 text-destructive", children: [
2831
+ /* @__PURE__ */ jsx7(AlertIcon, { size: 14, className: "mt-0.5 shrink-0" }),
2832
+ /* @__PURE__ */ jsx7("span", { children })
2552
2833
  ] });
2553
2834
  }
2554
2835
  function NewSessionDialog(props) {
2555
2836
  const client = useCodingSessionsClient();
2556
2837
  const state = useCodingSessionsState();
2557
2838
  const now = useMinuteClock();
2558
- const [provider, setProvider] = useState5("claude");
2559
- const [folder, setFolder] = useState5("");
2560
- const [choice, setChoice] = useState5({ model: null, effort: null });
2561
- const [prompt, setPrompt] = useState5("");
2562
- const [errors, setErrors] = useState5({});
2563
- const [problem, setProblem] = useState5(null);
2564
- const [starting, setStarting] = useState5(false);
2565
- const [creating, setCreating] = useState5(false);
2566
- const promptRef = useRef2(null);
2567
- const folderRef = useRef2(null);
2568
- const agentRef = useRef2(null);
2569
- useEffect3(() => {
2839
+ const [provider, setProvider] = useState6("claude");
2840
+ const [folder, setFolder] = useState6("");
2841
+ const [choice, setChoice] = useState6({ model: null, effort: null });
2842
+ const [prompt, setPrompt] = useState6("");
2843
+ const [errors, setErrors] = useState6({});
2844
+ const [problem, setProblem] = useState6(null);
2845
+ const [starting, setStarting] = useState6(false);
2846
+ const [creating, setCreating] = useState6(false);
2847
+ const [agent, setAgent] = useState6(null);
2848
+ const [agentDetails, setAgentDetails] = useState6(null);
2849
+ const [agentMissing, setAgentMissing] = useState6(null);
2850
+ const promptRef = useRef3(null);
2851
+ const folderRef = useRef3(null);
2852
+ const agentRef = useRef3(null);
2853
+ useEffect4(() => {
2570
2854
  if (!props.open) return;
2571
2855
  setProblem(null);
2572
2856
  setErrors({});
2573
2857
  void client.refreshProviders();
2574
2858
  void client.refreshFolders();
2575
2859
  }, [props.open, client]);
2576
- useEffect3(() => {
2860
+ useEffect4(() => {
2577
2861
  if (!folder && state.folders.data[0]?.exists) setFolder(state.folders.data[0].path);
2578
2862
  }, [state.folders.data, folder]);
2579
- useEffect3(() => {
2863
+ useEffect4(() => {
2580
2864
  const ready = state.providers.data.filter((p) => p.ready);
2581
2865
  const current = state.providers.data.find((p) => p.provider === provider);
2582
2866
  if (current && !current.ready && ready[0]) setProvider(ready[0].provider);
@@ -2602,9 +2886,22 @@ function NewSessionDialog(props) {
2602
2886
  focusField(first);
2603
2887
  return;
2604
2888
  }
2889
+ const missing = missingRequiredVariable(agentDetails, agent);
2890
+ setAgentMissing(missing);
2891
+ if (missing) {
2892
+ document.getElementById(`cs-agent-var-${missing}`)?.focus();
2893
+ return;
2894
+ }
2605
2895
  setStarting(true);
2606
2896
  try {
2607
- const result = await client.start({ provider, cwd: folder.trim(), prompt, model: choice.model, effort: choice.effort });
2897
+ const result = await client.start({
2898
+ provider,
2899
+ cwd: folder.trim(),
2900
+ prompt,
2901
+ model: choice.model,
2902
+ effort: choice.effort,
2903
+ ...agent ? { agent } : {}
2904
+ });
2608
2905
  setPrompt("");
2609
2906
  props.onStarted(result.session.id);
2610
2907
  } catch (error) {
@@ -2640,16 +2937,16 @@ function NewSessionDialog(props) {
2640
2937
  if (field === "folder") delete next.createFolder;
2641
2938
  return next;
2642
2939
  });
2643
- return /* @__PURE__ */ jsx6(Dialog, { open: props.open, onOpenChange: props.onOpenChange, children: /* @__PURE__ */ jsxs6(DialogContent, { className: "max-w-[560px]", children: [
2644
- /* @__PURE__ */ jsxs6(DialogHeader, { children: [
2645
- /* @__PURE__ */ jsx6(DialogTitle, { children: "New coding session" }),
2646
- /* @__PURE__ */ jsxs6(DialogDescription, { children: [
2940
+ return /* @__PURE__ */ jsx7(Dialog, { open: props.open, onOpenChange: props.onOpenChange, children: /* @__PURE__ */ jsxs7(DialogContent, { className: "max-w-[560px]", children: [
2941
+ /* @__PURE__ */ jsxs7(DialogHeader, { children: [
2942
+ /* @__PURE__ */ jsx7(DialogTitle, { children: "New coding session" }),
2943
+ /* @__PURE__ */ jsxs7(DialogDescription, { children: [
2647
2944
  "Runs on your own ",
2648
2945
  provider === "claude" ? "Claude" : "ChatGPT",
2649
2946
  " sign-in, in a folder on this computer."
2650
2947
  ] })
2651
2948
  ] }),
2652
- /* @__PURE__ */ jsxs6(
2949
+ /* @__PURE__ */ jsxs7(
2653
2950
  "form",
2654
2951
  {
2655
2952
  noValidate: true,
@@ -2659,13 +2956,13 @@ function NewSessionDialog(props) {
2659
2956
  },
2660
2957
  className: "flex min-h-0 flex-col",
2661
2958
  children: [
2662
- /* @__PURE__ */ jsxs6("div", { className: "cs-dialog-body space-y-5 py-1 pr-1", children: [
2663
- /* @__PURE__ */ jsxs6("fieldset", { className: "space-y-2", ref: agentRef, children: [
2664
- /* @__PURE__ */ jsx6("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Agent" }),
2665
- state.providers.loading && state.providers.loadedAt === null ? /* @__PURE__ */ jsxs6("div", { className: "flex gap-2", children: [
2666
- /* @__PURE__ */ jsx6("div", { className: "cs-skeleton h-[68px] flex-1 rounded-xl" }),
2667
- /* @__PURE__ */ jsx6("div", { className: "cs-skeleton h-[68px] flex-1 rounded-xl" })
2668
- ] }) : state.providers.error ? /* @__PURE__ */ jsx6("p", { className: "text-[12.5px] text-destructive", children: state.providers.error }) : /* @__PURE__ */ jsx6("div", { className: "flex gap-2", children: state.providers.data.map((p) => /* @__PURE__ */ jsx6(
2959
+ /* @__PURE__ */ jsxs7("div", { className: "cs-dialog-body space-y-5 py-1 pr-1", children: [
2960
+ /* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", ref: agentRef, children: [
2961
+ /* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Agent" }),
2962
+ state.providers.loading && state.providers.loadedAt === null ? /* @__PURE__ */ jsxs7("div", { className: "flex gap-2", children: [
2963
+ /* @__PURE__ */ jsx7("div", { className: "cs-skeleton h-[68px] flex-1 rounded-xl" }),
2964
+ /* @__PURE__ */ jsx7("div", { className: "cs-skeleton h-[68px] flex-1 rounded-xl" })
2965
+ ] }) : state.providers.error ? /* @__PURE__ */ jsx7("p", { className: "text-[12.5px] text-destructive", children: state.providers.error }) : /* @__PURE__ */ jsx7("div", { className: "flex gap-2", children: state.providers.data.map((p) => /* @__PURE__ */ jsx7(
2669
2966
  ProviderCard,
2670
2967
  {
2671
2968
  status: p,
@@ -2678,14 +2975,31 @@ function NewSessionDialog(props) {
2678
2975
  },
2679
2976
  p.provider
2680
2977
  )) }),
2681
- errors.agent ? /* @__PURE__ */ jsx6(FieldError, { id: "cs-err-agent", children: errors.agent }) : selected && !selected.ready && selected.fix ? /* @__PURE__ */ jsxs6("p", { className: "text-[12px] leading-4 text-muted-foreground", children: [
2978
+ errors.agent ? /* @__PURE__ */ jsx7(FieldError, { id: "cs-err-agent", children: errors.agent }) : selected && !selected.ready && selected.fix ? /* @__PURE__ */ jsxs7("p", { className: "text-[12px] leading-4 text-muted-foreground", children: [
2682
2979
  selected.fix,
2683
2980
  selected.installed && selected.loggedIn ? " You can still try \u2014 the run will say if it's still blocked." : ""
2684
2981
  ] }) : null
2685
2982
  ] }),
2686
- /* @__PURE__ */ jsxs6("fieldset", { className: "space-y-2", children: [
2687
- /* @__PURE__ */ jsx6("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Folder" }),
2688
- state.folders.data.length > 0 ? /* @__PURE__ */ jsx6("div", { className: "max-h-[132px] space-y-0.5 overflow-y-auto rounded-lg border border-border p-1", children: state.folders.data.map((f) => /* @__PURE__ */ jsxs6(
2983
+ /* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
2984
+ /* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "AI Matrx agent" }),
2985
+ /* @__PURE__ */ jsx7(
2986
+ AgentField,
2987
+ {
2988
+ transport: client.transport,
2989
+ open: props.open,
2990
+ value: agent,
2991
+ onChange: (next) => {
2992
+ setAgent(next);
2993
+ setAgentMissing(null);
2994
+ },
2995
+ missing: agentMissing,
2996
+ onDetails: setAgentDetails
2997
+ }
2998
+ )
2999
+ ] }),
3000
+ /* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
3001
+ /* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Folder" }),
3002
+ state.folders.data.length > 0 ? /* @__PURE__ */ jsx7("div", { className: "max-h-[132px] space-y-0.5 overflow-y-auto rounded-lg border border-border p-1", children: state.folders.data.map((f) => /* @__PURE__ */ jsxs7(
2689
3003
  "button",
2690
3004
  {
2691
3005
  type: "button",
@@ -2695,21 +3009,21 @@ function NewSessionDialog(props) {
2695
3009
  },
2696
3010
  disabled: !f.exists,
2697
3011
  title: f.exists ? f.path : `${f.path} no longer exists`,
2698
- className: cn4(
3012
+ className: cn5(
2699
3013
  "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-[12.5px]",
2700
3014
  folder === f.path ? "bg-accent text-accent-foreground" : "hover:bg-accent/50",
2701
3015
  !f.exists && "opacity-50"
2702
3016
  ),
2703
3017
  children: [
2704
- /* @__PURE__ */ jsx6(FolderIcon, { size: 14, className: "shrink-0 text-muted-foreground" }),
2705
- /* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate", children: prettyPath2(f.path) }),
2706
- /* @__PURE__ */ jsx6("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: f.exists ? relativeTime(f.lastUsedAt, now) : "missing" })
3018
+ /* @__PURE__ */ jsx7(FolderIcon, { size: 14, className: "shrink-0 text-muted-foreground" }),
3019
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate", children: prettyPath2(f.path) }),
3020
+ /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: f.exists ? relativeTime(f.lastUsedAt, now) : "missing" })
2707
3021
  ]
2708
3022
  },
2709
3023
  f.path
2710
- )) }) : state.folders.loading ? /* @__PURE__ */ jsx6("div", { className: "cs-skeleton h-10 rounded-lg" }) : null,
2711
- /* @__PURE__ */ jsx6(
2712
- Input,
3024
+ )) }) : state.folders.loading ? /* @__PURE__ */ jsx7("div", { className: "cs-skeleton h-10 rounded-lg" }) : null,
3025
+ /* @__PURE__ */ jsx7(
3026
+ Input2,
2713
3027
  {
2714
3028
  ref: folderRef,
2715
3029
  value: folder,
@@ -2724,18 +3038,18 @@ function NewSessionDialog(props) {
2724
3038
  spellCheck: false
2725
3039
  }
2726
3040
  ),
2727
- errors.folder ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: [
2728
- /* @__PURE__ */ jsx6(FieldError, { id: "cs-err-folder", children: errors.folder }),
2729
- errors.createFolder ? /* @__PURE__ */ jsxs6(Button2, { type: "button", size: "sm", variant: "outline", onClick: () => void createFolder(), disabled: creating, className: "gap-1.5", children: [
2730
- creating ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx6(FolderIcon, { size: 13 }),
3041
+ errors.folder ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: [
3042
+ /* @__PURE__ */ jsx7(FieldError, { id: "cs-err-folder", children: errors.folder }),
3043
+ errors.createFolder ? /* @__PURE__ */ jsxs7(Button3, { type: "button", size: "sm", variant: "outline", onClick: () => void createFolder(), disabled: creating, className: "gap-1.5", children: [
3044
+ creating ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx7(FolderIcon, { size: 13 }),
2731
3045
  "Create this folder"
2732
3046
  ] }) : null
2733
3047
  ] }) : null
2734
3048
  ] }),
2735
- /* @__PURE__ */ jsxs6("fieldset", { className: "space-y-2", children: [
2736
- /* @__PURE__ */ jsx6("legend", { className: "mb-2 text-[12.5px] font-medium", children: "What should it do?" }),
2737
- /* @__PURE__ */ jsx6(
2738
- Textarea,
3049
+ /* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
3050
+ /* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "What should it do?" }),
3051
+ /* @__PURE__ */ jsx7(
3052
+ Textarea2,
2739
3053
  {
2740
3054
  ref: promptRef,
2741
3055
  value: prompt,
@@ -2756,25 +3070,25 @@ function NewSessionDialog(props) {
2756
3070
  "aria-describedby": errors.prompt ? "cs-err-prompt" : void 0
2757
3071
  }
2758
3072
  ),
2759
- errors.prompt ? /* @__PURE__ */ jsx6(FieldError, { id: "cs-err-prompt", children: errors.prompt }) : null
3073
+ errors.prompt ? /* @__PURE__ */ jsx7(FieldError, { id: "cs-err-prompt", children: errors.prompt }) : null
2760
3074
  ] }),
2761
- /* @__PURE__ */ jsxs6("fieldset", { className: "space-y-2", children: [
2762
- /* @__PURE__ */ jsx6("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Model and thinking effort" }),
2763
- /* @__PURE__ */ jsx6(ModelPicker, { status: selected, value: choice, onChange: setChoice, appearance: "field" }),
2764
- /* @__PURE__ */ jsxs6("p", { className: "text-[11.5px] leading-4 text-muted-foreground", children: [
3075
+ /* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
3076
+ /* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Model and thinking effort" }),
3077
+ /* @__PURE__ */ jsx7(ModelPicker, { status: selected, value: choice, onChange: setChoice, appearance: "field" }),
3078
+ /* @__PURE__ */ jsxs7("p", { className: "text-[11.5px] leading-4 text-muted-foreground", children: [
2765
3079
  "Default is ",
2766
3080
  defaultModelWords(selected),
2767
3081
  ". You can change it later from the chat's header."
2768
3082
  ] })
2769
3083
  ] }),
2770
- problem ? /* @__PURE__ */ jsx6(FieldError, { id: "cs-err-start", children: problem }) : null
3084
+ problem ? /* @__PURE__ */ jsx7(FieldError, { id: "cs-err-start", children: problem }) : null
2771
3085
  ] }),
2772
- /* @__PURE__ */ jsxs6(DialogFooter, { className: "pt-4", children: [
2773
- /* @__PURE__ */ jsx6(Button2, { type: "button", variant: "ghost", onClick: () => props.onOpenChange(false), children: "Cancel" }),
2774
- /* @__PURE__ */ jsxs6(Button2, { type: "submit", disabled: starting, className: "gap-1.5", children: [
2775
- starting ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 14 }) : null,
3086
+ /* @__PURE__ */ jsxs7(DialogFooter, { className: "pt-4", children: [
3087
+ /* @__PURE__ */ jsx7(Button3, { type: "button", variant: "ghost", onClick: () => props.onOpenChange(false), children: "Cancel" }),
3088
+ /* @__PURE__ */ jsxs7(Button3, { type: "submit", disabled: starting, className: "gap-1.5", children: [
3089
+ starting ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 14 }) : null,
2776
3090
  starting ? "Starting\u2026" : "Start session",
2777
- !starting ? /* @__PURE__ */ jsx6("kbd", { className: "cs-kbd", children: "\u2318\u21B5" }) : null
3091
+ !starting ? /* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2318\u21B5" }) : null
2778
3092
  ] })
2779
3093
  ] })
2780
3094
  ]
@@ -2784,47 +3098,58 @@ function NewSessionDialog(props) {
2784
3098
  }
2785
3099
  function Home({ onNew }) {
2786
3100
  const state = useCodingSessionsState();
2787
- return /* @__PURE__ */ jsx6("section", { className: "flex flex-1 items-center justify-center px-6", children: /* @__PURE__ */ jsxs6("div", { className: "w-full max-w-[460px] text-center", children: [
2788
- /* @__PURE__ */ jsx6("span", { className: "mx-auto mb-4 flex h-11 w-11 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx6(ChatBubbleIcon, { size: 22 }) }),
2789
- /* @__PURE__ */ jsx6("h1", { className: "text-[19px] font-semibold tracking-[-0.015em]", children: "Drive Claude Code and Codex from here" }),
2790
- /* @__PURE__ */ jsx6("p", { className: "mx-auto mt-2 max-w-[400px] text-[13.5px] leading-6 text-muted-foreground", children: "Start a session in any folder, or pick up a chat you began somewhere else. Everything runs on your own subscriptions \u2014 no API keys." }),
2791
- /* @__PURE__ */ jsxs6(Button2, { className: "mt-5 gap-1.5", onClick: onNew, children: [
2792
- /* @__PURE__ */ jsx6(PlusIcon, { size: 15 }),
3101
+ return /* @__PURE__ */ jsx7("section", { className: "flex flex-1 items-center justify-center px-6", children: /* @__PURE__ */ jsxs7("div", { className: "w-full max-w-[460px] text-center", children: [
3102
+ /* @__PURE__ */ jsx7("span", { className: "mx-auto mb-4 flex h-11 w-11 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx7(ChatBubbleIcon, { size: 22 }) }),
3103
+ /* @__PURE__ */ jsx7("h1", { className: "text-[15px] font-semibold leading-5 tracking-[-0.01em]", children: "Drive Claude Code and Codex from here" }),
3104
+ /* @__PURE__ */ jsx7("p", { className: "mx-auto mt-2 max-w-[400px] text-[13.5px] leading-6 text-muted-foreground", children: "Start a session in any folder, or pick up a chat you began somewhere else. Everything runs on your own subscriptions \u2014 no API keys." }),
3105
+ /* @__PURE__ */ jsxs7(Button3, { className: "mt-5 gap-1.5", onClick: onNew, children: [
3106
+ /* @__PURE__ */ jsx7(PlusIcon, { size: 15 }),
2793
3107
  "New session"
2794
3108
  ] }),
2795
- /* @__PURE__ */ jsxs6("p", { className: "mt-3 text-[12px] text-muted-foreground", children: [
2796
- /* @__PURE__ */ jsx6("kbd", { className: "cs-kbd", children: "\u2325\u2318N" }),
3109
+ /* @__PURE__ */ jsxs7("p", { className: "mt-3 text-[12px] text-muted-foreground", children: [
3110
+ /* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2325\u2318N" }),
2797
3111
  " new session \xB7 ",
2798
- /* @__PURE__ */ jsx6("kbd", { className: "cs-kbd", children: "\u2318K" }),
3112
+ /* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2318K" }),
2799
3113
  " search your chats \xB7",
2800
3114
  " ",
2801
- /* @__PURE__ */ jsx6("kbd", { className: "cs-kbd", children: "\u2318/" }),
3115
+ /* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2318/" }),
2802
3116
  " all shortcuts"
2803
3117
  ] }),
2804
- /* @__PURE__ */ jsx6("div", { className: "mt-6 space-y-1.5 text-left", children: state.providers.data.map((p) => /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2.5 rounded-lg border border-border px-3 py-2.5", children: [
2805
- /* @__PURE__ */ jsx6(ProviderMark, { provider: p.provider, size: 18 }),
2806
- /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1 text-[12.5px] leading-5", children: [
2807
- /* @__PURE__ */ jsx6("span", { className: "font-medium", children: p.label }),
2808
- p.ready ? /* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground", children: [
3118
+ /* @__PURE__ */ jsx7("div", { className: "mt-6 grid grid-cols-[repeat(auto-fit,minmax(220px,1fr))] gap-1.5 text-left", children: state.providers.data.map((p) => /* @__PURE__ */ jsxs7("div", { className: "flex min-w-[220px] items-start gap-2.5 rounded-lg border border-border px-3 py-2.5", children: [
3119
+ /* @__PURE__ */ jsx7(ProviderMark, { provider: p.provider, size: 16 }),
3120
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1 text-[12.5px] leading-5", children: [
3121
+ /* @__PURE__ */ jsx7("span", { className: "font-medium", children: p.label }),
3122
+ p.ready ? /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground", children: [
2809
3123
  " ",
2810
3124
  "\u2014 ready",
2811
3125
  p.plan ? ` on your ${p.plan} plan` : "",
2812
- p.billing === "api" ? " (API key, billed per use)" : "",
2813
- p.version ? ` \xB7 version ${p.version}` : ""
2814
- ] }) : /* @__PURE__ */ jsxs6("span", { className: "block text-muted-foreground", children: [
3126
+ p.billing === "api" ? " (API key, billed per use)" : ""
3127
+ ] }) : null,
3128
+ p.installed && p.version ? /* @__PURE__ */ jsxs7(
3129
+ "span",
3130
+ {
3131
+ className: "block text-[11.5px] text-muted-foreground",
3132
+ title: newerWords(p) ?? p.binary?.path ?? void 0,
3133
+ children: [
3134
+ binaryWords(p),
3135
+ p.binary?.newer ? ` \xB7 ${p.binary.newer.version} available` : ""
3136
+ ]
3137
+ }
3138
+ ) : null,
3139
+ p.ready ? null : /* @__PURE__ */ jsxs7("span", { className: "block text-muted-foreground", children: [
2815
3140
  p.problem,
2816
3141
  " ",
2817
3142
  p.fix
2818
3143
  ] })
2819
3144
  ] }),
2820
- p.ready ? /* @__PURE__ */ jsx6(CheckIcon, { size: 15, className: "mt-0.5 text-success" }) : /* @__PURE__ */ jsx6(AlertIcon, { size: 15, className: "mt-0.5 text-warning" })
3145
+ p.ready ? /* @__PURE__ */ jsx7(CheckIcon, { size: 15, className: "mt-0.5 text-success" }) : /* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 text-warning" })
2821
3146
  ] }, p.provider)) })
2822
3147
  ] }) });
2823
3148
  }
2824
3149
  function useToast() {
2825
- const [text, setText] = useState5(null);
2826
- const timer = useRef2(null);
2827
- useEffect3(() => () => {
3150
+ const [text, setText] = useState6(null);
3151
+ const timer = useRef3(null);
3152
+ useEffect4(() => () => {
2828
3153
  if (timer.current) clearTimeout(timer.current);
2829
3154
  }, []);
2830
3155
  const show = useCallback2((next) => {
@@ -2836,7 +3161,7 @@ function useToast() {
2836
3161
  }
2837
3162
  function Toast({ text }) {
2838
3163
  if (!text) return null;
2839
- return /* @__PURE__ */ jsx6("div", { role: "status", className: "cs-toast", children: text });
3164
+ return /* @__PURE__ */ jsx7("div", { role: "status", className: "cs-toast", children: text });
2840
3165
  }
2841
3166
  var SIDEBAR_DEFAULT = 300;
2842
3167
  var SIDEBAR_MIN = 220;
@@ -2845,7 +3170,7 @@ function clampWidth(n) {
2845
3170
  return Math.round(Math.min(SIDEBAR_MAX, Math.max(SIDEBAR_MIN, n)));
2846
3171
  }
2847
3172
  function useSidebarLayout() {
2848
- const [width, setWidthState] = useState5(() => {
3173
+ const [width, setWidthState] = useState6(() => {
2849
3174
  try {
2850
3175
  const n = Number(localStorage.getItem("coding-sessions.sidebar-width"));
2851
3176
  return Number.isFinite(n) && n > 0 ? clampWidth(n) : SIDEBAR_DEFAULT;
@@ -2853,7 +3178,7 @@ function useSidebarLayout() {
2853
3178
  return SIDEBAR_DEFAULT;
2854
3179
  }
2855
3180
  });
2856
- const [collapsed, setCollapsedState] = useState5(() => {
3181
+ const [collapsed, setCollapsedState] = useState6(() => {
2857
3182
  try {
2858
3183
  return localStorage.getItem("coding-sessions.sidebar-collapsed") === "1";
2859
3184
  } catch {
@@ -2878,8 +3203,8 @@ function useSidebarLayout() {
2878
3203
  return { width, setWidth, collapsed, setCollapsed };
2879
3204
  }
2880
3205
  function Resizer(props) {
2881
- const [dragging, setDragging] = useState5(false);
2882
- return /* @__PURE__ */ jsx6("div", { className: cn4("cs-resizer", dragging && "cs-resizer--dragging"), children: /* @__PURE__ */ jsx6(
3206
+ const [dragging, setDragging] = useState6(false);
3207
+ return /* @__PURE__ */ jsx7("div", { className: cn5("cs-resizer", dragging && "cs-resizer--dragging"), children: /* @__PURE__ */ jsx7(
2883
3208
  "button",
2884
3209
  {
2885
3210
  type: "button",
@@ -2927,24 +3252,24 @@ var SHORTCUTS = [
2927
3252
  { keys: "\u2318/", what: "These shortcuts" }
2928
3253
  ];
2929
3254
  function ShortcutsDialog(props) {
2930
- return /* @__PURE__ */ jsx6(Dialog, { open: props.open, onOpenChange: props.onOpenChange, children: /* @__PURE__ */ jsxs6(DialogContent, { className: "max-w-[420px]", children: [
2931
- /* @__PURE__ */ jsxs6(DialogHeader, { children: [
2932
- /* @__PURE__ */ jsx6(DialogTitle, { children: "Keyboard shortcuts" }),
2933
- /* @__PURE__ */ jsx6(DialogDescription, { children: "Ctrl works in place of \u2318 on Windows and Linux." })
3255
+ return /* @__PURE__ */ jsx7(Dialog, { open: props.open, onOpenChange: props.onOpenChange, children: /* @__PURE__ */ jsxs7(DialogContent, { className: "max-w-[420px]", children: [
3256
+ /* @__PURE__ */ jsxs7(DialogHeader, { children: [
3257
+ /* @__PURE__ */ jsx7(DialogTitle, { children: "Keyboard shortcuts" }),
3258
+ /* @__PURE__ */ jsx7(DialogDescription, { children: "Ctrl works in place of \u2318 on Windows and Linux." })
2934
3259
  ] }),
2935
- /* @__PURE__ */ jsx6("dl", { className: "divide-y divide-border text-[13px]", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-4 py-2", children: [
2936
- /* @__PURE__ */ jsx6("dt", { className: "text-muted-foreground", children: s.what }),
2937
- /* @__PURE__ */ jsx6("dd", { children: /* @__PURE__ */ jsx6("kbd", { className: "rounded border border-border px-1.5 py-0.5 font-sans text-[12px]", children: s.keys }) })
3260
+ /* @__PURE__ */ jsx7("dl", { className: "divide-y divide-border text-[13px]", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-4 py-2", children: [
3261
+ /* @__PURE__ */ jsx7("dt", { className: "text-muted-foreground", children: s.what }),
3262
+ /* @__PURE__ */ jsx7("dd", { children: /* @__PURE__ */ jsx7("kbd", { className: "rounded border border-border px-1.5 py-0.5 font-sans text-[12px]", children: s.keys }) })
2938
3263
  ] }, s.keys)) })
2939
3264
  ] }) });
2940
3265
  }
2941
3266
  var BASE_TITLE = "Coding sessions";
2942
3267
  function useRunFinishedNotices(openSessionId, show) {
2943
3268
  const client = useCodingSessionsClient();
2944
- const unseen = useRef2(0);
2945
- const openRef = useRef2(openSessionId);
3269
+ const unseen = useRef3(0);
3270
+ const openRef = useRef3(openSessionId);
2946
3271
  openRef.current = openSessionId;
2947
- useEffect3(() => {
3272
+ useEffect4(() => {
2948
3273
  const reset = () => {
2949
3274
  if (document.visibilityState === "visible") {
2950
3275
  unseen.current = 0;
@@ -2960,7 +3285,7 @@ function useRunFinishedNotices(openSessionId, show) {
2960
3285
  unseen.current += 1;
2961
3286
  document.title = `(${unseen.current}) ${BASE_TITLE}`;
2962
3287
  if (typeof Notification !== "undefined" && Notification.permission === "granted") {
2963
- const note = new Notification(sentence, run.error ? { tag: run.runId, body: run.error } : { tag: run.runId });
3288
+ const note = new Notification(sentence, run.error ? { tag: run.runId, body: runErrorLabel(run.error) } : { tag: run.runId });
2964
3289
  note.onclick = () => {
2965
3290
  window.focus();
2966
3291
  location.hash = `#s/${run.sessionId}`;
@@ -2979,9 +3304,9 @@ function useRunFinishedNotices(openSessionId, show) {
2979
3304
  }
2980
3305
  function NotifyToggle() {
2981
3306
  const supported = typeof Notification !== "undefined";
2982
- const [permission, setPermission] = useState5(supported ? Notification.permission : "denied");
3307
+ const [permission, setPermission] = useState6(supported ? Notification.permission : "denied");
2983
3308
  if (!supported || permission === "granted") return null;
2984
- return /* @__PURE__ */ jsx6(
3309
+ return /* @__PURE__ */ jsx7(
2985
3310
  "button",
2986
3311
  {
2987
3312
  type: "button",
@@ -2990,7 +3315,7 @@ function NotifyToggle() {
2990
3315
  "aria-label": permission === "denied" ? "Notifications are blocked for this page in your browser's site settings" : "Notify me when a run finishes",
2991
3316
  title: permission === "denied" ? "Notifications are blocked in your browser's site settings" : "Notify me when a run finishes",
2992
3317
  disabled: permission === "denied",
2993
- children: /* @__PURE__ */ jsx6(BellIcon, { size: 14 })
3318
+ children: /* @__PURE__ */ jsx7(BellIcon, { size: 14 })
2994
3319
  }
2995
3320
  );
2996
3321
  }
@@ -3002,20 +3327,20 @@ function isTyping(target) {
3002
3327
  function Shell() {
3003
3328
  const client = useCodingSessionsClient();
3004
3329
  const state = useCodingSessionsState();
3005
- const [selection, setSelection] = useState5(readHash);
3006
- const [newOpen, setNewOpen] = useState5(false);
3007
- const [shortcutsOpen, setShortcutsOpen] = useState5(false);
3008
- const [changesOpen, setChangesOpen] = useState5(false);
3009
- const [found, setFound] = useState5({});
3330
+ const [selection, setSelection] = useState6(readHash);
3331
+ const [newOpen, setNewOpen] = useState6(false);
3332
+ const [shortcutsOpen, setShortcutsOpen] = useState6(false);
3333
+ const [changesOpen, setChangesOpen] = useState6(false);
3334
+ const [found, setFound] = useState6({});
3010
3335
  const [theme, setTheme] = useTheme();
3011
3336
  const [toast, showToast] = useToast();
3012
3337
  const layout = useSidebarLayout();
3013
- const searchRef = useRef2(null);
3338
+ const searchRef = useRef3(null);
3014
3339
  const select = useCallback2((next) => {
3015
3340
  setSelection(next);
3016
3341
  writeHash(next);
3017
3342
  }, []);
3018
- useEffect3(() => {
3343
+ useEffect4(() => {
3019
3344
  const onHash = () => setSelection(readHash());
3020
3345
  window.addEventListener("hashchange", onHash);
3021
3346
  return () => window.removeEventListener("hashchange", onHash);
@@ -3025,14 +3350,14 @@ function Shell() {
3025
3350
  const discovered = selection.kind === "discovered" ? state.discovered.data.find((d) => d.providerSessionId === selection.id) ?? found[`${selection.provider}:${selection.id}`] ?? null : null;
3026
3351
  const run = session ? state.runs[session.id] : void 0;
3027
3352
  const live = run !== void 0 && !isTerminalRunStatus(run.status);
3028
- const order = useMemo3(() => {
3353
+ const order = useMemo4(() => {
3029
3354
  const known = new Set(state.sessions.data.map((s) => s.providerSessionId).filter(Boolean));
3030
3355
  return [
3031
3356
  ...state.sessions.data.map((s) => ({ kind: "session", id: s.id })),
3032
3357
  ...state.discovered.data.filter((d) => !known.has(d.providerSessionId)).map((d) => ({ kind: "discovered", provider: d.provider, id: d.providerSessionId }))
3033
3358
  ];
3034
3359
  }, [state.sessions.data, state.discovered.data]);
3035
- useEffect3(() => {
3360
+ useEffect4(() => {
3036
3361
  const onKey = (e) => {
3037
3362
  const mod = e.metaKey || e.ctrlKey;
3038
3363
  const key = e.key.toLowerCase();
@@ -3088,12 +3413,12 @@ function Shell() {
3088
3413
  }, [client, layout, live, run, order, selection, select, showToast]);
3089
3414
  let main;
3090
3415
  if (selection.kind === "session") {
3091
- main = session ? /* @__PURE__ */ jsx6(SessionView, { session, changesOpen, setChangesOpen }, session.id) : state.sessions.loadedAt === null ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-1 items-center justify-center gap-2 text-[13px] text-muted-foreground", children: [
3092
- /* @__PURE__ */ jsx6(SpinnerIcon, { size: 15 }),
3416
+ main = session ? /* @__PURE__ */ jsx7(SessionView, { session, changesOpen, setChangesOpen }, session.id) : state.sessions.loadedAt === null ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 items-center justify-center gap-2 text-[13px] text-muted-foreground", children: [
3417
+ /* @__PURE__ */ jsx7(SpinnerIcon, { size: 15 }),
3093
3418
  " Loading\u2026"
3094
- ] }) : /* @__PURE__ */ jsx6("div", { className: "flex flex-1 items-center justify-center text-[13px] text-muted-foreground", children: "That session is not in the list anymore." });
3419
+ ] }) : /* @__PURE__ */ jsx7("div", { className: "flex flex-1 items-center justify-center text-[13px] text-muted-foreground", children: "That session is not in the list anymore." });
3095
3420
  } else if (selection.kind === "discovered") {
3096
- main = /* @__PURE__ */ jsx6(
3421
+ main = /* @__PURE__ */ jsx7(
3097
3422
  DiscoveredView,
3098
3423
  {
3099
3424
  session: discovered,
@@ -3106,13 +3431,13 @@ function Shell() {
3106
3431
  `${selection.provider}:${selection.id}`
3107
3432
  );
3108
3433
  } else {
3109
- main = /* @__PURE__ */ jsx6(Home, { onNew: () => setNewOpen(true) });
3434
+ main = /* @__PURE__ */ jsx7(Home, { onNew: () => setNewOpen(true) });
3110
3435
  }
3111
- return /* @__PURE__ */ jsx6(ToastContext.Provider, { value: showToast, children: /* @__PURE__ */ jsxs6("div", { className: "cs-app flex h-full flex-col bg-background text-foreground", children: [
3112
- /* @__PURE__ */ jsx6(ConnectionBanner, {}),
3113
- /* @__PURE__ */ jsxs6("div", { className: "flex min-h-0 flex-1", children: [
3114
- layout.collapsed ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center gap-1 border-r border-border bg-muted/30 px-1.5 py-3", children: [
3115
- /* @__PURE__ */ jsx6(
3436
+ return /* @__PURE__ */ jsx7(ToastContext.Provider, { value: showToast, children: /* @__PURE__ */ jsxs7("div", { className: "cs-app flex h-full flex-col bg-background text-foreground", children: [
3437
+ /* @__PURE__ */ jsx7(ConnectionBanner, {}),
3438
+ /* @__PURE__ */ jsxs7("div", { className: "flex min-h-0 flex-1", children: [
3439
+ layout.collapsed ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center gap-1 border-r border-border bg-muted/30 px-1.5 py-3", children: [
3440
+ /* @__PURE__ */ jsx7(
3116
3441
  "button",
3117
3442
  {
3118
3443
  type: "button",
@@ -3120,10 +3445,10 @@ function Shell() {
3120
3445
  onClick: () => layout.setCollapsed(false),
3121
3446
  "aria-label": "Show the sidebar (\u2318B)",
3122
3447
  title: "Show sidebar \u2318B",
3123
- children: /* @__PURE__ */ jsx6(SidebarIcon, { size: 15 })
3448
+ children: /* @__PURE__ */ jsx7(SidebarIcon, { size: 15 })
3124
3449
  }
3125
3450
  ),
3126
- /* @__PURE__ */ jsx6(
3451
+ /* @__PURE__ */ jsx7(
3127
3452
  "button",
3128
3453
  {
3129
3454
  type: "button",
@@ -3131,11 +3456,11 @@ function Shell() {
3131
3456
  onClick: () => setNewOpen(true),
3132
3457
  "aria-label": "New session",
3133
3458
  title: "New session \u2325\u2318N",
3134
- children: /* @__PURE__ */ jsx6(PlusIcon, { size: 15 })
3459
+ children: /* @__PURE__ */ jsx7(PlusIcon, { size: 15 })
3135
3460
  }
3136
3461
  )
3137
- ] }) : /* @__PURE__ */ jsxs6(Fragment4, { children: [
3138
- /* @__PURE__ */ jsx6(
3462
+ ] }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
3463
+ /* @__PURE__ */ jsx7(
3139
3464
  Sidebar,
3140
3465
  {
3141
3466
  selection,
@@ -3145,14 +3470,14 @@ function Shell() {
3145
3470
  width: layout.width,
3146
3471
  searchRef,
3147
3472
  onFound: (d) => setFound((f) => ({ ...f, [`${d.provider}:${d.providerSessionId}`]: d })),
3148
- footer: /* @__PURE__ */ jsx6(
3473
+ footer: /* @__PURE__ */ jsx7(
3149
3474
  ProvidersFooter,
3150
3475
  {
3151
3476
  theme,
3152
3477
  setTheme,
3153
- extra: /* @__PURE__ */ jsxs6(Fragment4, { children: [
3154
- /* @__PURE__ */ jsx6(NotifyToggle, {}),
3155
- /* @__PURE__ */ jsx6(
3478
+ extra: /* @__PURE__ */ jsxs7(Fragment5, { children: [
3479
+ /* @__PURE__ */ jsx7(NotifyToggle, {}),
3480
+ /* @__PURE__ */ jsx7(
3156
3481
  "button",
3157
3482
  {
3158
3483
  type: "button",
@@ -3160,7 +3485,7 @@ function Shell() {
3160
3485
  onClick: () => setShortcutsOpen(true),
3161
3486
  "aria-label": "Keyboard shortcuts (\u2318/)",
3162
3487
  title: "Keyboard shortcuts \u2318/",
3163
- children: /* @__PURE__ */ jsx6(KeyboardIcon, { size: 14 })
3488
+ children: /* @__PURE__ */ jsx7(KeyboardIcon, { size: 14 })
3164
3489
  }
3165
3490
  )
3166
3491
  ] })
@@ -3168,11 +3493,11 @@ function Shell() {
3168
3493
  )
3169
3494
  }
3170
3495
  ),
3171
- /* @__PURE__ */ jsx6(Resizer, { width: layout.width, setWidth: layout.setWidth })
3496
+ /* @__PURE__ */ jsx7(Resizer, { width: layout.width, setWidth: layout.setWidth })
3172
3497
  ] }),
3173
- /* @__PURE__ */ jsx6("main", { className: "flex min-w-0 flex-1", children: main })
3498
+ /* @__PURE__ */ jsx7("main", { className: "flex min-w-0 flex-1", children: main })
3174
3499
  ] }),
3175
- /* @__PURE__ */ jsx6(
3500
+ /* @__PURE__ */ jsx7(
3176
3501
  NewSessionDialog,
3177
3502
  {
3178
3503
  open: newOpen,
@@ -3183,12 +3508,12 @@ function Shell() {
3183
3508
  }
3184
3509
  }
3185
3510
  ),
3186
- /* @__PURE__ */ jsx6(ShortcutsDialog, { open: shortcutsOpen, onOpenChange: setShortcutsOpen }),
3187
- /* @__PURE__ */ jsx6(Toast, { text: toast })
3511
+ /* @__PURE__ */ jsx7(ShortcutsDialog, { open: shortcutsOpen, onOpenChange: setShortcutsOpen }),
3512
+ /* @__PURE__ */ jsx7(Toast, { text: toast })
3188
3513
  ] }) });
3189
3514
  }
3190
3515
  function CodingSessionsApp({ transport }) {
3191
- return /* @__PURE__ */ jsx6(CodingSessionsProvider, { transport, children: /* @__PURE__ */ jsx6(Shell, {}) });
3516
+ return /* @__PURE__ */ jsx7(CodingSessionsProvider, { transport, children: /* @__PURE__ */ jsx7(Shell, {}) });
3192
3517
  }
3193
3518
  export {
3194
3519
  CodingSessionsApp,