@ai-matrx/coding-sessions 0.1.83 → 0.1.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/engine/index.cjs +656 -126
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +4 -1
- package/dist/engine/index.d.ts +4 -1
- package/dist/engine/index.js +654 -126
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/worker.js +7 -5
- package/dist/engine/worker.js.map +1 -1
- package/dist/{index-DQ0teQvw.d.cts → index-aavbdzSo.d.cts} +161 -1
- package/dist/{index-DQ0teQvw.d.ts → index-aavbdzSo.d.ts} +161 -1
- package/dist/index.cjs +16 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -1
- package/dist/index.d.ts +112 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +821 -412
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +113 -8
- package/dist/react/index.d.ts +113 -8
- package/dist/react/index.js +851 -418
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +720 -141
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +5 -1
- package/dist/server/index.d.ts +5 -1
- package/dist/server/index.js +719 -140
- package/dist/server/index.js.map +1 -1
- package/dist/ui/assets/index-XIcCZr8A.js +71 -0
- package/dist/ui/assets/index-eqe0sxR4.css +2 -0
- package/dist/ui/index.html +2 -2
- package/package.json +3 -1
- package/dist/ui/assets/index-C-_1qjy9.css +0 -2
- package/dist/ui/assets/index-CmFgFvLa.js +0 -69
package/dist/react/index.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
import {
|
|
5
5
|
useCallback as useCallback2,
|
|
6
6
|
useContext as useContext3,
|
|
7
|
-
useEffect as
|
|
8
|
-
useMemo as
|
|
9
|
-
useRef as
|
|
10
|
-
useState as
|
|
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,19 +16,19 @@ 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
|
|
20
|
-
Dialog,
|
|
21
|
-
DropdownMenu as
|
|
22
|
-
DropdownMenuContent as
|
|
23
|
-
DropdownMenuTrigger as
|
|
24
|
-
DialogContent,
|
|
19
|
+
Button as Button3,
|
|
20
|
+
Dialog as Dialog2,
|
|
21
|
+
DropdownMenu as DropdownMenu3,
|
|
22
|
+
DropdownMenuContent as DropdownMenuContent3,
|
|
23
|
+
DropdownMenuTrigger as DropdownMenuTrigger3,
|
|
24
|
+
DialogContent as DialogContent2,
|
|
25
25
|
DialogDescription,
|
|
26
|
-
DialogFooter,
|
|
27
|
-
DialogHeader,
|
|
28
|
-
DialogTitle,
|
|
29
|
-
Input,
|
|
30
|
-
Textarea,
|
|
31
|
-
cn as
|
|
26
|
+
DialogFooter as DialogFooter2,
|
|
27
|
+
DialogHeader as DialogHeader2,
|
|
28
|
+
DialogTitle as DialogTitle2,
|
|
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
|
|
|
@@ -489,14 +489,20 @@ var SpinnerIcon = ({ size = 16, className }) => /* @__PURE__ */ jsxs(
|
|
|
489
489
|
]
|
|
490
490
|
}
|
|
491
491
|
);
|
|
492
|
-
|
|
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 }) {
|
|
493
495
|
return /* @__PURE__ */ jsx(
|
|
494
|
-
"
|
|
496
|
+
"svg",
|
|
495
497
|
{
|
|
496
498
|
className: `cs-provider-mark cs-provider-mark--${provider}`,
|
|
497
|
-
|
|
499
|
+
width: size,
|
|
500
|
+
height: size,
|
|
501
|
+
viewBox: "0 0 24 24",
|
|
502
|
+
fill: "currentColor",
|
|
498
503
|
"aria-hidden": "true",
|
|
499
|
-
|
|
504
|
+
"data-provider-mark": provider,
|
|
505
|
+
children: /* @__PURE__ */ jsx("path", { d: provider === "claude" ? CLAUDE_MARK : OPENAI_MARK })
|
|
500
506
|
}
|
|
501
507
|
);
|
|
502
508
|
}
|
|
@@ -893,24 +899,392 @@ function ModelPicker(props) {
|
|
|
893
899
|
] });
|
|
894
900
|
}
|
|
895
901
|
|
|
896
|
-
// src/react/
|
|
897
|
-
import {
|
|
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";
|
|
898
910
|
import {
|
|
899
911
|
Button,
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
912
|
+
Dialog,
|
|
913
|
+
DialogContent,
|
|
914
|
+
DialogFooter,
|
|
915
|
+
DialogHeader,
|
|
916
|
+
DialogTitle,
|
|
903
917
|
DropdownMenu,
|
|
904
918
|
DropdownMenuContent,
|
|
905
919
|
DropdownMenuItem as DropdownMenuItem2,
|
|
906
920
|
DropdownMenuLabel,
|
|
907
|
-
DropdownMenuRadioGroup,
|
|
908
|
-
DropdownMenuRadioItem,
|
|
909
921
|
DropdownMenuSeparator as DropdownMenuSeparator2,
|
|
910
922
|
DropdownMenuTrigger,
|
|
923
|
+
Input,
|
|
924
|
+
Select,
|
|
925
|
+
SelectContent,
|
|
926
|
+
SelectItem,
|
|
927
|
+
SelectTrigger,
|
|
928
|
+
SelectValue,
|
|
929
|
+
Textarea,
|
|
930
|
+
TooltipProvider,
|
|
911
931
|
cn as cn3
|
|
912
932
|
} from "@ai-matrx/design-system";
|
|
913
933
|
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
934
|
+
var SIGNED_OUT_AGENTS = "Sign in to AI Matrx to use your agents";
|
|
935
|
+
var LATEST = "latest";
|
|
936
|
+
function bridgedClient(transport) {
|
|
937
|
+
const call = (request) => {
|
|
938
|
+
const run = () => transport.call("agentCatalogRpc", request).then((result) => ({
|
|
939
|
+
data: result.data,
|
|
940
|
+
error: result.error ? {
|
|
941
|
+
message: result.error.message,
|
|
942
|
+
...result.error.code ? { code: result.error.code } : {},
|
|
943
|
+
details: result.error.details ?? null,
|
|
944
|
+
hint: result.error.hint ?? null
|
|
945
|
+
} : null,
|
|
946
|
+
count: result.count ?? null
|
|
947
|
+
}));
|
|
948
|
+
return {
|
|
949
|
+
then: (onOk, onErr) => run().then(onOk, onErr),
|
|
950
|
+
range: (from, to) => call({ ...request, range: [from, to] }),
|
|
951
|
+
order: (column, options) => call({ ...request, order: { column, ascending: options?.ascending !== false } })
|
|
952
|
+
};
|
|
953
|
+
};
|
|
954
|
+
return {
|
|
955
|
+
rpc: (fn, args, options) => call({ fn, ...args ? { args } : {}, ...options?.count ? { count: options.count } : {} })
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
function useAgentAccess(transport, open) {
|
|
959
|
+
const [access, setAccess] = useState4(null);
|
|
960
|
+
useEffect2(() => {
|
|
961
|
+
if (!open) return;
|
|
962
|
+
let alive = true;
|
|
963
|
+
transport.call("agentAccess").then((next) => alive && setAccess(next)).catch(() => alive && setAccess({ signedIn: false, userId: null, organizationId: null, configured: false }));
|
|
964
|
+
return () => {
|
|
965
|
+
alive = false;
|
|
966
|
+
};
|
|
967
|
+
}, [transport, open]);
|
|
968
|
+
return access;
|
|
969
|
+
}
|
|
970
|
+
function useCatalog(transport, userId, onError) {
|
|
971
|
+
const report = useRef(onError);
|
|
972
|
+
report.current = onError;
|
|
973
|
+
return useMemo2(() => {
|
|
974
|
+
if (!userId) return null;
|
|
975
|
+
return createAgentCatalog({
|
|
976
|
+
client: bridgedClient(transport),
|
|
977
|
+
identity: { requireUserId: () => userId, getUserId: () => userId },
|
|
978
|
+
catalogId: `coding-sessions:${userId}`,
|
|
979
|
+
// A failed catalogue read shows at the field, never only in the console.
|
|
980
|
+
errorSink: (event) => {
|
|
981
|
+
console.error(`[coding-sessions] agent catalogue: ${event.code}: ${event.message}`);
|
|
982
|
+
if (event.code === "list_read_failed") report.current("Couldn't load your agents. Reopen to retry.");
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
}, [transport, userId]);
|
|
986
|
+
}
|
|
987
|
+
function asRunInputVariables(defs) {
|
|
988
|
+
return defs.flatMap((def) => typeof def.name === "string" ? [def] : []);
|
|
989
|
+
}
|
|
990
|
+
function AgentField(props) {
|
|
991
|
+
const access = useAgentAccess(props.transport, props.open);
|
|
992
|
+
const [details, setDetails] = useState4(null);
|
|
993
|
+
const [problem, setProblem] = useState4(null);
|
|
994
|
+
const catalog = useCatalog(props.transport, access?.signedIn ? access.userId : null, setProblem);
|
|
995
|
+
const agentId = props.value?.agentId ?? null;
|
|
996
|
+
useEffect2(() => {
|
|
997
|
+
setDetails(null);
|
|
998
|
+
setProblem(null);
|
|
999
|
+
if (!agentId) return;
|
|
1000
|
+
let alive = true;
|
|
1001
|
+
props.transport.call("agentDetails", agentId).then((next) => alive && setDetails(next)).catch((error) => alive && setProblem(error instanceof Error ? error.message : String(error)));
|
|
1002
|
+
return () => {
|
|
1003
|
+
alive = false;
|
|
1004
|
+
};
|
|
1005
|
+
}, [agentId, props.transport]);
|
|
1006
|
+
const { onDetails } = props;
|
|
1007
|
+
useEffect2(() => {
|
|
1008
|
+
onDetails?.(details);
|
|
1009
|
+
}, [details, onDetails]);
|
|
1010
|
+
const inputs = useMemo2(() => deriveRunInputs(asRunInputVariables(details?.variables ?? []), humanizeContextKey), [details]);
|
|
1011
|
+
if (access === null) return /* @__PURE__ */ jsx5("div", { className: "cs-skeleton h-9 rounded-lg" });
|
|
1012
|
+
if (!access.signedIn || !catalog) {
|
|
1013
|
+
return /* @__PURE__ */ jsx5("p", { className: "text-[12.5px] text-muted-foreground", children: SIGNED_OUT_AGENTS });
|
|
1014
|
+
}
|
|
1015
|
+
const setVariable = (name, value) => {
|
|
1016
|
+
if (!props.value) return;
|
|
1017
|
+
props.onChange({ ...props.value, variables: { ...props.value.variables ?? {}, [name]: value } });
|
|
1018
|
+
};
|
|
1019
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-3", children: [
|
|
1020
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
1021
|
+
/* @__PURE__ */ jsx5(TooltipProvider, { children: /* @__PURE__ */ jsx5(AgentCatalogProvider, { catalog, children: /* @__PURE__ */ jsx5(
|
|
1022
|
+
AgentListDropdown,
|
|
1023
|
+
{
|
|
1024
|
+
consumerId: "coding-sessions-new-session",
|
|
1025
|
+
activeAgentId: agentId,
|
|
1026
|
+
label: details?.name ?? (agentId ? "Loading\u2026" : "None"),
|
|
1027
|
+
onSelect: (id) => props.onChange({ agentId: id, versionId: null, variables: {} })
|
|
1028
|
+
}
|
|
1029
|
+
) }) }),
|
|
1030
|
+
agentId ? /* @__PURE__ */ jsx5(Button, { type: "button", size: "sm", variant: "ghost", onClick: () => props.onChange(null), children: "Remove" }) : null
|
|
1031
|
+
] }),
|
|
1032
|
+
problem ? /* @__PURE__ */ jsx5("p", { className: "text-[12px] text-destructive", children: problem }) : null,
|
|
1033
|
+
details && props.value ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1034
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
1035
|
+
/* @__PURE__ */ jsx5("span", { className: "w-[72px] shrink-0 text-[12px] text-muted-foreground", children: "Version" }),
|
|
1036
|
+
/* @__PURE__ */ jsxs5(
|
|
1037
|
+
Select,
|
|
1038
|
+
{
|
|
1039
|
+
value: props.value.versionId ?? LATEST,
|
|
1040
|
+
onValueChange: (next) => props.value && props.onChange({ ...props.value, versionId: next === LATEST ? null : next }),
|
|
1041
|
+
children: [
|
|
1042
|
+
/* @__PURE__ */ jsx5(SelectTrigger, { className: "h-8 w-[200px] text-[12.5px]", "aria-label": "Agent version", children: /* @__PURE__ */ jsx5(SelectValue, {}) }),
|
|
1043
|
+
/* @__PURE__ */ jsxs5(SelectContent, { children: [
|
|
1044
|
+
/* @__PURE__ */ jsx5(SelectItem, { value: LATEST, children: details.latestVersionNumber !== null ? `Latest (v${details.latestVersionNumber})` : "Latest" }),
|
|
1045
|
+
details.versions.map((v) => /* @__PURE__ */ jsxs5(SelectItem, { value: v.id, children: [
|
|
1046
|
+
"v",
|
|
1047
|
+
v.versionNumber
|
|
1048
|
+
] }, v.id))
|
|
1049
|
+
] })
|
|
1050
|
+
]
|
|
1051
|
+
}
|
|
1052
|
+
)
|
|
1053
|
+
] }),
|
|
1054
|
+
inputs.map((input) => {
|
|
1055
|
+
const raw = props.value?.variables?.[input.name];
|
|
1056
|
+
const value = typeof raw === "string" ? raw : "";
|
|
1057
|
+
const id = `cs-agent-var-${input.name}`;
|
|
1058
|
+
const invalid = props.missing === input.name;
|
|
1059
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-1", children: [
|
|
1060
|
+
/* @__PURE__ */ jsxs5("label", { htmlFor: id, className: "text-[12px] font-medium", children: [
|
|
1061
|
+
input.label,
|
|
1062
|
+
input.required ? /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground", children: " \xB7 required" }) : null
|
|
1063
|
+
] }),
|
|
1064
|
+
input.options && input.options.length > 0 ? /* @__PURE__ */ jsxs5(Select, { value, onValueChange: (next) => setVariable(input.name, next), children: [
|
|
1065
|
+
/* @__PURE__ */ jsx5(SelectTrigger, { id, className: "h-8 text-[12.5px]", "aria-invalid": invalid || void 0, children: /* @__PURE__ */ jsx5(SelectValue, { placeholder: "Choose\u2026" }) }),
|
|
1066
|
+
/* @__PURE__ */ jsx5(SelectContent, { children: input.options.map((option) => /* @__PURE__ */ jsx5(SelectItem, { value: option, children: option }, option)) })
|
|
1067
|
+
] }) : input.variable.customComponent?.type === "textarea" ? /* @__PURE__ */ jsx5(
|
|
1068
|
+
Textarea,
|
|
1069
|
+
{
|
|
1070
|
+
id,
|
|
1071
|
+
rows: 2,
|
|
1072
|
+
value,
|
|
1073
|
+
onChange: (e) => setVariable(input.name, e.target.value),
|
|
1074
|
+
placeholder: input.hint ?? "",
|
|
1075
|
+
"aria-invalid": invalid || void 0
|
|
1076
|
+
}
|
|
1077
|
+
) : /* @__PURE__ */ jsx5(
|
|
1078
|
+
Input,
|
|
1079
|
+
{
|
|
1080
|
+
id,
|
|
1081
|
+
value,
|
|
1082
|
+
onChange: (e) => setVariable(input.name, e.target.value),
|
|
1083
|
+
placeholder: input.hint ?? "",
|
|
1084
|
+
"aria-invalid": invalid || void 0
|
|
1085
|
+
}
|
|
1086
|
+
),
|
|
1087
|
+
invalid ? /* @__PURE__ */ jsx5("p", { className: "text-[12px] text-destructive", children: "Fill this in to use the agent" }) : null
|
|
1088
|
+
] }, input.name);
|
|
1089
|
+
})
|
|
1090
|
+
] }) : null
|
|
1091
|
+
] });
|
|
1092
|
+
}
|
|
1093
|
+
function missingRequiredVariable(details, selection) {
|
|
1094
|
+
if (!details || !selection) return null;
|
|
1095
|
+
for (const input of deriveRunInputs(asRunInputVariables(details.variables), humanizeContextKey)) {
|
|
1096
|
+
if (!input.required) continue;
|
|
1097
|
+
const value = selection.variables?.[input.name];
|
|
1098
|
+
if (typeof value !== "string" || !value.trim()) return input.name;
|
|
1099
|
+
}
|
|
1100
|
+
return null;
|
|
1101
|
+
}
|
|
1102
|
+
var PART_LABEL = {
|
|
1103
|
+
instructions: "Instructions",
|
|
1104
|
+
skills: "Skills",
|
|
1105
|
+
tools: "Tools"
|
|
1106
|
+
};
|
|
1107
|
+
function agentChipText(agent) {
|
|
1108
|
+
const parts = agent.loaded.map(
|
|
1109
|
+
(part) => part.part === "instructions" ? `${PART_LABEL.instructions} ${part.loaded === 1 ? "\u2713" : "\u2014"}` : `${PART_LABEL[part.part]} ${part.loaded}/${part.total}`
|
|
1110
|
+
);
|
|
1111
|
+
return `${agent.name}${agent.versionNumber !== null ? ` v${agent.versionNumber}` : ""} \xB7 ${parts.join(" \xB7 ")}`;
|
|
1112
|
+
}
|
|
1113
|
+
function AgentMenu(props) {
|
|
1114
|
+
const { agent } = props;
|
|
1115
|
+
const show = useToastShow();
|
|
1116
|
+
const [open, setOpen] = useState4(false);
|
|
1117
|
+
const [choosing, setChoosing] = useState4(false);
|
|
1118
|
+
const [latest, setLatest] = useState4(null);
|
|
1119
|
+
const [access, setAccess] = useState4(null);
|
|
1120
|
+
useEffect2(() => {
|
|
1121
|
+
if (!open) return;
|
|
1122
|
+
let alive = true;
|
|
1123
|
+
void props.transport.call("agentAccess").then((next) => alive && setAccess(next)).catch(() => void 0);
|
|
1124
|
+
if (agent) {
|
|
1125
|
+
props.transport.call("agentDetails", agent.agentId).then((d) => {
|
|
1126
|
+
if (alive && d.latestVersionId && d.latestVersionNumber !== null) setLatest({ id: d.latestVersionId, number: d.latestVersionNumber });
|
|
1127
|
+
}).catch(() => void 0);
|
|
1128
|
+
}
|
|
1129
|
+
return () => {
|
|
1130
|
+
alive = false;
|
|
1131
|
+
};
|
|
1132
|
+
}, [open, agent, props.transport]);
|
|
1133
|
+
const apply = async (selection, done) => {
|
|
1134
|
+
try {
|
|
1135
|
+
await props.transport.call("setAgent", props.sessionId, selection);
|
|
1136
|
+
show(done);
|
|
1137
|
+
props.onChange();
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
show(`That didn't change: ${error instanceof Error ? error.message : String(error)}`);
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
const behind = agent && latest && agent.versionNumber !== null && latest.number > agent.versionNumber ? latest : null;
|
|
1143
|
+
const complete = agent ? agent.loaded.every((part) => part.loaded === part.total) : true;
|
|
1144
|
+
const signedIn = access?.signedIn ?? false;
|
|
1145
|
+
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1146
|
+
/* @__PURE__ */ jsxs5(DropdownMenu, { open, onOpenChange: setOpen, children: [
|
|
1147
|
+
/* @__PURE__ */ jsx5(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
|
|
1148
|
+
"button",
|
|
1149
|
+
{
|
|
1150
|
+
type: "button",
|
|
1151
|
+
className: cn3("cs-agent-chip", agent ? "cs-agent-chip--set" : "cs-agent-chip--none", !complete && "cs-agent-chip--partial"),
|
|
1152
|
+
"data-testid": "cs-agent-chip",
|
|
1153
|
+
"aria-label": agent ? `AI Matrx agent: ${agent.name}` : "Add an AI Matrx agent",
|
|
1154
|
+
children: [
|
|
1155
|
+
agent ? agentChipText(agent) : "No agent",
|
|
1156
|
+
behind ? /* @__PURE__ */ jsx5("span", { className: "cs-agent-chip-dot", "aria-label": "Update available" }) : null,
|
|
1157
|
+
/* @__PURE__ */ jsx5(ChevronDownIcon, { size: 12, className: "ml-1 inline shrink-0" })
|
|
1158
|
+
]
|
|
1159
|
+
}
|
|
1160
|
+
) }),
|
|
1161
|
+
/* @__PURE__ */ jsxs5(DropdownMenuContent, { align: "end", className: "w-[320px]", children: [
|
|
1162
|
+
agent ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1163
|
+
/* @__PURE__ */ jsxs5(DropdownMenuLabel, { className: "truncate", children: [
|
|
1164
|
+
agent.name,
|
|
1165
|
+
agent.versionNumber !== null ? ` \xB7 v${agent.versionNumber}` : ""
|
|
1166
|
+
] }),
|
|
1167
|
+
/* @__PURE__ */ jsxs5("div", { className: "cs-agent-parts", children: [
|
|
1168
|
+
agent.blockDue ? /* @__PURE__ */ jsx5("p", { className: "text-[12px] text-muted-foreground", children: "Sent with your next message" }) : null,
|
|
1169
|
+
/* @__PURE__ */ jsx5(AgentPartList, { title: "Skills", items: agent.skills ?? [] }),
|
|
1170
|
+
/* @__PURE__ */ jsx5(AgentPartList, { title: "Tools", items: agent.tools ?? [] }),
|
|
1171
|
+
agent.unavailable.length > 0 ? /* @__PURE__ */ jsx5(
|
|
1172
|
+
AgentPartList,
|
|
1173
|
+
{
|
|
1174
|
+
title: "Not loaded",
|
|
1175
|
+
items: agent.unavailable.map((u) => `${u.name} \u2014 ${u.reason}`)
|
|
1176
|
+
}
|
|
1177
|
+
) : null
|
|
1178
|
+
] }),
|
|
1179
|
+
/* @__PURE__ */ jsx5(DropdownMenuSeparator2, {})
|
|
1180
|
+
] }) : null,
|
|
1181
|
+
signedIn ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1182
|
+
behind && agent ? /* @__PURE__ */ jsxs5(
|
|
1183
|
+
DropdownMenuItem2,
|
|
1184
|
+
{
|
|
1185
|
+
onSelect: () => void apply(
|
|
1186
|
+
{ agentId: agent.agentId, versionId: behind.id, variables: agent.variables ?? {} },
|
|
1187
|
+
`The next message uses ${agent.name} v${behind.number}.`
|
|
1188
|
+
),
|
|
1189
|
+
children: [
|
|
1190
|
+
"Update to v",
|
|
1191
|
+
behind.number
|
|
1192
|
+
]
|
|
1193
|
+
}
|
|
1194
|
+
) : null,
|
|
1195
|
+
/* @__PURE__ */ jsx5(DropdownMenuItem2, { onSelect: () => setChoosing(true), children: agent ? "Change agent\u2026" : "Choose agent\u2026" }),
|
|
1196
|
+
agent ? /* @__PURE__ */ jsx5(DropdownMenuItem2, { onSelect: () => void apply(null, "The next message runs without an agent."), children: "Remove agent" }) : null
|
|
1197
|
+
] }) : access ? /* @__PURE__ */ jsx5("p", { className: "px-2 py-1.5 text-[12px] text-muted-foreground", children: SIGNED_OUT_AGENTS }) : null
|
|
1198
|
+
] })
|
|
1199
|
+
] }),
|
|
1200
|
+
/* @__PURE__ */ jsx5(
|
|
1201
|
+
ChooseAgentDialog,
|
|
1202
|
+
{
|
|
1203
|
+
transport: props.transport,
|
|
1204
|
+
open: choosing,
|
|
1205
|
+
onOpenChange: setChoosing,
|
|
1206
|
+
title: agent ? "Change agent" : "Choose an agent",
|
|
1207
|
+
action: "Use this agent",
|
|
1208
|
+
onConfirm: (selection) => apply(selection, "The next message uses the new agent.")
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
] });
|
|
1212
|
+
}
|
|
1213
|
+
function AgentPartList({ title, items }) {
|
|
1214
|
+
return /* @__PURE__ */ jsxs5("div", { children: [
|
|
1215
|
+
/* @__PURE__ */ jsxs5("p", { className: "text-[11.5px] font-medium text-muted-foreground", children: [
|
|
1216
|
+
title,
|
|
1217
|
+
" \xB7 ",
|
|
1218
|
+
items.length
|
|
1219
|
+
] }),
|
|
1220
|
+
items.length > 0 ? /* @__PURE__ */ jsx5("ul", { className: "cs-agent-part-list", children: items.map((item) => /* @__PURE__ */ jsx5("li", { className: "truncate", title: item, children: item }, item)) }) : null
|
|
1221
|
+
] });
|
|
1222
|
+
}
|
|
1223
|
+
function ChooseAgentDialog(props) {
|
|
1224
|
+
const [value, setValue] = useState4(null);
|
|
1225
|
+
const [details, setDetails] = useState4(null);
|
|
1226
|
+
const [missing, setMissing] = useState4(null);
|
|
1227
|
+
const [busy, setBusy] = useState4(false);
|
|
1228
|
+
useEffect2(() => {
|
|
1229
|
+
if (props.open) {
|
|
1230
|
+
setValue(null);
|
|
1231
|
+
setMissing(null);
|
|
1232
|
+
}
|
|
1233
|
+
}, [props.open]);
|
|
1234
|
+
const confirm = async () => {
|
|
1235
|
+
if (!value) return;
|
|
1236
|
+
const gap = missingRequiredVariable(details, value);
|
|
1237
|
+
setMissing(gap);
|
|
1238
|
+
if (gap) return;
|
|
1239
|
+
setBusy(true);
|
|
1240
|
+
try {
|
|
1241
|
+
await props.onConfirm(value);
|
|
1242
|
+
props.onOpenChange(false);
|
|
1243
|
+
} finally {
|
|
1244
|
+
setBusy(false);
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
return /* @__PURE__ */ jsx5(Dialog, { open: props.open, onOpenChange: props.onOpenChange, children: /* @__PURE__ */ jsxs5(DialogContent, { className: "max-w-[480px]", children: [
|
|
1248
|
+
/* @__PURE__ */ jsx5(DialogHeader, { children: /* @__PURE__ */ jsx5(DialogTitle, { children: props.title }) }),
|
|
1249
|
+
/* @__PURE__ */ jsx5(
|
|
1250
|
+
AgentField,
|
|
1251
|
+
{
|
|
1252
|
+
transport: props.transport,
|
|
1253
|
+
open: props.open,
|
|
1254
|
+
value,
|
|
1255
|
+
onChange: (next) => {
|
|
1256
|
+
setValue(next);
|
|
1257
|
+
setMissing(null);
|
|
1258
|
+
},
|
|
1259
|
+
missing,
|
|
1260
|
+
onDetails: setDetails
|
|
1261
|
+
}
|
|
1262
|
+
),
|
|
1263
|
+
/* @__PURE__ */ jsxs5(DialogFooter, { children: [
|
|
1264
|
+
/* @__PURE__ */ jsx5(Button, { type: "button", variant: "ghost", onClick: () => props.onOpenChange(false), children: "Cancel" }),
|
|
1265
|
+
/* @__PURE__ */ jsx5(Button, { type: "button", disabled: !value || busy, onClick: () => void confirm(), children: props.action })
|
|
1266
|
+
] })
|
|
1267
|
+
] }) });
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// src/react/sidebar.tsx
|
|
1271
|
+
import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState5 } from "react";
|
|
1272
|
+
import {
|
|
1273
|
+
Button as Button2,
|
|
1274
|
+
ContextMenu,
|
|
1275
|
+
ContextMenuContent,
|
|
1276
|
+
ContextMenuTrigger,
|
|
1277
|
+
DropdownMenu as DropdownMenu2,
|
|
1278
|
+
DropdownMenuContent as DropdownMenuContent2,
|
|
1279
|
+
DropdownMenuItem as DropdownMenuItem3,
|
|
1280
|
+
DropdownMenuLabel as DropdownMenuLabel2,
|
|
1281
|
+
DropdownMenuRadioGroup,
|
|
1282
|
+
DropdownMenuRadioItem,
|
|
1283
|
+
DropdownMenuSeparator as DropdownMenuSeparator3,
|
|
1284
|
+
DropdownMenuTrigger as DropdownMenuTrigger2,
|
|
1285
|
+
cn as cn4
|
|
1286
|
+
} from "@ai-matrx/design-system";
|
|
1287
|
+
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
914
1288
|
function readLocal(key, allowed, fallback) {
|
|
915
1289
|
try {
|
|
916
1290
|
const value = localStorage.getItem(key);
|
|
@@ -926,23 +1300,23 @@ function writeLocal(key, value) {
|
|
|
926
1300
|
}
|
|
927
1301
|
}
|
|
928
1302
|
function SectionLabel({ children, action }) {
|
|
929
|
-
return /* @__PURE__ */
|
|
930
|
-
/* @__PURE__ */
|
|
1303
|
+
return /* @__PURE__ */ jsxs6("div", { "data-cs-section-label": true, className: "flex h-8 items-center justify-between px-3 pt-3", children: [
|
|
1304
|
+
/* @__PURE__ */ jsx6("span", { className: "text-[12px] font-medium text-muted-foreground", children }),
|
|
931
1305
|
action
|
|
932
1306
|
] });
|
|
933
1307
|
}
|
|
934
1308
|
function GroupLabel({ children }) {
|
|
935
|
-
return /* @__PURE__ */
|
|
1309
|
+
return /* @__PURE__ */ jsx6("div", { className: "truncate px-4 pb-0.5 pt-2.5 text-[12px] font-medium text-muted-foreground", children });
|
|
936
1310
|
}
|
|
937
1311
|
function RenameInput(props) {
|
|
938
|
-
const [value, setValue] =
|
|
939
|
-
const done =
|
|
1312
|
+
const [value, setValue] = useState5(props.initial);
|
|
1313
|
+
const done = useRef2(false);
|
|
940
1314
|
const finish = (title) => {
|
|
941
1315
|
if (done.current) return;
|
|
942
1316
|
done.current = true;
|
|
943
1317
|
props.onDone(title);
|
|
944
1318
|
};
|
|
945
|
-
return /* @__PURE__ */
|
|
1319
|
+
return /* @__PURE__ */ jsx6(
|
|
946
1320
|
"input",
|
|
947
1321
|
{
|
|
948
1322
|
autoFocus: true,
|
|
@@ -959,11 +1333,16 @@ function RenameInput(props) {
|
|
|
959
1333
|
}
|
|
960
1334
|
);
|
|
961
1335
|
}
|
|
1336
|
+
function entryTarget(entry) {
|
|
1337
|
+
if (entry.kind === "session" && entry.session) return `#s/${entry.session.id}`;
|
|
1338
|
+
if (entry.providerSessionId) return `#d/${entry.provider}/${entry.providerSessionId}`;
|
|
1339
|
+
return "";
|
|
1340
|
+
}
|
|
962
1341
|
function Row(props) {
|
|
963
1342
|
const client = useCodingSessionsClient();
|
|
964
1343
|
const show = useToastShow();
|
|
965
|
-
const [renaming, setRenaming] =
|
|
966
|
-
const [menuOpen, setMenuOpen] =
|
|
1344
|
+
const [renaming, setRenaming] = useState5(false);
|
|
1345
|
+
const [menuOpen, setMenuOpen] = useState5(false);
|
|
967
1346
|
const { entry } = props;
|
|
968
1347
|
const rename = (title) => {
|
|
969
1348
|
setRenaming(false);
|
|
@@ -973,14 +1352,20 @@ function Row(props) {
|
|
|
973
1352
|
(error) => show(`The new name didn't save: ${error instanceof Error ? error.message : String(error)}`)
|
|
974
1353
|
);
|
|
975
1354
|
};
|
|
976
|
-
return /* @__PURE__ */
|
|
977
|
-
/* @__PURE__ */
|
|
1355
|
+
return /* @__PURE__ */ jsxs6(ContextMenu, { children: [
|
|
1356
|
+
/* @__PURE__ */ jsx6(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
|
|
978
1357
|
"div",
|
|
979
1358
|
{
|
|
980
|
-
className:
|
|
1359
|
+
className: cn4("cs-row group", props.active && "cs-row--active", menuOpen && "cs-row--menu"),
|
|
981
1360
|
"data-hidden": entry.hidden || void 0,
|
|
1361
|
+
"data-cs-row": entry.key,
|
|
1362
|
+
"data-cs-target": entryTarget(entry),
|
|
1363
|
+
"data-cs-provider": entry.provider,
|
|
1364
|
+
"data-cs-title": entry.title,
|
|
1365
|
+
"data-cs-live": props.live ? "true" : void 0,
|
|
1366
|
+
"data-cs-active": props.active ? "true" : void 0,
|
|
982
1367
|
children: [
|
|
983
|
-
/* @__PURE__ */
|
|
1368
|
+
/* @__PURE__ */ jsx6(
|
|
984
1369
|
"button",
|
|
985
1370
|
{
|
|
986
1371
|
type: "button",
|
|
@@ -992,39 +1377,39 @@ function Row(props) {
|
|
|
992
1377
|
(${entry.originalTitle})` : entry.title
|
|
993
1378
|
}
|
|
994
1379
|
),
|
|
995
|
-
/* @__PURE__ */
|
|
996
|
-
/* @__PURE__ */
|
|
997
|
-
renaming ? /* @__PURE__ */
|
|
998
|
-
/* @__PURE__ */
|
|
999
|
-
entry.pinned ? /* @__PURE__ */
|
|
1380
|
+
/* @__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 }) }),
|
|
1381
|
+
/* @__PURE__ */ jsxs6("span", { className: "cs-row__body", children: [
|
|
1382
|
+
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: [
|
|
1383
|
+
/* @__PURE__ */ jsx6("span", { className: "min-w-0 truncate text-[13px] font-medium leading-5", children: entry.title }),
|
|
1384
|
+
entry.pinned ? /* @__PURE__ */ jsx6(PinIcon, { size: 11, className: "shrink-0 text-muted-foreground", "aria-label": "Pinned" }) : null
|
|
1000
1385
|
] }),
|
|
1001
|
-
/* @__PURE__ */
|
|
1002
|
-
props.snippet ? /* @__PURE__ */
|
|
1386
|
+
/* @__PURE__ */ jsx6("span", { className: "block truncate text-[11.5px] leading-4 text-muted-foreground", children: props.meta }),
|
|
1387
|
+
props.snippet ? /* @__PURE__ */ jsx6("span", { className: "cs-row__snippet", children: props.snippet }) : null
|
|
1003
1388
|
] }),
|
|
1004
|
-
renaming ? null : /* @__PURE__ */
|
|
1389
|
+
renaming ? null : /* @__PURE__ */ jsxs6("span", { className: "cs-row__actions", children: [
|
|
1005
1390
|
props.takeover,
|
|
1006
|
-
/* @__PURE__ */
|
|
1007
|
-
/* @__PURE__ */
|
|
1008
|
-
/* @__PURE__ */
|
|
1391
|
+
/* @__PURE__ */ jsxs6(DropdownMenu2, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
1392
|
+
/* @__PURE__ */ jsx6(DropdownMenuTrigger2, { 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 }) }) }),
|
|
1393
|
+
/* @__PURE__ */ jsx6(DropdownMenuContent2, { align: "start", className: "w-60", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx6(ChatMenuItems, { entry, variant: "dropdown", onRename: () => setRenaming(true) }) })
|
|
1009
1394
|
] })
|
|
1010
1395
|
] })
|
|
1011
1396
|
]
|
|
1012
1397
|
}
|
|
1013
1398
|
) }),
|
|
1014
|
-
/* @__PURE__ */
|
|
1399
|
+
/* @__PURE__ */ jsx6(ContextMenuContent, { className: "w-60", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx6(ChatMenuItems, { entry, variant: "context", onRename: () => setRenaming(true) }) })
|
|
1015
1400
|
] });
|
|
1016
1401
|
}
|
|
1017
1402
|
function SidebarSkeleton() {
|
|
1018
|
-
return /* @__PURE__ */
|
|
1403
|
+
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)) });
|
|
1019
1404
|
}
|
|
1020
1405
|
function Highlight({ text, query }) {
|
|
1021
1406
|
const q = query.trim().toLowerCase();
|
|
1022
1407
|
if (!q) return text;
|
|
1023
1408
|
const at = text.toLowerCase().indexOf(q);
|
|
1024
1409
|
if (at < 0) return text;
|
|
1025
|
-
return /* @__PURE__ */
|
|
1410
|
+
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1026
1411
|
text.slice(0, at),
|
|
1027
|
-
/* @__PURE__ */
|
|
1412
|
+
/* @__PURE__ */ jsx6("mark", { className: "cs-mark", children: text.slice(at, at + q.length) }),
|
|
1028
1413
|
text.slice(at + q.length)
|
|
1029
1414
|
] });
|
|
1030
1415
|
}
|
|
@@ -1039,8 +1424,8 @@ var EMPTY_SEARCH = {
|
|
|
1039
1424
|
};
|
|
1040
1425
|
function useContentSearch(query) {
|
|
1041
1426
|
const client = useCodingSessionsClient();
|
|
1042
|
-
const [state, setState] =
|
|
1043
|
-
const latest =
|
|
1427
|
+
const [state, setState] = useState5(EMPTY_SEARCH);
|
|
1428
|
+
const latest = useRef2(query);
|
|
1044
1429
|
latest.current = query;
|
|
1045
1430
|
const run = useCallback(
|
|
1046
1431
|
async (q, cursor, append) => {
|
|
@@ -1064,7 +1449,7 @@ function useContentSearch(query) {
|
|
|
1064
1449
|
},
|
|
1065
1450
|
[client]
|
|
1066
1451
|
);
|
|
1067
|
-
|
|
1452
|
+
useEffect3(() => {
|
|
1068
1453
|
const q = query.trim();
|
|
1069
1454
|
if (q.length < 2) {
|
|
1070
1455
|
setState(EMPTY_SEARCH);
|
|
@@ -1093,19 +1478,19 @@ function Sidebar(props) {
|
|
|
1093
1478
|
const client = useCodingSessionsClient();
|
|
1094
1479
|
const state = useCodingSessionsState();
|
|
1095
1480
|
const now = useMinuteClock();
|
|
1096
|
-
const [query, setQuery] =
|
|
1481
|
+
const [query, setQuery] = useState5("");
|
|
1097
1482
|
const [search, searchMore] = useContentSearch(query);
|
|
1098
|
-
const [groupMode, setGroupMode] =
|
|
1099
|
-
const [showHidden, setShowHidden] =
|
|
1100
|
-
const [takingOver, setTakingOver] =
|
|
1101
|
-
const [takeoverError, setTakeoverError] =
|
|
1483
|
+
const [groupMode, setGroupMode] = useState5(() => readLocal("coding-sessions.group", ["date", "folder"], "date"));
|
|
1484
|
+
const [showHidden, setShowHidden] = useState5(false);
|
|
1485
|
+
const [takingOver, setTakingOver] = useState5(null);
|
|
1486
|
+
const [takeoverError, setTakeoverError] = useState5(null);
|
|
1102
1487
|
const prefs = state.preferences;
|
|
1103
1488
|
const sessions = state.sessions.data;
|
|
1104
1489
|
const isLive = (id) => {
|
|
1105
1490
|
const run = state.runs[id];
|
|
1106
1491
|
return run !== void 0 && !isTerminalRunStatus(run.status);
|
|
1107
1492
|
};
|
|
1108
|
-
const { ours, others, hiddenCount } =
|
|
1493
|
+
const { ours, others, hiddenCount } = useMemo3(() => {
|
|
1109
1494
|
const oursList = sessions.map((s) => sessionEntry(s, prefs));
|
|
1110
1495
|
const known = new Set(sessions.map((s) => s.providerSessionId).filter(Boolean));
|
|
1111
1496
|
const othersList = state.discovered.data.filter((d) => !known.has(d.providerSessionId)).map((d) => discoveredEntry(d, prefs));
|
|
@@ -1145,8 +1530,8 @@ function Sidebar(props) {
|
|
|
1145
1530
|
let meta;
|
|
1146
1531
|
if (live) meta = `${PROVIDER_LABEL[entry.provider]} is working\u2026`;
|
|
1147
1532
|
else if (d?.activeElsewhere)
|
|
1148
|
-
meta = /* @__PURE__ */
|
|
1149
|
-
/* @__PURE__ */
|
|
1533
|
+
meta = /* @__PURE__ */ jsxs6("span", { className: "cs-live-elsewhere", children: [
|
|
1534
|
+
/* @__PURE__ */ jsx6("span", { className: "cs-live-dot", "aria-hidden": "true" }),
|
|
1150
1535
|
"Running in ",
|
|
1151
1536
|
PROVIDER_LABEL[entry.provider]
|
|
1152
1537
|
] });
|
|
@@ -1155,8 +1540,8 @@ function Sidebar(props) {
|
|
|
1155
1540
|
const where = entry.cwd ? prettyPath2(entry.cwd) : "unknown folder";
|
|
1156
1541
|
meta = `${status}${entry.kind === "discovered" ? `${PROVIDER_LABEL[entry.provider]} \xB7 ` : ""}${groupMode === "folder" && !extra ? "" : `${where} \xB7 `}${relativeTime(entry.updatedAt, now)}`;
|
|
1157
1542
|
}
|
|
1158
|
-
return /* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1543
|
+
return /* @__PURE__ */ jsxs6("div", { children: [
|
|
1544
|
+
/* @__PURE__ */ jsx6(
|
|
1160
1545
|
Row,
|
|
1161
1546
|
{
|
|
1162
1547
|
entry,
|
|
@@ -1165,7 +1550,7 @@ function Sidebar(props) {
|
|
|
1165
1550
|
live,
|
|
1166
1551
|
meta,
|
|
1167
1552
|
snippet: extra?.snippet,
|
|
1168
|
-
takeover: d?.cwd ? /* @__PURE__ */
|
|
1553
|
+
takeover: d?.cwd ? /* @__PURE__ */ jsxs6(
|
|
1169
1554
|
"button",
|
|
1170
1555
|
{
|
|
1171
1556
|
type: "button",
|
|
@@ -1174,18 +1559,18 @@ function Sidebar(props) {
|
|
|
1174
1559
|
title: d.activeElsewhere ? d.activeElsewhere.message : "Continue this chat here",
|
|
1175
1560
|
disabled: takingOver === d.providerSessionId,
|
|
1176
1561
|
children: [
|
|
1177
|
-
takingOver === d.providerSessionId ? /* @__PURE__ */
|
|
1562
|
+
takingOver === d.providerSessionId ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 11 }) : null,
|
|
1178
1563
|
"Take over"
|
|
1179
1564
|
]
|
|
1180
1565
|
}
|
|
1181
1566
|
) : null
|
|
1182
1567
|
}
|
|
1183
1568
|
),
|
|
1184
|
-
takeoverError && d && takeoverError.id === d.providerSessionId ? /* @__PURE__ */
|
|
1569
|
+
takeoverError && d && takeoverError.id === d.providerSessionId ? /* @__PURE__ */ jsx6("p", { className: "mx-4 mb-1 text-[11.5px] text-destructive", children: takeoverError.message }) : null
|
|
1185
1570
|
] }, entry.key);
|
|
1186
1571
|
};
|
|
1187
|
-
const renderGroups = (entries) => groupEntries(entries, groupMode, now).map((group) => /* @__PURE__ */
|
|
1188
|
-
/* @__PURE__ */
|
|
1572
|
+
const renderGroups = (entries) => groupEntries(entries, groupMode, now).map((group) => /* @__PURE__ */ jsxs6("div", { role: "group", "aria-label": group.label, children: [
|
|
1573
|
+
/* @__PURE__ */ jsx6(GroupLabel, { children: group.label }),
|
|
1189
1574
|
group.entries.map((e) => renderEntry(e))
|
|
1190
1575
|
] }, group.label));
|
|
1191
1576
|
const searching = query.trim().length > 0;
|
|
@@ -1202,60 +1587,60 @@ function Sidebar(props) {
|
|
|
1202
1587
|
props.onFound(hitToDiscovered(hit));
|
|
1203
1588
|
props.select({ kind: "discovered", provider: hit.provider, id: hit.providerSessionId });
|
|
1204
1589
|
};
|
|
1205
|
-
const searchBody = /* @__PURE__ */
|
|
1206
|
-
/* @__PURE__ */
|
|
1207
|
-
titleMatches.length === 0 ? /* @__PURE__ */
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
query.trim().length < 2 ? /* @__PURE__ */
|
|
1590
|
+
const searchBody = /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1591
|
+
/* @__PURE__ */ jsx6(SectionLabel, { children: "Chats" }),
|
|
1592
|
+
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 })),
|
|
1593
|
+
/* @__PURE__ */ jsx6(SectionLabel, { children: "In conversations" }),
|
|
1594
|
+
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: [
|
|
1210
1595
|
contentHits.map((hit) => {
|
|
1211
1596
|
const known = allByKey.get(chatKey(hit.provider, hit.providerSessionId));
|
|
1212
1597
|
const entry = known ?? discoveredEntry(hitToDiscovered(hit), prefs);
|
|
1213
|
-
return /* @__PURE__ */
|
|
1598
|
+
return /* @__PURE__ */ jsx6("div", { onClickCapture: known ? void 0 : () => props.onFound(hitToDiscovered(hit)), children: renderEntry(entry, {
|
|
1214
1599
|
query,
|
|
1215
|
-
snippet: hit.snippet ? /* @__PURE__ */
|
|
1600
|
+
snippet: hit.snippet ? /* @__PURE__ */ jsx6(Highlight, { text: hit.snippet, query }) : void 0
|
|
1216
1601
|
}) }, `hit:${entry.key}`);
|
|
1217
1602
|
}),
|
|
1218
|
-
/* @__PURE__ */
|
|
1603
|
+
/* @__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: [
|
|
1219
1604
|
"Search stopped: ",
|
|
1220
1605
|
search.error
|
|
1221
|
-
] }) : search.loading ? /* @__PURE__ */
|
|
1222
|
-
/* @__PURE__ */
|
|
1606
|
+
] }) : search.loading ? /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
1607
|
+
/* @__PURE__ */ jsx6(SpinnerIcon, { size: 12 }),
|
|
1223
1608
|
" Searching your chats\u2026"
|
|
1224
|
-
] }) : search.query ? /* @__PURE__ */
|
|
1609
|
+
] }) : search.query ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1225
1610
|
contentHits.length === 0 && search.hits.length === 0 ? "Nothing found. " : null,
|
|
1226
1611
|
search.nextCursor === null ? `Searched all ${search.total.toLocaleString()} chats on this computer.` : `Searched the ${search.scanned.toLocaleString()} most recent of ${search.total.toLocaleString()} chats.`,
|
|
1227
|
-
search.nextCursor !== null ? /* @__PURE__ */
|
|
1612
|
+
search.nextCursor !== null ? /* @__PURE__ */ jsx6("button", { type: "button", className: "cs-link ml-1", onClick: searchMore, children: "Search older chats" }) : null
|
|
1228
1613
|
] }) : null })
|
|
1229
1614
|
] })
|
|
1230
1615
|
] });
|
|
1231
|
-
const listBody = /* @__PURE__ */
|
|
1232
|
-
pinned.length > 0 ? /* @__PURE__ */
|
|
1233
|
-
/* @__PURE__ */
|
|
1616
|
+
const listBody = /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1617
|
+
pinned.length > 0 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1618
|
+
/* @__PURE__ */ jsx6(SectionLabel, { children: "Pinned" }),
|
|
1234
1619
|
pinned.map((e) => renderEntry(e))
|
|
1235
1620
|
] }) : null,
|
|
1236
|
-
running.length > 0 ? /* @__PURE__ */
|
|
1237
|
-
/* @__PURE__ */
|
|
1621
|
+
running.length > 0 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1622
|
+
/* @__PURE__ */ jsx6(SectionLabel, { children: "Running" }),
|
|
1238
1623
|
running.map((e) => renderEntry(e))
|
|
1239
1624
|
] }) : null,
|
|
1240
|
-
/* @__PURE__ */
|
|
1241
|
-
state.sessions.loading && state.sessions.loadedAt === null ? /* @__PURE__ */
|
|
1242
|
-
/* @__PURE__ */
|
|
1625
|
+
/* @__PURE__ */ jsx6(SectionLabel, { children: "Recent" }),
|
|
1626
|
+
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)),
|
|
1627
|
+
/* @__PURE__ */ jsx6(
|
|
1243
1628
|
SectionLabel,
|
|
1244
1629
|
{
|
|
1245
|
-
action: /* @__PURE__ */
|
|
1246
|
-
/* @__PURE__ */
|
|
1247
|
-
/* @__PURE__ */
|
|
1248
|
-
/* @__PURE__ */
|
|
1249
|
-
/* @__PURE__ */
|
|
1250
|
-
/* @__PURE__ */
|
|
1251
|
-
/* @__PURE__ */
|
|
1252
|
-
/* @__PURE__ */
|
|
1630
|
+
action: /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-0.5", children: [
|
|
1631
|
+
/* @__PURE__ */ jsxs6(DropdownMenu2, { children: [
|
|
1632
|
+
/* @__PURE__ */ jsx6(DropdownMenuTrigger2, { 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" }) }),
|
|
1633
|
+
/* @__PURE__ */ jsxs6(DropdownMenuContent2, { align: "end", className: "w-52", children: [
|
|
1634
|
+
/* @__PURE__ */ jsx6(DropdownMenuLabel2, { children: "Group your other chats" }),
|
|
1635
|
+
/* @__PURE__ */ jsxs6(DropdownMenuRadioGroup, { value: groupMode, onValueChange: (v) => setMode(v), children: [
|
|
1636
|
+
/* @__PURE__ */ jsx6(DropdownMenuRadioItem, { value: "date", children: "By date" }),
|
|
1637
|
+
/* @__PURE__ */ jsx6(DropdownMenuRadioItem, { value: "folder", children: "By folder" })
|
|
1253
1638
|
] }),
|
|
1254
|
-
/* @__PURE__ */
|
|
1255
|
-
/* @__PURE__ */
|
|
1639
|
+
/* @__PURE__ */ jsx6(DropdownMenuSeparator3, {}),
|
|
1640
|
+
/* @__PURE__ */ jsx6(DropdownMenuItem3, { onSelect: () => setShowHidden((v) => !v), children: showHidden ? "Leave hidden chats out" : `Show hidden chats${hiddenCount ? ` (${hiddenCount})` : ""}` })
|
|
1256
1641
|
] })
|
|
1257
1642
|
] }),
|
|
1258
|
-
/* @__PURE__ */
|
|
1643
|
+
/* @__PURE__ */ jsx6(
|
|
1259
1644
|
"button",
|
|
1260
1645
|
{
|
|
1261
1646
|
type: "button",
|
|
@@ -1263,17 +1648,17 @@ function Sidebar(props) {
|
|
|
1263
1648
|
onClick: () => void client.refreshDiscovered(),
|
|
1264
1649
|
"aria-label": "Look again for your other chats",
|
|
1265
1650
|
title: "Look again",
|
|
1266
|
-
children: state.discovered.loading ? /* @__PURE__ */
|
|
1651
|
+
children: state.discovered.loading ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx6(RefreshIcon, { size: 13 })
|
|
1267
1652
|
}
|
|
1268
1653
|
)
|
|
1269
1654
|
] }),
|
|
1270
1655
|
children: "Your other chats"
|
|
1271
1656
|
}
|
|
1272
1657
|
),
|
|
1273
|
-
state.discovered.loading && state.discovered.loadedAt === null ? /* @__PURE__ */
|
|
1658
|
+
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: [
|
|
1274
1659
|
renderGroups(otherList),
|
|
1275
|
-
state.discovered.data.length >= state.discoveredLimit ? /* @__PURE__ */
|
|
1276
|
-
|
|
1660
|
+
state.discovered.data.length >= state.discoveredLimit ? /* @__PURE__ */ jsx6("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxs6(
|
|
1661
|
+
Button2,
|
|
1277
1662
|
{
|
|
1278
1663
|
variant: "ghost",
|
|
1279
1664
|
size: "sm",
|
|
@@ -1281,32 +1666,32 @@ function Sidebar(props) {
|
|
|
1281
1666
|
onClick: () => void client.showMoreDiscovered(),
|
|
1282
1667
|
disabled: state.discovered.loading,
|
|
1283
1668
|
children: [
|
|
1284
|
-
state.discovered.loading ? /* @__PURE__ */
|
|
1669
|
+
state.discovered.loading ? /* @__PURE__ */ jsx6(SpinnerIcon, { size: 13 }) : null,
|
|
1285
1670
|
"Show older chats"
|
|
1286
1671
|
]
|
|
1287
1672
|
}
|
|
1288
1673
|
) }) : null
|
|
1289
1674
|
] }),
|
|
1290
|
-
showHidden ? null : hiddenCount > 0 ? /* @__PURE__ */
|
|
1675
|
+
showHidden ? null : hiddenCount > 0 ? /* @__PURE__ */ jsxs6("button", { type: "button", className: "cs-link mx-4 mt-3 text-[11.5px]", onClick: () => setShowHidden(true), children: [
|
|
1291
1676
|
hiddenCount,
|
|
1292
1677
|
" hidden ",
|
|
1293
1678
|
hiddenCount === 1 ? "chat" : "chats",
|
|
1294
1679
|
" \u2014 show"
|
|
1295
1680
|
] }) : null
|
|
1296
1681
|
] });
|
|
1297
|
-
return /* @__PURE__ */
|
|
1682
|
+
return /* @__PURE__ */ jsxs6(
|
|
1298
1683
|
"aside",
|
|
1299
1684
|
{
|
|
1300
|
-
className: "cs-sidebar flex h-full shrink-0 flex-col border-r border-border bg-
|
|
1685
|
+
className: "cs-sidebar flex h-full shrink-0 flex-col border-r border-border bg-sidebar-background",
|
|
1301
1686
|
style: { width: props.width },
|
|
1302
1687
|
"aria-label": "Sessions",
|
|
1303
1688
|
children: [
|
|
1304
|
-
/* @__PURE__ */
|
|
1305
|
-
/* @__PURE__ */
|
|
1306
|
-
/* @__PURE__ */
|
|
1307
|
-
/* @__PURE__ */
|
|
1689
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2 px-4 pb-2 pt-3.5", children: [
|
|
1690
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1691
|
+
/* @__PURE__ */ jsx6("span", { className: "cs-app-mark", "aria-hidden": "true" }),
|
|
1692
|
+
/* @__PURE__ */ jsx6("span", { className: "truncate text-[14px] font-semibold tracking-[-0.01em]", children: "Coding sessions" })
|
|
1308
1693
|
] }),
|
|
1309
|
-
/* @__PURE__ */
|
|
1694
|
+
/* @__PURE__ */ jsx6(
|
|
1310
1695
|
"button",
|
|
1311
1696
|
{
|
|
1312
1697
|
type: "button",
|
|
@@ -1314,19 +1699,19 @@ function Sidebar(props) {
|
|
|
1314
1699
|
onClick: props.onCollapse,
|
|
1315
1700
|
"aria-label": "Hide the sidebar (\u2318B)",
|
|
1316
1701
|
title: "Hide sidebar \u2318B",
|
|
1317
|
-
children: /* @__PURE__ */
|
|
1702
|
+
children: /* @__PURE__ */ jsx6(SidebarIcon, { size: 15 })
|
|
1318
1703
|
}
|
|
1319
1704
|
)
|
|
1320
1705
|
] }),
|
|
1321
|
-
/* @__PURE__ */
|
|
1322
|
-
/* @__PURE__ */
|
|
1323
|
-
/* @__PURE__ */
|
|
1706
|
+
/* @__PURE__ */ jsxs6("div", { className: "space-y-1.5 px-3 pb-1", children: [
|
|
1707
|
+
/* @__PURE__ */ jsxs6(Button2, { className: "w-full justify-start gap-2", variant: "outline", size: "sm", onClick: props.onNew, children: [
|
|
1708
|
+
/* @__PURE__ */ jsx6(PlusIcon, { size: 15 }),
|
|
1324
1709
|
"New session",
|
|
1325
|
-
/* @__PURE__ */
|
|
1710
|
+
/* @__PURE__ */ jsx6("kbd", { className: "cs-kbd ml-auto", children: "\u2325\u2318N" })
|
|
1326
1711
|
] }),
|
|
1327
|
-
/* @__PURE__ */
|
|
1328
|
-
/* @__PURE__ */
|
|
1329
|
-
/* @__PURE__ */
|
|
1712
|
+
/* @__PURE__ */ jsxs6("div", { className: "cs-search", children: [
|
|
1713
|
+
/* @__PURE__ */ jsx6(SearchIcon, { size: 14, className: "cs-search__icon" }),
|
|
1714
|
+
/* @__PURE__ */ jsx6(
|
|
1330
1715
|
"input",
|
|
1331
1716
|
{
|
|
1332
1717
|
ref: props.searchRef,
|
|
@@ -1352,10 +1737,10 @@ function Sidebar(props) {
|
|
|
1352
1737
|
className: "cs-search__input"
|
|
1353
1738
|
}
|
|
1354
1739
|
),
|
|
1355
|
-
query ? /* @__PURE__ */
|
|
1740
|
+
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" })
|
|
1356
1741
|
] })
|
|
1357
1742
|
] }),
|
|
1358
|
-
/* @__PURE__ */
|
|
1743
|
+
/* @__PURE__ */ jsx6("nav", { className: "min-h-0 flex-1 overflow-y-auto pb-3", children: searching ? searchBody : listBody }),
|
|
1359
1744
|
props.footer
|
|
1360
1745
|
]
|
|
1361
1746
|
}
|
|
@@ -1901,12 +2286,13 @@ var CodingSessionsClient = class {
|
|
|
1901
2286
|
start(input) {
|
|
1902
2287
|
return this.transport.call("start", input);
|
|
1903
2288
|
}
|
|
1904
|
-
takeover(session) {
|
|
2289
|
+
takeover(session, agent) {
|
|
1905
2290
|
return this.transport.call("takeover", {
|
|
1906
2291
|
provider: session.provider,
|
|
1907
2292
|
providerSessionId: session.providerSessionId,
|
|
1908
2293
|
cwd: session.cwd ?? "",
|
|
1909
|
-
title: session.title
|
|
2294
|
+
title: session.title,
|
|
2295
|
+
...agent ? { agent } : {}
|
|
1910
2296
|
});
|
|
1911
2297
|
}
|
|
1912
2298
|
send(sessionId, prompt) {
|
|
@@ -1948,13 +2334,13 @@ function firstInvalidField(errors) {
|
|
|
1948
2334
|
}
|
|
1949
2335
|
|
|
1950
2336
|
// src/react/app.tsx
|
|
1951
|
-
import { Fragment as
|
|
2337
|
+
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1952
2338
|
function CodingSessionsProvider({ transport, children }) {
|
|
1953
|
-
const [client] =
|
|
1954
|
-
|
|
2339
|
+
const [client] = useState6(() => new CodingSessionsClient(transport));
|
|
2340
|
+
useEffect4(() => {
|
|
1955
2341
|
if (transport.status().state === "open") void client.refreshAll();
|
|
1956
2342
|
}, [client, transport]);
|
|
1957
|
-
return /* @__PURE__ */
|
|
2343
|
+
return /* @__PURE__ */ jsx7(CodingSessionsContext.Provider, { value: client, children });
|
|
1958
2344
|
}
|
|
1959
2345
|
function readHash() {
|
|
1960
2346
|
if (typeof location === "undefined") return { kind: "none" };
|
|
@@ -1977,8 +2363,8 @@ function readTheme() {
|
|
|
1977
2363
|
}
|
|
1978
2364
|
}
|
|
1979
2365
|
function useTheme() {
|
|
1980
|
-
const [choice, setChoice] =
|
|
1981
|
-
|
|
2366
|
+
const [choice, setChoice] = useState6(readTheme);
|
|
2367
|
+
useEffect4(() => {
|
|
1982
2368
|
const media = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
|
|
1983
2369
|
const apply = () => {
|
|
1984
2370
|
const dark = choice === "dark" || choice === "system" && media?.matches === true;
|
|
@@ -2008,8 +2394,8 @@ var RUN_LABEL = {
|
|
|
2008
2394
|
function RunPill({ run }) {
|
|
2009
2395
|
if (!run) return null;
|
|
2010
2396
|
const live = !isTerminalRunStatus(run.status);
|
|
2011
|
-
return /* @__PURE__ */
|
|
2012
|
-
live ? /* @__PURE__ */
|
|
2397
|
+
return /* @__PURE__ */ jsxs7("span", { className: cn5("cs-pill", `cs-pill--${run.status}`), children: [
|
|
2398
|
+
live ? /* @__PURE__ */ jsx7("span", { className: "cs-pill__dot", "aria-hidden": "true" }) : null,
|
|
2013
2399
|
RUN_LABEL[run.status]
|
|
2014
2400
|
] });
|
|
2015
2401
|
}
|
|
@@ -2017,17 +2403,17 @@ function ConnectionBanner() {
|
|
|
2017
2403
|
const { connection } = useCodingSessionsState();
|
|
2018
2404
|
if (connection.state === "open") return null;
|
|
2019
2405
|
const closed = connection.state === "closed";
|
|
2020
|
-
return /* @__PURE__ */
|
|
2406
|
+
return /* @__PURE__ */ jsxs7(
|
|
2021
2407
|
"div",
|
|
2022
2408
|
{
|
|
2023
2409
|
role: "status",
|
|
2024
|
-
className:
|
|
2410
|
+
className: cn5(
|
|
2025
2411
|
"flex items-center gap-2 border-b px-4 py-2 text-[13px]",
|
|
2026
2412
|
closed ? "border-destructive/30 bg-destructive/10 text-destructive" : "border-border bg-muted/60 text-muted-foreground"
|
|
2027
2413
|
),
|
|
2028
2414
|
children: [
|
|
2029
|
-
closed ? /* @__PURE__ */
|
|
2030
|
-
/* @__PURE__ */
|
|
2415
|
+
closed ? /* @__PURE__ */ jsx7(AlertIcon, { size: 15 }) : /* @__PURE__ */ jsx7(SpinnerIcon, { size: 14 }),
|
|
2416
|
+
/* @__PURE__ */ jsx7("span", { children: closed ? connection.reason : "Connecting to the coding sessions host\u2026" })
|
|
2031
2417
|
]
|
|
2032
2418
|
}
|
|
2033
2419
|
);
|
|
@@ -2037,22 +2423,22 @@ function ProvidersFooter(props) {
|
|
|
2037
2423
|
const client = useCodingSessionsClient();
|
|
2038
2424
|
const next = { system: "light", light: "dark", dark: "system" };
|
|
2039
2425
|
const themeLabel = { system: "Match system", light: "Light", dark: "Dark" };
|
|
2040
|
-
return /* @__PURE__ */
|
|
2041
|
-
/* @__PURE__ */
|
|
2426
|
+
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: [
|
|
2427
|
+
/* @__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(
|
|
2042
2428
|
"span",
|
|
2043
2429
|
{
|
|
2044
|
-
className:
|
|
2430
|
+
className: cn5("cs-provider-chip", p.ready ? "" : "cs-provider-chip--problem"),
|
|
2045
2431
|
title: p.problem ? `${p.problem} ${p.fix ?? ""}` : [binaryWords(p) ?? p.label, p.plan, newerWords(p)].filter(Boolean).join(" \xB7 "),
|
|
2046
2432
|
children: [
|
|
2047
|
-
/* @__PURE__ */
|
|
2433
|
+
/* @__PURE__ */ jsx7(ProviderMark, { provider: p.provider, size: 13 }),
|
|
2048
2434
|
p.label,
|
|
2049
|
-
p.lastProblem ? /* @__PURE__ */
|
|
2050
|
-
p.ready ? /* @__PURE__ */
|
|
2435
|
+
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,
|
|
2436
|
+
p.ready ? /* @__PURE__ */ jsx7(CheckIcon, { size: 12 }) : /* @__PURE__ */ jsx7(AlertIcon, { size: 12 })
|
|
2051
2437
|
]
|
|
2052
2438
|
},
|
|
2053
2439
|
p.provider
|
|
2054
2440
|
)) }),
|
|
2055
|
-
/* @__PURE__ */
|
|
2441
|
+
/* @__PURE__ */ jsx7(
|
|
2056
2442
|
"button",
|
|
2057
2443
|
{
|
|
2058
2444
|
type: "button",
|
|
@@ -2060,11 +2446,11 @@ function ProvidersFooter(props) {
|
|
|
2060
2446
|
onClick: () => void client.refreshProviders(),
|
|
2061
2447
|
"aria-label": "Check Claude Code and Codex again",
|
|
2062
2448
|
title: "Check again",
|
|
2063
|
-
children: state.providers.loading ? /* @__PURE__ */
|
|
2449
|
+
children: state.providers.loading ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx7(RefreshIcon, { size: 13 })
|
|
2064
2450
|
}
|
|
2065
2451
|
),
|
|
2066
2452
|
props.extra,
|
|
2067
|
-
/* @__PURE__ */
|
|
2453
|
+
/* @__PURE__ */ jsx7(
|
|
2068
2454
|
"button",
|
|
2069
2455
|
{
|
|
2070
2456
|
type: "button",
|
|
@@ -2072,14 +2458,14 @@ function ProvidersFooter(props) {
|
|
|
2072
2458
|
onClick: () => props.setTheme(next[props.theme]),
|
|
2073
2459
|
"aria-label": `Theme: ${themeLabel[props.theme]}. Switch to ${themeLabel[next[props.theme]]}.`,
|
|
2074
2460
|
title: `Theme: ${themeLabel[props.theme]}`,
|
|
2075
|
-
children: props.theme === "system" ? /* @__PURE__ */
|
|
2461
|
+
children: props.theme === "system" ? /* @__PURE__ */ jsx7(MonitorIcon, { size: 14 }) : props.theme === "light" ? /* @__PURE__ */ jsx7(SunIcon, { size: 14 }) : /* @__PURE__ */ jsx7(MoonIcon, { size: 14 })
|
|
2076
2462
|
}
|
|
2077
2463
|
)
|
|
2078
2464
|
] }) });
|
|
2079
2465
|
}
|
|
2080
2466
|
function useNotifier() {
|
|
2081
2467
|
const show = useContext3(ToastContext);
|
|
2082
|
-
return
|
|
2468
|
+
return useMemo4(
|
|
2083
2469
|
() => ({
|
|
2084
2470
|
notify(event) {
|
|
2085
2471
|
show(event.message);
|
|
@@ -2090,8 +2476,8 @@ function useNotifier() {
|
|
|
2090
2476
|
}
|
|
2091
2477
|
function useLiveElsewhere(provider, providerSessionId, initial = null) {
|
|
2092
2478
|
const client = useCodingSessionsClient();
|
|
2093
|
-
const [state, setState] =
|
|
2094
|
-
|
|
2479
|
+
const [state, setState] = useState6(initial);
|
|
2480
|
+
useEffect4(() => {
|
|
2095
2481
|
if (!provider || !providerSessionId) {
|
|
2096
2482
|
setState(null);
|
|
2097
2483
|
return;
|
|
@@ -2111,8 +2497,8 @@ function useLiveElsewhere(provider, providerSessionId, initial = null) {
|
|
|
2111
2497
|
}
|
|
2112
2498
|
function useSessionUsage(sessionId, lastRunKey) {
|
|
2113
2499
|
const client = useCodingSessionsClient();
|
|
2114
|
-
const [usage, setUsage] =
|
|
2115
|
-
|
|
2500
|
+
const [usage, setUsage] = useState6(null);
|
|
2501
|
+
useEffect4(() => {
|
|
2116
2502
|
let cancelled = false;
|
|
2117
2503
|
void client.transport.call("listRuns", sessionId).then((runs) => {
|
|
2118
2504
|
if (cancelled) return;
|
|
@@ -2133,18 +2519,18 @@ function useSessionUsage(sessionId, lastRunKey) {
|
|
|
2133
2519
|
return usage;
|
|
2134
2520
|
}
|
|
2135
2521
|
function HeaderMenu(props) {
|
|
2136
|
-
return /* @__PURE__ */
|
|
2137
|
-
/* @__PURE__ */
|
|
2138
|
-
/* @__PURE__ */
|
|
2522
|
+
return /* @__PURE__ */ jsxs7(DropdownMenu3, { children: [
|
|
2523
|
+
/* @__PURE__ */ jsx7(DropdownMenuTrigger3, { 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 }) }) }),
|
|
2524
|
+
/* @__PURE__ */ jsx7(DropdownMenuContent3, { align: "end", className: "w-64", onCloseAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx7(ChatMenuItems, { entry: props.entry, variant: "dropdown", onRename: props.onRename }) })
|
|
2139
2525
|
] });
|
|
2140
2526
|
}
|
|
2141
2527
|
function HeaderTitle(props) {
|
|
2142
2528
|
const client = useCodingSessionsClient();
|
|
2143
2529
|
const show = useContext3(ToastContext);
|
|
2144
|
-
const [value, setValue] =
|
|
2145
|
-
|
|
2146
|
-
const inputRef =
|
|
2147
|
-
|
|
2530
|
+
const [value, setValue] = useState6(props.entry.title);
|
|
2531
|
+
useEffect4(() => setValue(props.entry.title), [props.entry.title, props.renaming]);
|
|
2532
|
+
const inputRef = useRef3(null);
|
|
2533
|
+
useEffect4(() => {
|
|
2148
2534
|
if (!props.renaming) return;
|
|
2149
2535
|
const timer = setTimeout(() => {
|
|
2150
2536
|
const input = inputRef.current;
|
|
@@ -2156,7 +2542,7 @@ function HeaderTitle(props) {
|
|
|
2156
2542
|
return () => clearTimeout(timer);
|
|
2157
2543
|
}, [props.renaming]);
|
|
2158
2544
|
if (!props.renaming) {
|
|
2159
|
-
return /* @__PURE__ */
|
|
2545
|
+
return /* @__PURE__ */ jsx7(
|
|
2160
2546
|
"h1",
|
|
2161
2547
|
{
|
|
2162
2548
|
className: "truncate text-[15px] font-semibold leading-5 tracking-[-0.01em]",
|
|
@@ -2173,7 +2559,7 @@ function HeaderTitle(props) {
|
|
|
2173
2559
|
const next = title === "" || title === props.entry.originalTitle ? null : title;
|
|
2174
2560
|
client.setPreference(props.entry.key, { title: next }).catch((error) => show(`The new name didn't save: ${error instanceof Error ? error.message : String(error)}`));
|
|
2175
2561
|
};
|
|
2176
|
-
return /* @__PURE__ */
|
|
2562
|
+
return /* @__PURE__ */ jsx7(
|
|
2177
2563
|
"input",
|
|
2178
2564
|
{
|
|
2179
2565
|
ref: inputRef,
|
|
@@ -2192,9 +2578,9 @@ function HeaderTitle(props) {
|
|
|
2192
2578
|
);
|
|
2193
2579
|
}
|
|
2194
2580
|
function LongChatNote(props) {
|
|
2195
|
-
return /* @__PURE__ */
|
|
2581
|
+
return /* @__PURE__ */ jsxs7("p", { className: "mx-auto mt-3 flex items-center gap-2 text-[12px] text-muted-foreground", children: [
|
|
2196
2582
|
"This chat is very long \u2014 showing its most recent part.",
|
|
2197
|
-
/* @__PURE__ */
|
|
2583
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "cs-link", onClick: props.onEarlier, disabled: props.loading, children: props.loading ? "Reading\u2026" : "Show earlier" })
|
|
2198
2584
|
] });
|
|
2199
2585
|
}
|
|
2200
2586
|
function binaryWords(p) {
|
|
@@ -2216,8 +2602,8 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
|
|
|
2216
2602
|
const blocked = provider && (!provider.installed || !provider.loggedIn) ? provider : null;
|
|
2217
2603
|
const limited = !blocked && provider?.lastProblem ? provider : null;
|
|
2218
2604
|
const modelRefused = run?.status === "failed" && isModelUnavailable(run.error);
|
|
2219
|
-
const [stopping, setStopping] =
|
|
2220
|
-
const [renaming, setRenaming] =
|
|
2605
|
+
const [stopping, setStopping] = useState6(false);
|
|
2606
|
+
const [renaming, setRenaming] = useState6(false);
|
|
2221
2607
|
const elsewhere = useLiveElsewhere(
|
|
2222
2608
|
session.origin === "takeover" && !live ? session.provider : null,
|
|
2223
2609
|
session.providerSessionId
|
|
@@ -2226,7 +2612,7 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
|
|
|
2226
2612
|
const messages = transcript.thread.getSnapshot().messages;
|
|
2227
2613
|
const files = useChangedFiles(messages);
|
|
2228
2614
|
const usage = useSessionUsage(session.id, `${run?.runId ?? ""}:${run?.status ?? ""}`);
|
|
2229
|
-
|
|
2615
|
+
useEffect4(() => {
|
|
2230
2616
|
if (!live) setStopping(false);
|
|
2231
2617
|
}, [live]);
|
|
2232
2618
|
const stop = async () => {
|
|
@@ -2239,16 +2625,16 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
|
|
|
2239
2625
|
};
|
|
2240
2626
|
const usageWords = usage ? `${formatCount(usage.tokens, { style: "compact" })} tokens${usage.cost !== null ? ` \xB7 ${formatUsd(usage.cost)}` : ""}` : null;
|
|
2241
2627
|
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.` : "") : "";
|
|
2242
|
-
return /* @__PURE__ */
|
|
2243
|
-
/* @__PURE__ */
|
|
2244
|
-
/* @__PURE__ */
|
|
2245
|
-
/* @__PURE__ */
|
|
2246
|
-
/* @__PURE__ */
|
|
2247
|
-
/* @__PURE__ */
|
|
2248
|
-
/* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2250
|
-
/* @__PURE__ */
|
|
2251
|
-
/* @__PURE__ */
|
|
2628
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1", children: [
|
|
2629
|
+
/* @__PURE__ */ jsxs7("section", { className: "flex min-w-0 flex-1 flex-col", "aria-label": entry.title, children: [
|
|
2630
|
+
/* @__PURE__ */ jsxs7("header", { className: "flex flex-wrap items-center gap-2 border-b border-border px-5 pt-2.5 pb-2.5", children: [
|
|
2631
|
+
/* @__PURE__ */ jsx7(ProviderMark, { provider: session.provider, size: 22 }),
|
|
2632
|
+
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1 overflow-hidden", children: [
|
|
2633
|
+
/* @__PURE__ */ jsx7(HeaderTitle, { entry, renaming, setRenaming }),
|
|
2634
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 items-center gap-1 text-[12px] leading-5 text-muted-foreground", children: [
|
|
2635
|
+
/* @__PURE__ */ jsx7("span", { className: "shrink-0", children: PROVIDER_LABEL[session.provider] }),
|
|
2636
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xB7" }),
|
|
2637
|
+
/* @__PURE__ */ jsx7(
|
|
2252
2638
|
ModelPicker,
|
|
2253
2639
|
{
|
|
2254
2640
|
status: provider,
|
|
@@ -2256,69 +2642,70 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
|
|
|
2256
2642
|
onChange: setOptions
|
|
2257
2643
|
}
|
|
2258
2644
|
),
|
|
2259
|
-
/* @__PURE__ */
|
|
2260
|
-
/* @__PURE__ */
|
|
2261
|
-
/* @__PURE__ */
|
|
2262
|
-
usageWords ? /* @__PURE__ */
|
|
2645
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xB7" }),
|
|
2646
|
+
/* @__PURE__ */ jsx7(FolderIcon, { size: 12, className: "shrink-0" }),
|
|
2647
|
+
/* @__PURE__ */ jsx7("span", { className: "min-w-[4rem] truncate", title: session.cwd, children: prettyPath2(session.cwd) }),
|
|
2648
|
+
usageWords ? /* @__PURE__ */ jsxs7("span", { className: "shrink-0", title: usageTitle, children: [
|
|
2263
2649
|
"\xB7 ",
|
|
2264
2650
|
usageWords
|
|
2265
2651
|
] }) : null
|
|
2266
2652
|
] })
|
|
2267
2653
|
] }),
|
|
2268
|
-
/* @__PURE__ */
|
|
2654
|
+
/* @__PURE__ */ jsx7(AgentMenu, { transport: client.transport, sessionId: session.id, agent: session.agent ?? null, onChange: () => void 0 }),
|
|
2655
|
+
/* @__PURE__ */ jsxs7(
|
|
2269
2656
|
"button",
|
|
2270
2657
|
{
|
|
2271
2658
|
type: "button",
|
|
2272
|
-
className:
|
|
2659
|
+
className: cn5("cs-chip-button", changesOpen && "cs-chip-button--on"),
|
|
2273
2660
|
onClick: () => setChangesOpen(!changesOpen),
|
|
2274
2661
|
"aria-pressed": changesOpen,
|
|
2275
2662
|
title: "Files this chat changed",
|
|
2276
2663
|
children: [
|
|
2277
|
-
/* @__PURE__ */
|
|
2664
|
+
/* @__PURE__ */ jsx7(FileIcon, { size: 13 }),
|
|
2278
2665
|
files.length > 0 ? `${files.length} ${files.length === 1 ? "file" : "files"} changed` : "Changes"
|
|
2279
2666
|
]
|
|
2280
2667
|
}
|
|
2281
2668
|
),
|
|
2282
|
-
/* @__PURE__ */
|
|
2283
|
-
live ? /* @__PURE__ */
|
|
2284
|
-
stopping ? /* @__PURE__ */
|
|
2669
|
+
/* @__PURE__ */ jsx7(RunPill, { run }),
|
|
2670
|
+
live ? /* @__PURE__ */ jsxs7(Button3, { variant: "outline", size: "sm", onClick: () => void stop(), disabled: stopping, className: "gap-1.5", title: "Stop Esc", children: [
|
|
2671
|
+
stopping ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx7(StopIcon, { size: 13 }),
|
|
2285
2672
|
stopping ? "Stopping\u2026" : "Stop"
|
|
2286
2673
|
] }) : null,
|
|
2287
|
-
/* @__PURE__ */
|
|
2674
|
+
/* @__PURE__ */ jsx7(HeaderMenu, { entry, onRename: () => setRenaming(true) })
|
|
2288
2675
|
] }),
|
|
2289
|
-
/* @__PURE__ */
|
|
2290
|
-
/* @__PURE__ */
|
|
2291
|
-
/* @__PURE__ */
|
|
2676
|
+
/* @__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: [
|
|
2677
|
+
/* @__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: [
|
|
2678
|
+
/* @__PURE__ */ jsx7(SpinnerIcon, { size: 15 }),
|
|
2292
2679
|
" Loading the conversation\u2026"
|
|
2293
|
-
] }) : /* @__PURE__ */
|
|
2294
|
-
transcript.state.unavailable ? /* @__PURE__ */
|
|
2295
|
-
transcript.state.truncated ? /* @__PURE__ */
|
|
2680
|
+
] }) : /* @__PURE__ */ jsxs7("div", { className: "flex h-full flex-col", children: [
|
|
2681
|
+
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,
|
|
2682
|
+
transcript.state.truncated ? /* @__PURE__ */ jsx7(
|
|
2296
2683
|
LongChatNote,
|
|
2297
2684
|
{
|
|
2298
2685
|
loading: transcript.state.loadingEarlier === true,
|
|
2299
2686
|
onEarlier: () => void transcript.loadEarlier()
|
|
2300
2687
|
}
|
|
2301
2688
|
) : null,
|
|
2302
|
-
messages.length === 0 && !live ? /* @__PURE__ */
|
|
2689
|
+
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}` })
|
|
2303
2690
|
] }) }),
|
|
2304
|
-
/* @__PURE__ */
|
|
2305
|
-
limited ? /* @__PURE__ */
|
|
2306
|
-
/* @__PURE__ */
|
|
2307
|
-
/* @__PURE__ */
|
|
2691
|
+
/* @__PURE__ */ jsxs7("div", { className: "mx-auto w-full max-w-[820px] px-4 pb-4", children: [
|
|
2692
|
+
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: [
|
|
2693
|
+
/* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
|
|
2694
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2308
2695
|
limited.problem,
|
|
2309
2696
|
" ",
|
|
2310
2697
|
limited.fix
|
|
2311
2698
|
] })
|
|
2312
2699
|
] }) : null,
|
|
2313
|
-
modelRefused && !blocked ? /* @__PURE__ */
|
|
2700
|
+
modelRefused && !blocked ? /* @__PURE__ */ jsxs7(
|
|
2314
2701
|
"div",
|
|
2315
2702
|
{
|
|
2316
2703
|
className: "mb-2 flex items-center gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-[12.5px]",
|
|
2317
2704
|
role: "alert",
|
|
2318
2705
|
children: [
|
|
2319
|
-
/* @__PURE__ */
|
|
2320
|
-
/* @__PURE__ */
|
|
2321
|
-
/* @__PURE__ */
|
|
2706
|
+
/* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "shrink-0 text-warning" }),
|
|
2707
|
+
/* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate", title: run?.error ?? void 0, children: MODEL_UNAVAILABLE_LABEL }),
|
|
2708
|
+
/* @__PURE__ */ jsx7(
|
|
2322
2709
|
ModelPicker,
|
|
2323
2710
|
{
|
|
2324
2711
|
status: provider,
|
|
@@ -2329,31 +2716,31 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
|
|
|
2329
2716
|
]
|
|
2330
2717
|
}
|
|
2331
2718
|
) : null,
|
|
2332
|
-
blocked ? /* @__PURE__ */
|
|
2333
|
-
/* @__PURE__ */
|
|
2334
|
-
/* @__PURE__ */
|
|
2719
|
+
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: [
|
|
2720
|
+
/* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
|
|
2721
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2335
2722
|
blocked.problem,
|
|
2336
2723
|
" ",
|
|
2337
2724
|
blocked.fix
|
|
2338
2725
|
] })
|
|
2339
2726
|
] }) : null,
|
|
2340
|
-
/* @__PURE__ */
|
|
2341
|
-
/* @__PURE__ */
|
|
2342
|
-
/* @__PURE__ */
|
|
2343
|
-
/* @__PURE__ */
|
|
2727
|
+
/* @__PURE__ */ jsx7("div", { className: "cs-activity", role: "status", "aria-live": "polite", "data-idle": live ? void 0 : true, children: live ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
2728
|
+
/* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }),
|
|
2729
|
+
/* @__PURE__ */ jsx7("span", { className: "truncate", children: run?.status === "starting" ? `Starting ${PROVIDER_LABEL[session.provider]}\u2026` : transcript.activity ?? "Thinking\u2026" }),
|
|
2730
|
+
/* @__PURE__ */ jsx7("span", { className: "ml-auto shrink-0 text-[11px] opacity-70", children: "Esc to stop" })
|
|
2344
2731
|
] }) : null }),
|
|
2345
|
-
elsewhere ? /* @__PURE__ */
|
|
2346
|
-
/* @__PURE__ */
|
|
2347
|
-
/* @__PURE__ */
|
|
2732
|
+
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: [
|
|
2733
|
+
/* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
|
|
2734
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2348
2735
|
elsewhere.message,
|
|
2349
2736
|
" A message sent here would put a second agent on the same chat."
|
|
2350
2737
|
] })
|
|
2351
2738
|
] }) : null,
|
|
2352
|
-
session.queued.length > 0 ? /* @__PURE__ */
|
|
2353
|
-
/* @__PURE__ */
|
|
2354
|
-
/* @__PURE__ */
|
|
2739
|
+
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: [
|
|
2740
|
+
/* @__PURE__ */ jsx7("span", { className: "cs-queued__label", children: "Queued \xB7 sends when this run finishes" }),
|
|
2741
|
+
/* @__PURE__ */ jsx7("span", { className: "cs-queued__text", children: text })
|
|
2355
2742
|
] }, `${index}-${text.slice(0, 16)}`)) }) : null,
|
|
2356
|
-
/* @__PURE__ */
|
|
2743
|
+
/* @__PURE__ */ jsx7(
|
|
2357
2744
|
ChatComposer,
|
|
2358
2745
|
{
|
|
2359
2746
|
placeholder: `Message ${PROVIDER_LABEL[session.provider]}\u2026`,
|
|
@@ -2364,14 +2751,14 @@ function SessionView({ session, changesOpen, setChangesOpen }) {
|
|
|
2364
2751
|
] })
|
|
2365
2752
|
] }) })
|
|
2366
2753
|
] }),
|
|
2367
|
-
changesOpen ? /* @__PURE__ */
|
|
2754
|
+
changesOpen ? /* @__PURE__ */ jsx7(ChangesPanel, { files, cwd: session.cwd, truncated: transcript.state.truncated, onClose: () => setChangesOpen(false) }) : null
|
|
2368
2755
|
] });
|
|
2369
2756
|
}
|
|
2370
2757
|
function usePreviewThread(id, onSend) {
|
|
2371
|
-
const ref =
|
|
2372
|
-
const send =
|
|
2758
|
+
const ref = useRef3({ messages: [], listeners: /* @__PURE__ */ new Set() });
|
|
2759
|
+
const send = useRef3(onSend);
|
|
2373
2760
|
send.current = onSend;
|
|
2374
|
-
const thread =
|
|
2761
|
+
const thread = useMemo4(
|
|
2375
2762
|
() => createExternalThreadSource2({
|
|
2376
2763
|
getSnapshot: () => ({ messages: ref.current.messages, status: "idle", conversationId: id }),
|
|
2377
2764
|
subscribe: (listener) => {
|
|
@@ -2396,13 +2783,13 @@ function DiscoveredView(props) {
|
|
|
2396
2783
|
const state = useCodingSessionsState();
|
|
2397
2784
|
const show = useContext3(ToastContext);
|
|
2398
2785
|
const now = useMinuteClock();
|
|
2399
|
-
const [preview, setPreview] =
|
|
2400
|
-
const [busy, setBusy] =
|
|
2401
|
-
const [error, setError] =
|
|
2402
|
-
const [confirming, setConfirming] =
|
|
2403
|
-
const [renaming, setRenaming] =
|
|
2404
|
-
const [maxBytes, setMaxBytes] =
|
|
2405
|
-
const [readingEarlier, setReadingEarlier] =
|
|
2786
|
+
const [preview, setPreview] = useState6({ loading: true, messages: [], unavailable: null, truncated: false });
|
|
2787
|
+
const [busy, setBusy] = useState6(false);
|
|
2788
|
+
const [error, setError] = useState6(null);
|
|
2789
|
+
const [confirming, setConfirming] = useState6(false);
|
|
2790
|
+
const [renaming, setRenaming] = useState6(false);
|
|
2791
|
+
const [maxBytes, setMaxBytes] = useState6(void 0);
|
|
2792
|
+
const [readingEarlier, setReadingEarlier] = useState6(false);
|
|
2406
2793
|
const elsewhere = useLiveElsewhere(props.provider, props.id, props.session?.activeElsewhere ?? null);
|
|
2407
2794
|
const files = useChangedFiles(preview.messages);
|
|
2408
2795
|
const d = props.session;
|
|
@@ -2412,7 +2799,7 @@ function DiscoveredView(props) {
|
|
|
2412
2799
|
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."
|
|
2413
2800
|
)
|
|
2414
2801
|
);
|
|
2415
|
-
|
|
2802
|
+
useEffect4(() => {
|
|
2416
2803
|
let cancelled = false;
|
|
2417
2804
|
const read = (first) => client.readPreview(props.provider, props.id, maxBytes).then((next) => {
|
|
2418
2805
|
if (cancelled) return;
|
|
@@ -2437,13 +2824,14 @@ function DiscoveredView(props) {
|
|
|
2437
2824
|
if (elsewhere) setConfirming(true);
|
|
2438
2825
|
else void takeover();
|
|
2439
2826
|
};
|
|
2440
|
-
const
|
|
2827
|
+
const [choosingAgent, setChoosingAgent] = useState6(false);
|
|
2828
|
+
const takeover = async (agent) => {
|
|
2441
2829
|
if (!d) return;
|
|
2442
2830
|
setConfirming(false);
|
|
2443
2831
|
setBusy(true);
|
|
2444
2832
|
setError(null);
|
|
2445
2833
|
try {
|
|
2446
|
-
const taken = await client.takeover(d);
|
|
2834
|
+
const taken = await client.takeover(d, agent);
|
|
2447
2835
|
props.onTakenOver(taken.id);
|
|
2448
2836
|
} catch (e) {
|
|
2449
2837
|
setError(e instanceof Error ? e.message : String(e));
|
|
@@ -2451,26 +2839,26 @@ function DiscoveredView(props) {
|
|
|
2451
2839
|
setBusy(false);
|
|
2452
2840
|
}
|
|
2453
2841
|
};
|
|
2454
|
-
return /* @__PURE__ */
|
|
2455
|
-
/* @__PURE__ */
|
|
2456
|
-
/* @__PURE__ */
|
|
2457
|
-
/* @__PURE__ */
|
|
2458
|
-
/* @__PURE__ */
|
|
2459
|
-
/* @__PURE__ */
|
|
2460
|
-
/* @__PURE__ */
|
|
2461
|
-
/* @__PURE__ */
|
|
2462
|
-
d?.cwd ? /* @__PURE__ */
|
|
2463
|
-
/* @__PURE__ */
|
|
2464
|
-
/* @__PURE__ */
|
|
2465
|
-
/* @__PURE__ */
|
|
2842
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1", children: [
|
|
2843
|
+
/* @__PURE__ */ jsxs7("section", { className: "flex min-w-0 flex-1 flex-col", "aria-label": entry.title, children: [
|
|
2844
|
+
/* @__PURE__ */ jsxs7("header", { className: "flex flex-wrap items-center gap-2 border-b border-border px-5 pt-2.5 pb-2.5", children: [
|
|
2845
|
+
/* @__PURE__ */ jsx7(ProviderMark, { provider: props.provider, size: 22 }),
|
|
2846
|
+
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
|
|
2847
|
+
/* @__PURE__ */ jsx7(HeaderTitle, { entry, renaming, setRenaming }),
|
|
2848
|
+
/* @__PURE__ */ jsxs7("p", { className: "flex items-center gap-1.5 truncate text-[12px] leading-4 text-muted-foreground", children: [
|
|
2849
|
+
/* @__PURE__ */ jsx7("span", { children: PROVIDER_LABEL[props.provider] }),
|
|
2850
|
+
d?.cwd ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
2851
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xB7" }),
|
|
2852
|
+
/* @__PURE__ */ jsx7(FolderIcon, { size: 12 }),
|
|
2853
|
+
/* @__PURE__ */ jsx7("span", { className: "truncate", title: d.cwd, children: prettyPath2(d.cwd) })
|
|
2466
2854
|
] }) : null,
|
|
2467
|
-
d ? /* @__PURE__ */
|
|
2855
|
+
d ? /* @__PURE__ */ jsxs7("span", { children: [
|
|
2468
2856
|
"\xB7 last active ",
|
|
2469
2857
|
relativeTime(d.updatedAt, now)
|
|
2470
2858
|
] }) : null
|
|
2471
2859
|
] })
|
|
2472
2860
|
] }),
|
|
2473
|
-
files.length > 0 ? /* @__PURE__ */
|
|
2861
|
+
files.length > 0 ? /* @__PURE__ */ jsxs7(
|
|
2474
2862
|
"button",
|
|
2475
2863
|
{
|
|
2476
2864
|
type: "button",
|
|
@@ -2479,13 +2867,13 @@ function DiscoveredView(props) {
|
|
|
2479
2867
|
"aria-pressed": props.changesOpen,
|
|
2480
2868
|
title: "Files this chat changed",
|
|
2481
2869
|
children: [
|
|
2482
|
-
/* @__PURE__ */
|
|
2870
|
+
/* @__PURE__ */ jsx7(FileIcon, { size: 13 }),
|
|
2483
2871
|
`${files.length} ${files.length === 1 ? "file" : "files"} changed`
|
|
2484
2872
|
]
|
|
2485
2873
|
}
|
|
2486
2874
|
) : null,
|
|
2487
|
-
d?.cwd ? /* @__PURE__ */
|
|
2488
|
-
|
|
2875
|
+
d?.cwd ? /* @__PURE__ */ jsxs7(
|
|
2876
|
+
Button3,
|
|
2489
2877
|
{
|
|
2490
2878
|
size: "sm",
|
|
2491
2879
|
variant: elsewhere ? "outline" : "default",
|
|
@@ -2494,44 +2882,56 @@ function DiscoveredView(props) {
|
|
|
2494
2882
|
className: "gap-1.5",
|
|
2495
2883
|
title: elsewhere ? elsewhere.message : void 0,
|
|
2496
2884
|
children: [
|
|
2497
|
-
busy ? /* @__PURE__ */
|
|
2885
|
+
busy ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : elsewhere ? /* @__PURE__ */ jsx7(AlertIcon, { size: 14, className: "text-warning" }) : /* @__PURE__ */ jsx7(HandoffIcon, { size: 14 }),
|
|
2498
2886
|
elsewhere ? "Take over anyway\u2026" : "Take over"
|
|
2499
2887
|
]
|
|
2500
2888
|
}
|
|
2501
2889
|
) : null,
|
|
2502
|
-
d ? /* @__PURE__ */
|
|
2890
|
+
d?.cwd && !elsewhere ? /* @__PURE__ */ jsx7(Button3, { size: "sm", variant: "outline", onClick: () => setChoosingAgent(true), disabled: busy, children: "Continue with agent\u2026" }) : null,
|
|
2891
|
+
/* @__PURE__ */ jsx7(
|
|
2892
|
+
ChooseAgentDialog,
|
|
2893
|
+
{
|
|
2894
|
+
transport: client.transport,
|
|
2895
|
+
open: choosingAgent,
|
|
2896
|
+
onOpenChange: setChoosingAgent,
|
|
2897
|
+
title: "Continue with an agent",
|
|
2898
|
+
action: "Take over with this agent",
|
|
2899
|
+
onConfirm: (agent) => takeover(agent)
|
|
2900
|
+
}
|
|
2901
|
+
),
|
|
2902
|
+
d ? /* @__PURE__ */ jsx7(HeaderMenu, { entry, onRename: () => setRenaming(true) }) : null
|
|
2503
2903
|
] }),
|
|
2504
|
-
elsewhere ? /* @__PURE__ */
|
|
2505
|
-
/* @__PURE__ */
|
|
2506
|
-
/* @__PURE__ */
|
|
2507
|
-
/* @__PURE__ */
|
|
2904
|
+
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: [
|
|
2905
|
+
/* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 shrink-0 text-warning" }),
|
|
2906
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2907
|
+
/* @__PURE__ */ jsx7("span", { className: "font-medium", children: elsewhere.message }),
|
|
2508
2908
|
" 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."
|
|
2509
2909
|
] })
|
|
2510
2910
|
] }) : null,
|
|
2511
|
-
/* @__PURE__ */
|
|
2512
|
-
/* @__PURE__ */
|
|
2513
|
-
/* @__PURE__ */
|
|
2911
|
+
/* @__PURE__ */ jsx7(Dialog2, { open: confirming, onOpenChange: setConfirming, children: /* @__PURE__ */ jsxs7(DialogContent2, { className: "max-w-[460px]", children: [
|
|
2912
|
+
/* @__PURE__ */ jsxs7(DialogHeader2, { children: [
|
|
2913
|
+
/* @__PURE__ */ jsxs7(DialogTitle2, { children: [
|
|
2514
2914
|
"This chat is running right now in ",
|
|
2515
2915
|
PROVIDER_LABEL[props.provider]
|
|
2516
2916
|
] }),
|
|
2517
|
-
/* @__PURE__ */
|
|
2917
|
+
/* @__PURE__ */ jsxs7(DialogDescription, { children: [
|
|
2518
2918
|
elsewhere?.message,
|
|
2519
2919
|
" If you take it over, two agents will work in the same conversation at once and may overwrite each other's changes."
|
|
2520
2920
|
] })
|
|
2521
2921
|
] }),
|
|
2522
|
-
/* @__PURE__ */
|
|
2523
|
-
/* @__PURE__ */
|
|
2524
|
-
/* @__PURE__ */
|
|
2922
|
+
/* @__PURE__ */ jsxs7(DialogFooter2, { children: [
|
|
2923
|
+
/* @__PURE__ */ jsx7(Button3, { variant: "ghost", onClick: () => setConfirming(false), children: "Cancel" }),
|
|
2924
|
+
/* @__PURE__ */ jsx7(Button3, { variant: "destructive", onClick: () => void takeover(), children: "Take over anyway" })
|
|
2525
2925
|
] })
|
|
2526
2926
|
] }) }),
|
|
2527
|
-
error ? /* @__PURE__ */
|
|
2528
|
-
d && !d.cwd ? /* @__PURE__ */
|
|
2529
|
-
/* @__PURE__ */
|
|
2530
|
-
preview.loading ? /* @__PURE__ */
|
|
2531
|
-
/* @__PURE__ */
|
|
2927
|
+
error ? /* @__PURE__ */ jsx7("p", { className: "border-b border-destructive/30 bg-destructive/10 px-5 py-2 text-[13px] text-destructive", children: error }) : null,
|
|
2928
|
+
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,
|
|
2929
|
+
/* @__PURE__ */ jsxs7("div", { className: "mx-chat flex min-h-0 flex-1 flex-col", children: [
|
|
2930
|
+
preview.loading ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 items-center justify-center gap-2 text-[13px] text-muted-foreground", children: [
|
|
2931
|
+
/* @__PURE__ */ jsx7(SpinnerIcon, { size: 15 }),
|
|
2532
2932
|
" Reading this chat\u2026"
|
|
2533
|
-
] }) : preview.unavailable ? /* @__PURE__ */
|
|
2534
|
-
preview.truncated ? /* @__PURE__ */
|
|
2933
|
+
] }) : 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: [
|
|
2934
|
+
preview.truncated ? /* @__PURE__ */ jsx7(
|
|
2535
2935
|
LongChatNote,
|
|
2536
2936
|
{
|
|
2537
2937
|
loading: readingEarlier,
|
|
@@ -2541,14 +2941,14 @@ function DiscoveredView(props) {
|
|
|
2541
2941
|
}
|
|
2542
2942
|
}
|
|
2543
2943
|
) : null,
|
|
2544
|
-
/* @__PURE__ */
|
|
2944
|
+
/* @__PURE__ */ jsx7(ChatMessageList, { className: "min-h-0 flex-1", label: "Chat preview" })
|
|
2545
2945
|
] }),
|
|
2546
|
-
d?.cwd ? /* @__PURE__ */
|
|
2946
|
+
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: [
|
|
2547
2947
|
"This chat was started in ",
|
|
2548
2948
|
PROVIDER_LABEL[props.provider],
|
|
2549
2949
|
".",
|
|
2550
2950
|
" ",
|
|
2551
|
-
/* @__PURE__ */
|
|
2951
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "font-medium text-foreground underline-offset-4 hover:underline", onClick: requestTakeover, children: "Take it over" }),
|
|
2552
2952
|
" ",
|
|
2553
2953
|
"to continue it here \u2014 it stays in your ",
|
|
2554
2954
|
PROVIDER_LABEL[props.provider],
|
|
@@ -2556,70 +2956,73 @@ function DiscoveredView(props) {
|
|
|
2556
2956
|
] }) : null
|
|
2557
2957
|
] })
|
|
2558
2958
|
] }),
|
|
2559
|
-
props.changesOpen && files.length > 0 ? /* @__PURE__ */
|
|
2959
|
+
props.changesOpen && files.length > 0 ? /* @__PURE__ */ jsx7(ChangesPanel, { files, cwd: d?.cwd ?? null, truncated: preview.truncated, onClose: () => props.setChangesOpen(false) }) : null
|
|
2560
2960
|
] });
|
|
2561
2961
|
}
|
|
2562
2962
|
function ProviderCard(props) {
|
|
2563
2963
|
const ready = props.status.ready;
|
|
2564
|
-
return /* @__PURE__ */
|
|
2964
|
+
return /* @__PURE__ */ jsxs7(
|
|
2565
2965
|
"button",
|
|
2566
2966
|
{
|
|
2567
2967
|
type: "button",
|
|
2568
2968
|
onClick: props.onSelect,
|
|
2569
2969
|
"aria-pressed": props.selected,
|
|
2570
|
-
className:
|
|
2970
|
+
className: cn5(
|
|
2571
2971
|
"flex flex-1 flex-col gap-1.5 rounded-xl border px-3.5 py-3 text-left transition-colors",
|
|
2572
2972
|
props.selected ? "border-primary bg-primary/5 ring-1 ring-primary" : "border-border hover:bg-accent/50"
|
|
2573
2973
|
),
|
|
2574
2974
|
children: [
|
|
2575
|
-
/* @__PURE__ */
|
|
2576
|
-
/* @__PURE__ */
|
|
2577
|
-
/* @__PURE__ */
|
|
2975
|
+
/* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-2", children: [
|
|
2976
|
+
/* @__PURE__ */ jsx7(ProviderMark, { provider: props.status.provider, size: 18 }),
|
|
2977
|
+
/* @__PURE__ */ jsx7("span", { className: "text-[13.5px] font-semibold", children: props.status.label })
|
|
2578
2978
|
] }),
|
|
2579
|
-
ready ? /* @__PURE__ */
|
|
2580
|
-
/* @__PURE__ */
|
|
2979
|
+
ready ? /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-1 text-[12px] text-success", children: [
|
|
2980
|
+
/* @__PURE__ */ jsx7(CheckIcon, { size: 13 }),
|
|
2581
2981
|
props.status.billing === "subscription" ? `Signed in${props.status.plan ? ` \xB7 ${props.status.plan} plan` : ""}` : "Signed in with an API key (billed per use)"
|
|
2582
|
-
] }) : /* @__PURE__ */
|
|
2583
|
-
/* @__PURE__ */
|
|
2982
|
+
] }) : /* @__PURE__ */ jsxs7("span", { className: "flex items-start gap-1 text-[12px] leading-4 text-warning", children: [
|
|
2983
|
+
/* @__PURE__ */ jsx7(AlertIcon, { size: 13, className: "mt-px shrink-0" }),
|
|
2584
2984
|
props.status.problem
|
|
2585
2985
|
] }),
|
|
2586
|
-
props.status.quota.filter((w) => w.usedPercent !== null).length > 0 ? /* @__PURE__ */
|
|
2986
|
+
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
|
|
2587
2987
|
]
|
|
2588
2988
|
}
|
|
2589
2989
|
);
|
|
2590
2990
|
}
|
|
2591
2991
|
function FieldError({ id, children }) {
|
|
2592
|
-
return /* @__PURE__ */
|
|
2593
|
-
/* @__PURE__ */
|
|
2594
|
-
/* @__PURE__ */
|
|
2992
|
+
return /* @__PURE__ */ jsxs7("p", { id, role: "alert", className: "flex items-start gap-1.5 text-[12.5px] leading-5 text-destructive", children: [
|
|
2993
|
+
/* @__PURE__ */ jsx7(AlertIcon, { size: 14, className: "mt-0.5 shrink-0" }),
|
|
2994
|
+
/* @__PURE__ */ jsx7("span", { children })
|
|
2595
2995
|
] });
|
|
2596
2996
|
}
|
|
2597
2997
|
function NewSessionDialog(props) {
|
|
2598
2998
|
const client = useCodingSessionsClient();
|
|
2599
2999
|
const state = useCodingSessionsState();
|
|
2600
3000
|
const now = useMinuteClock();
|
|
2601
|
-
const [provider, setProvider] =
|
|
2602
|
-
const [folder, setFolder] =
|
|
2603
|
-
const [choice, setChoice] =
|
|
2604
|
-
const [prompt, setPrompt] =
|
|
2605
|
-
const [errors, setErrors] =
|
|
2606
|
-
const [problem, setProblem] =
|
|
2607
|
-
const [starting, setStarting] =
|
|
2608
|
-
const [creating, setCreating] =
|
|
2609
|
-
const
|
|
2610
|
-
const
|
|
2611
|
-
const
|
|
2612
|
-
|
|
3001
|
+
const [provider, setProvider] = useState6("claude");
|
|
3002
|
+
const [folder, setFolder] = useState6("");
|
|
3003
|
+
const [choice, setChoice] = useState6({ model: null, effort: null });
|
|
3004
|
+
const [prompt, setPrompt] = useState6("");
|
|
3005
|
+
const [errors, setErrors] = useState6({});
|
|
3006
|
+
const [problem, setProblem] = useState6(null);
|
|
3007
|
+
const [starting, setStarting] = useState6(false);
|
|
3008
|
+
const [creating, setCreating] = useState6(false);
|
|
3009
|
+
const [agent, setAgent] = useState6(null);
|
|
3010
|
+
const [agentDetails, setAgentDetails] = useState6(null);
|
|
3011
|
+
const [agentMissing, setAgentMissing] = useState6(null);
|
|
3012
|
+
const promptRef = useRef3(null);
|
|
3013
|
+
const folderRef = useRef3(null);
|
|
3014
|
+
const agentRef = useRef3(null);
|
|
3015
|
+
useEffect4(() => {
|
|
2613
3016
|
if (!props.open) return;
|
|
2614
3017
|
setProblem(null);
|
|
2615
3018
|
setErrors({});
|
|
2616
3019
|
void client.refreshProviders();
|
|
2617
3020
|
void client.refreshFolders();
|
|
2618
3021
|
}, [props.open, client]);
|
|
2619
|
-
|
|
3022
|
+
useEffect4(() => {
|
|
2620
3023
|
if (!folder && state.folders.data[0]?.exists) setFolder(state.folders.data[0].path);
|
|
2621
3024
|
}, [state.folders.data, folder]);
|
|
2622
|
-
|
|
3025
|
+
useEffect4(() => {
|
|
2623
3026
|
const ready = state.providers.data.filter((p) => p.ready);
|
|
2624
3027
|
const current = state.providers.data.find((p) => p.provider === provider);
|
|
2625
3028
|
if (current && !current.ready && ready[0]) setProvider(ready[0].provider);
|
|
@@ -2645,9 +3048,22 @@ function NewSessionDialog(props) {
|
|
|
2645
3048
|
focusField(first);
|
|
2646
3049
|
return;
|
|
2647
3050
|
}
|
|
3051
|
+
const missing = missingRequiredVariable(agentDetails, agent);
|
|
3052
|
+
setAgentMissing(missing);
|
|
3053
|
+
if (missing) {
|
|
3054
|
+
document.getElementById(`cs-agent-var-${missing}`)?.focus();
|
|
3055
|
+
return;
|
|
3056
|
+
}
|
|
2648
3057
|
setStarting(true);
|
|
2649
3058
|
try {
|
|
2650
|
-
const result = await client.start({
|
|
3059
|
+
const result = await client.start({
|
|
3060
|
+
provider,
|
|
3061
|
+
cwd: folder.trim(),
|
|
3062
|
+
prompt,
|
|
3063
|
+
model: choice.model,
|
|
3064
|
+
effort: choice.effort,
|
|
3065
|
+
...agent ? { agent } : {}
|
|
3066
|
+
});
|
|
2651
3067
|
setPrompt("");
|
|
2652
3068
|
props.onStarted(result.session.id);
|
|
2653
3069
|
} catch (error) {
|
|
@@ -2683,16 +3099,16 @@ function NewSessionDialog(props) {
|
|
|
2683
3099
|
if (field === "folder") delete next.createFolder;
|
|
2684
3100
|
return next;
|
|
2685
3101
|
});
|
|
2686
|
-
return /* @__PURE__ */
|
|
2687
|
-
/* @__PURE__ */
|
|
2688
|
-
/* @__PURE__ */
|
|
2689
|
-
/* @__PURE__ */
|
|
3102
|
+
return /* @__PURE__ */ jsx7(Dialog2, { open: props.open, onOpenChange: props.onOpenChange, children: /* @__PURE__ */ jsxs7(DialogContent2, { className: "max-w-[560px]", children: [
|
|
3103
|
+
/* @__PURE__ */ jsxs7(DialogHeader2, { children: [
|
|
3104
|
+
/* @__PURE__ */ jsx7(DialogTitle2, { children: "New coding session" }),
|
|
3105
|
+
/* @__PURE__ */ jsxs7(DialogDescription, { children: [
|
|
2690
3106
|
"Runs on your own ",
|
|
2691
3107
|
provider === "claude" ? "Claude" : "ChatGPT",
|
|
2692
3108
|
" sign-in, in a folder on this computer."
|
|
2693
3109
|
] })
|
|
2694
3110
|
] }),
|
|
2695
|
-
/* @__PURE__ */
|
|
3111
|
+
/* @__PURE__ */ jsxs7(
|
|
2696
3112
|
"form",
|
|
2697
3113
|
{
|
|
2698
3114
|
noValidate: true,
|
|
@@ -2702,13 +3118,13 @@ function NewSessionDialog(props) {
|
|
|
2702
3118
|
},
|
|
2703
3119
|
className: "flex min-h-0 flex-col",
|
|
2704
3120
|
children: [
|
|
2705
|
-
/* @__PURE__ */
|
|
2706
|
-
/* @__PURE__ */
|
|
2707
|
-
/* @__PURE__ */
|
|
2708
|
-
state.providers.loading && state.providers.loadedAt === null ? /* @__PURE__ */
|
|
2709
|
-
/* @__PURE__ */
|
|
2710
|
-
/* @__PURE__ */
|
|
2711
|
-
] }) : state.providers.error ? /* @__PURE__ */
|
|
3121
|
+
/* @__PURE__ */ jsxs7("div", { className: "cs-dialog-body space-y-5 py-1 pr-1", children: [
|
|
3122
|
+
/* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", ref: agentRef, children: [
|
|
3123
|
+
/* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Agent" }),
|
|
3124
|
+
state.providers.loading && state.providers.loadedAt === null ? /* @__PURE__ */ jsxs7("div", { className: "flex gap-2", children: [
|
|
3125
|
+
/* @__PURE__ */ jsx7("div", { className: "cs-skeleton h-[68px] flex-1 rounded-xl" }),
|
|
3126
|
+
/* @__PURE__ */ jsx7("div", { className: "cs-skeleton h-[68px] flex-1 rounded-xl" })
|
|
3127
|
+
] }) : 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(
|
|
2712
3128
|
ProviderCard,
|
|
2713
3129
|
{
|
|
2714
3130
|
status: p,
|
|
@@ -2721,14 +3137,31 @@ function NewSessionDialog(props) {
|
|
|
2721
3137
|
},
|
|
2722
3138
|
p.provider
|
|
2723
3139
|
)) }),
|
|
2724
|
-
errors.agent ? /* @__PURE__ */
|
|
3140
|
+
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: [
|
|
2725
3141
|
selected.fix,
|
|
2726
3142
|
selected.installed && selected.loggedIn ? " You can still try \u2014 the run will say if it's still blocked." : ""
|
|
2727
3143
|
] }) : null
|
|
2728
3144
|
] }),
|
|
2729
|
-
/* @__PURE__ */
|
|
2730
|
-
/* @__PURE__ */
|
|
2731
|
-
|
|
3145
|
+
/* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
|
|
3146
|
+
/* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "AI Matrx agent" }),
|
|
3147
|
+
/* @__PURE__ */ jsx7(
|
|
3148
|
+
AgentField,
|
|
3149
|
+
{
|
|
3150
|
+
transport: client.transport,
|
|
3151
|
+
open: props.open,
|
|
3152
|
+
value: agent,
|
|
3153
|
+
onChange: (next) => {
|
|
3154
|
+
setAgent(next);
|
|
3155
|
+
setAgentMissing(null);
|
|
3156
|
+
},
|
|
3157
|
+
missing: agentMissing,
|
|
3158
|
+
onDetails: setAgentDetails
|
|
3159
|
+
}
|
|
3160
|
+
)
|
|
3161
|
+
] }),
|
|
3162
|
+
/* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
|
|
3163
|
+
/* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Folder" }),
|
|
3164
|
+
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(
|
|
2732
3165
|
"button",
|
|
2733
3166
|
{
|
|
2734
3167
|
type: "button",
|
|
@@ -2738,21 +3171,21 @@ function NewSessionDialog(props) {
|
|
|
2738
3171
|
},
|
|
2739
3172
|
disabled: !f.exists,
|
|
2740
3173
|
title: f.exists ? f.path : `${f.path} no longer exists`,
|
|
2741
|
-
className:
|
|
3174
|
+
className: cn5(
|
|
2742
3175
|
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-[12.5px]",
|
|
2743
3176
|
folder === f.path ? "bg-accent text-accent-foreground" : "hover:bg-accent/50",
|
|
2744
3177
|
!f.exists && "opacity-50"
|
|
2745
3178
|
),
|
|
2746
3179
|
children: [
|
|
2747
|
-
/* @__PURE__ */
|
|
2748
|
-
/* @__PURE__ */
|
|
2749
|
-
/* @__PURE__ */
|
|
3180
|
+
/* @__PURE__ */ jsx7(FolderIcon, { size: 14, className: "shrink-0 text-muted-foreground" }),
|
|
3181
|
+
/* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate", children: prettyPath2(f.path) }),
|
|
3182
|
+
/* @__PURE__ */ jsx7("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: f.exists ? relativeTime(f.lastUsedAt, now) : "missing" })
|
|
2750
3183
|
]
|
|
2751
3184
|
},
|
|
2752
3185
|
f.path
|
|
2753
|
-
)) }) : state.folders.loading ? /* @__PURE__ */
|
|
2754
|
-
/* @__PURE__ */
|
|
2755
|
-
|
|
3186
|
+
)) }) : state.folders.loading ? /* @__PURE__ */ jsx7("div", { className: "cs-skeleton h-10 rounded-lg" }) : null,
|
|
3187
|
+
/* @__PURE__ */ jsx7(
|
|
3188
|
+
Input2,
|
|
2756
3189
|
{
|
|
2757
3190
|
ref: folderRef,
|
|
2758
3191
|
value: folder,
|
|
@@ -2767,18 +3200,18 @@ function NewSessionDialog(props) {
|
|
|
2767
3200
|
spellCheck: false
|
|
2768
3201
|
}
|
|
2769
3202
|
),
|
|
2770
|
-
errors.folder ? /* @__PURE__ */
|
|
2771
|
-
/* @__PURE__ */
|
|
2772
|
-
errors.createFolder ? /* @__PURE__ */
|
|
2773
|
-
creating ? /* @__PURE__ */
|
|
3203
|
+
errors.folder ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: [
|
|
3204
|
+
/* @__PURE__ */ jsx7(FieldError, { id: "cs-err-folder", children: errors.folder }),
|
|
3205
|
+
errors.createFolder ? /* @__PURE__ */ jsxs7(Button3, { type: "button", size: "sm", variant: "outline", onClick: () => void createFolder(), disabled: creating, className: "gap-1.5", children: [
|
|
3206
|
+
creating ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 13 }) : /* @__PURE__ */ jsx7(FolderIcon, { size: 13 }),
|
|
2774
3207
|
"Create this folder"
|
|
2775
3208
|
] }) : null
|
|
2776
3209
|
] }) : null
|
|
2777
3210
|
] }),
|
|
2778
|
-
/* @__PURE__ */
|
|
2779
|
-
/* @__PURE__ */
|
|
2780
|
-
/* @__PURE__ */
|
|
2781
|
-
|
|
3211
|
+
/* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
|
|
3212
|
+
/* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "What should it do?" }),
|
|
3213
|
+
/* @__PURE__ */ jsx7(
|
|
3214
|
+
Textarea2,
|
|
2782
3215
|
{
|
|
2783
3216
|
ref: promptRef,
|
|
2784
3217
|
value: prompt,
|
|
@@ -2799,25 +3232,25 @@ function NewSessionDialog(props) {
|
|
|
2799
3232
|
"aria-describedby": errors.prompt ? "cs-err-prompt" : void 0
|
|
2800
3233
|
}
|
|
2801
3234
|
),
|
|
2802
|
-
errors.prompt ? /* @__PURE__ */
|
|
3235
|
+
errors.prompt ? /* @__PURE__ */ jsx7(FieldError, { id: "cs-err-prompt", children: errors.prompt }) : null
|
|
2803
3236
|
] }),
|
|
2804
|
-
/* @__PURE__ */
|
|
2805
|
-
/* @__PURE__ */
|
|
2806
|
-
/* @__PURE__ */
|
|
2807
|
-
/* @__PURE__ */
|
|
3237
|
+
/* @__PURE__ */ jsxs7("fieldset", { className: "space-y-2", children: [
|
|
3238
|
+
/* @__PURE__ */ jsx7("legend", { className: "mb-2 text-[12.5px] font-medium", children: "Model and thinking effort" }),
|
|
3239
|
+
/* @__PURE__ */ jsx7(ModelPicker, { status: selected, value: choice, onChange: setChoice, appearance: "field" }),
|
|
3240
|
+
/* @__PURE__ */ jsxs7("p", { className: "text-[11.5px] leading-4 text-muted-foreground", children: [
|
|
2808
3241
|
"Default is ",
|
|
2809
3242
|
defaultModelWords(selected),
|
|
2810
3243
|
". You can change it later from the chat's header."
|
|
2811
3244
|
] })
|
|
2812
3245
|
] }),
|
|
2813
|
-
problem ? /* @__PURE__ */
|
|
3246
|
+
problem ? /* @__PURE__ */ jsx7(FieldError, { id: "cs-err-start", children: problem }) : null
|
|
2814
3247
|
] }),
|
|
2815
|
-
/* @__PURE__ */
|
|
2816
|
-
/* @__PURE__ */
|
|
2817
|
-
/* @__PURE__ */
|
|
2818
|
-
starting ? /* @__PURE__ */
|
|
3248
|
+
/* @__PURE__ */ jsxs7(DialogFooter2, { className: "pt-4", children: [
|
|
3249
|
+
/* @__PURE__ */ jsx7(Button3, { type: "button", variant: "ghost", onClick: () => props.onOpenChange(false), children: "Cancel" }),
|
|
3250
|
+
/* @__PURE__ */ jsxs7(Button3, { type: "submit", disabled: starting, className: "gap-1.5", children: [
|
|
3251
|
+
starting ? /* @__PURE__ */ jsx7(SpinnerIcon, { size: 14 }) : null,
|
|
2819
3252
|
starting ? "Starting\u2026" : "Start session",
|
|
2820
|
-
!starting ? /* @__PURE__ */
|
|
3253
|
+
!starting ? /* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2318\u21B5" }) : null
|
|
2821
3254
|
] })
|
|
2822
3255
|
] })
|
|
2823
3256
|
]
|
|
@@ -2827,34 +3260,34 @@ function NewSessionDialog(props) {
|
|
|
2827
3260
|
}
|
|
2828
3261
|
function Home({ onNew }) {
|
|
2829
3262
|
const state = useCodingSessionsState();
|
|
2830
|
-
return /* @__PURE__ */
|
|
2831
|
-
/* @__PURE__ */
|
|
2832
|
-
/* @__PURE__ */
|
|
2833
|
-
/* @__PURE__ */
|
|
2834
|
-
/* @__PURE__ */
|
|
2835
|
-
/* @__PURE__ */
|
|
3263
|
+
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: [
|
|
3264
|
+
/* @__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 }) }),
|
|
3265
|
+
/* @__PURE__ */ jsx7("h1", { className: "text-[15px] font-semibold leading-5 tracking-[-0.01em]", children: "Drive Claude Code and Codex from here" }),
|
|
3266
|
+
/* @__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." }),
|
|
3267
|
+
/* @__PURE__ */ jsxs7(Button3, { className: "mt-5 gap-1.5", onClick: onNew, children: [
|
|
3268
|
+
/* @__PURE__ */ jsx7(PlusIcon, { size: 15 }),
|
|
2836
3269
|
"New session"
|
|
2837
3270
|
] }),
|
|
2838
|
-
/* @__PURE__ */
|
|
2839
|
-
/* @__PURE__ */
|
|
3271
|
+
/* @__PURE__ */ jsxs7("p", { className: "mt-3 text-[12px] text-muted-foreground", children: [
|
|
3272
|
+
/* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2325\u2318N" }),
|
|
2840
3273
|
" new session \xB7 ",
|
|
2841
|
-
/* @__PURE__ */
|
|
3274
|
+
/* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2318K" }),
|
|
2842
3275
|
" search your chats \xB7",
|
|
2843
3276
|
" ",
|
|
2844
|
-
/* @__PURE__ */
|
|
3277
|
+
/* @__PURE__ */ jsx7("kbd", { className: "cs-kbd", children: "\u2318/" }),
|
|
2845
3278
|
" all shortcuts"
|
|
2846
3279
|
] }),
|
|
2847
|
-
/* @__PURE__ */
|
|
2848
|
-
/* @__PURE__ */
|
|
2849
|
-
/* @__PURE__ */
|
|
2850
|
-
/* @__PURE__ */
|
|
2851
|
-
p.ready ? /* @__PURE__ */
|
|
3280
|
+
/* @__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: [
|
|
3281
|
+
/* @__PURE__ */ jsx7(ProviderMark, { provider: p.provider, size: 16 }),
|
|
3282
|
+
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1 text-[12.5px] leading-5", children: [
|
|
3283
|
+
/* @__PURE__ */ jsx7("span", { className: "font-medium", children: p.label }),
|
|
3284
|
+
p.ready ? /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground", children: [
|
|
2852
3285
|
" ",
|
|
2853
3286
|
"\u2014 ready",
|
|
2854
3287
|
p.plan ? ` on your ${p.plan} plan` : "",
|
|
2855
3288
|
p.billing === "api" ? " (API key, billed per use)" : ""
|
|
2856
3289
|
] }) : null,
|
|
2857
|
-
p.installed && p.version ? /* @__PURE__ */
|
|
3290
|
+
p.installed && p.version ? /* @__PURE__ */ jsxs7(
|
|
2858
3291
|
"span",
|
|
2859
3292
|
{
|
|
2860
3293
|
className: "block text-[11.5px] text-muted-foreground",
|
|
@@ -2865,20 +3298,20 @@ function Home({ onNew }) {
|
|
|
2865
3298
|
]
|
|
2866
3299
|
}
|
|
2867
3300
|
) : null,
|
|
2868
|
-
p.ready ? null : /* @__PURE__ */
|
|
3301
|
+
p.ready ? null : /* @__PURE__ */ jsxs7("span", { className: "block text-muted-foreground", children: [
|
|
2869
3302
|
p.problem,
|
|
2870
3303
|
" ",
|
|
2871
3304
|
p.fix
|
|
2872
3305
|
] })
|
|
2873
3306
|
] }),
|
|
2874
|
-
p.ready ? /* @__PURE__ */
|
|
3307
|
+
p.ready ? /* @__PURE__ */ jsx7(CheckIcon, { size: 15, className: "mt-0.5 text-success" }) : /* @__PURE__ */ jsx7(AlertIcon, { size: 15, className: "mt-0.5 text-warning" })
|
|
2875
3308
|
] }, p.provider)) })
|
|
2876
3309
|
] }) });
|
|
2877
3310
|
}
|
|
2878
3311
|
function useToast() {
|
|
2879
|
-
const [text, setText] =
|
|
2880
|
-
const timer =
|
|
2881
|
-
|
|
3312
|
+
const [text, setText] = useState6(null);
|
|
3313
|
+
const timer = useRef3(null);
|
|
3314
|
+
useEffect4(() => () => {
|
|
2882
3315
|
if (timer.current) clearTimeout(timer.current);
|
|
2883
3316
|
}, []);
|
|
2884
3317
|
const show = useCallback2((next) => {
|
|
@@ -2890,7 +3323,7 @@ function useToast() {
|
|
|
2890
3323
|
}
|
|
2891
3324
|
function Toast({ text }) {
|
|
2892
3325
|
if (!text) return null;
|
|
2893
|
-
return /* @__PURE__ */
|
|
3326
|
+
return /* @__PURE__ */ jsx7("div", { role: "status", className: "cs-toast", children: text });
|
|
2894
3327
|
}
|
|
2895
3328
|
var SIDEBAR_DEFAULT = 300;
|
|
2896
3329
|
var SIDEBAR_MIN = 220;
|
|
@@ -2899,7 +3332,7 @@ function clampWidth(n) {
|
|
|
2899
3332
|
return Math.round(Math.min(SIDEBAR_MAX, Math.max(SIDEBAR_MIN, n)));
|
|
2900
3333
|
}
|
|
2901
3334
|
function useSidebarLayout() {
|
|
2902
|
-
const [width, setWidthState] =
|
|
3335
|
+
const [width, setWidthState] = useState6(() => {
|
|
2903
3336
|
try {
|
|
2904
3337
|
const n = Number(localStorage.getItem("coding-sessions.sidebar-width"));
|
|
2905
3338
|
return Number.isFinite(n) && n > 0 ? clampWidth(n) : SIDEBAR_DEFAULT;
|
|
@@ -2907,7 +3340,7 @@ function useSidebarLayout() {
|
|
|
2907
3340
|
return SIDEBAR_DEFAULT;
|
|
2908
3341
|
}
|
|
2909
3342
|
});
|
|
2910
|
-
const [collapsed, setCollapsedState] =
|
|
3343
|
+
const [collapsed, setCollapsedState] = useState6(() => {
|
|
2911
3344
|
try {
|
|
2912
3345
|
return localStorage.getItem("coding-sessions.sidebar-collapsed") === "1";
|
|
2913
3346
|
} catch {
|
|
@@ -2932,8 +3365,8 @@ function useSidebarLayout() {
|
|
|
2932
3365
|
return { width, setWidth, collapsed, setCollapsed };
|
|
2933
3366
|
}
|
|
2934
3367
|
function Resizer(props) {
|
|
2935
|
-
const [dragging, setDragging] =
|
|
2936
|
-
return /* @__PURE__ */
|
|
3368
|
+
const [dragging, setDragging] = useState6(false);
|
|
3369
|
+
return /* @__PURE__ */ jsx7("div", { className: cn5("cs-resizer", dragging && "cs-resizer--dragging"), children: /* @__PURE__ */ jsx7(
|
|
2937
3370
|
"button",
|
|
2938
3371
|
{
|
|
2939
3372
|
type: "button",
|
|
@@ -2981,24 +3414,24 @@ var SHORTCUTS = [
|
|
|
2981
3414
|
{ keys: "\u2318/", what: "These shortcuts" }
|
|
2982
3415
|
];
|
|
2983
3416
|
function ShortcutsDialog(props) {
|
|
2984
|
-
return /* @__PURE__ */
|
|
2985
|
-
/* @__PURE__ */
|
|
2986
|
-
/* @__PURE__ */
|
|
2987
|
-
/* @__PURE__ */
|
|
3417
|
+
return /* @__PURE__ */ jsx7(Dialog2, { open: props.open, onOpenChange: props.onOpenChange, children: /* @__PURE__ */ jsxs7(DialogContent2, { className: "max-w-[420px]", children: [
|
|
3418
|
+
/* @__PURE__ */ jsxs7(DialogHeader2, { children: [
|
|
3419
|
+
/* @__PURE__ */ jsx7(DialogTitle2, { children: "Keyboard shortcuts" }),
|
|
3420
|
+
/* @__PURE__ */ jsx7(DialogDescription, { children: "Ctrl works in place of \u2318 on Windows and Linux." })
|
|
2988
3421
|
] }),
|
|
2989
|
-
/* @__PURE__ */
|
|
2990
|
-
/* @__PURE__ */
|
|
2991
|
-
/* @__PURE__ */
|
|
3422
|
+
/* @__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: [
|
|
3423
|
+
/* @__PURE__ */ jsx7("dt", { className: "text-muted-foreground", children: s.what }),
|
|
3424
|
+
/* @__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 }) })
|
|
2992
3425
|
] }, s.keys)) })
|
|
2993
3426
|
] }) });
|
|
2994
3427
|
}
|
|
2995
3428
|
var BASE_TITLE = "Coding sessions";
|
|
2996
3429
|
function useRunFinishedNotices(openSessionId, show) {
|
|
2997
3430
|
const client = useCodingSessionsClient();
|
|
2998
|
-
const unseen =
|
|
2999
|
-
const openRef =
|
|
3431
|
+
const unseen = useRef3(0);
|
|
3432
|
+
const openRef = useRef3(openSessionId);
|
|
3000
3433
|
openRef.current = openSessionId;
|
|
3001
|
-
|
|
3434
|
+
useEffect4(() => {
|
|
3002
3435
|
const reset = () => {
|
|
3003
3436
|
if (document.visibilityState === "visible") {
|
|
3004
3437
|
unseen.current = 0;
|
|
@@ -3033,9 +3466,9 @@ function useRunFinishedNotices(openSessionId, show) {
|
|
|
3033
3466
|
}
|
|
3034
3467
|
function NotifyToggle() {
|
|
3035
3468
|
const supported = typeof Notification !== "undefined";
|
|
3036
|
-
const [permission, setPermission] =
|
|
3469
|
+
const [permission, setPermission] = useState6(supported ? Notification.permission : "denied");
|
|
3037
3470
|
if (!supported || permission === "granted") return null;
|
|
3038
|
-
return /* @__PURE__ */
|
|
3471
|
+
return /* @__PURE__ */ jsx7(
|
|
3039
3472
|
"button",
|
|
3040
3473
|
{
|
|
3041
3474
|
type: "button",
|
|
@@ -3044,7 +3477,7 @@ function NotifyToggle() {
|
|
|
3044
3477
|
"aria-label": permission === "denied" ? "Notifications are blocked for this page in your browser's site settings" : "Notify me when a run finishes",
|
|
3045
3478
|
title: permission === "denied" ? "Notifications are blocked in your browser's site settings" : "Notify me when a run finishes",
|
|
3046
3479
|
disabled: permission === "denied",
|
|
3047
|
-
children: /* @__PURE__ */
|
|
3480
|
+
children: /* @__PURE__ */ jsx7(BellIcon, { size: 14 })
|
|
3048
3481
|
}
|
|
3049
3482
|
);
|
|
3050
3483
|
}
|
|
@@ -3056,20 +3489,20 @@ function isTyping(target) {
|
|
|
3056
3489
|
function Shell() {
|
|
3057
3490
|
const client = useCodingSessionsClient();
|
|
3058
3491
|
const state = useCodingSessionsState();
|
|
3059
|
-
const [selection, setSelection] =
|
|
3060
|
-
const [newOpen, setNewOpen] =
|
|
3061
|
-
const [shortcutsOpen, setShortcutsOpen] =
|
|
3062
|
-
const [changesOpen, setChangesOpen] =
|
|
3063
|
-
const [found, setFound] =
|
|
3492
|
+
const [selection, setSelection] = useState6(readHash);
|
|
3493
|
+
const [newOpen, setNewOpen] = useState6(false);
|
|
3494
|
+
const [shortcutsOpen, setShortcutsOpen] = useState6(false);
|
|
3495
|
+
const [changesOpen, setChangesOpen] = useState6(false);
|
|
3496
|
+
const [found, setFound] = useState6({});
|
|
3064
3497
|
const [theme, setTheme] = useTheme();
|
|
3065
3498
|
const [toast, showToast] = useToast();
|
|
3066
3499
|
const layout = useSidebarLayout();
|
|
3067
|
-
const searchRef =
|
|
3500
|
+
const searchRef = useRef3(null);
|
|
3068
3501
|
const select = useCallback2((next) => {
|
|
3069
3502
|
setSelection(next);
|
|
3070
3503
|
writeHash(next);
|
|
3071
3504
|
}, []);
|
|
3072
|
-
|
|
3505
|
+
useEffect4(() => {
|
|
3073
3506
|
const onHash = () => setSelection(readHash());
|
|
3074
3507
|
window.addEventListener("hashchange", onHash);
|
|
3075
3508
|
return () => window.removeEventListener("hashchange", onHash);
|
|
@@ -3079,14 +3512,14 @@ function Shell() {
|
|
|
3079
3512
|
const discovered = selection.kind === "discovered" ? state.discovered.data.find((d) => d.providerSessionId === selection.id) ?? found[`${selection.provider}:${selection.id}`] ?? null : null;
|
|
3080
3513
|
const run = session ? state.runs[session.id] : void 0;
|
|
3081
3514
|
const live = run !== void 0 && !isTerminalRunStatus(run.status);
|
|
3082
|
-
const order =
|
|
3515
|
+
const order = useMemo4(() => {
|
|
3083
3516
|
const known = new Set(state.sessions.data.map((s) => s.providerSessionId).filter(Boolean));
|
|
3084
3517
|
return [
|
|
3085
3518
|
...state.sessions.data.map((s) => ({ kind: "session", id: s.id })),
|
|
3086
3519
|
...state.discovered.data.filter((d) => !known.has(d.providerSessionId)).map((d) => ({ kind: "discovered", provider: d.provider, id: d.providerSessionId }))
|
|
3087
3520
|
];
|
|
3088
3521
|
}, [state.sessions.data, state.discovered.data]);
|
|
3089
|
-
|
|
3522
|
+
useEffect4(() => {
|
|
3090
3523
|
const onKey = (e) => {
|
|
3091
3524
|
const mod = e.metaKey || e.ctrlKey;
|
|
3092
3525
|
const key = e.key.toLowerCase();
|
|
@@ -3142,12 +3575,12 @@ function Shell() {
|
|
|
3142
3575
|
}, [client, layout, live, run, order, selection, select, showToast]);
|
|
3143
3576
|
let main;
|
|
3144
3577
|
if (selection.kind === "session") {
|
|
3145
|
-
main = session ? /* @__PURE__ */
|
|
3146
|
-
/* @__PURE__ */
|
|
3578
|
+
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: [
|
|
3579
|
+
/* @__PURE__ */ jsx7(SpinnerIcon, { size: 15 }),
|
|
3147
3580
|
" Loading\u2026"
|
|
3148
|
-
] }) : /* @__PURE__ */
|
|
3581
|
+
] }) : /* @__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." });
|
|
3149
3582
|
} else if (selection.kind === "discovered") {
|
|
3150
|
-
main = /* @__PURE__ */
|
|
3583
|
+
main = /* @__PURE__ */ jsx7(
|
|
3151
3584
|
DiscoveredView,
|
|
3152
3585
|
{
|
|
3153
3586
|
session: discovered,
|
|
@@ -3160,13 +3593,13 @@ function Shell() {
|
|
|
3160
3593
|
`${selection.provider}:${selection.id}`
|
|
3161
3594
|
);
|
|
3162
3595
|
} else {
|
|
3163
|
-
main = /* @__PURE__ */
|
|
3596
|
+
main = /* @__PURE__ */ jsx7(Home, { onNew: () => setNewOpen(true) });
|
|
3164
3597
|
}
|
|
3165
|
-
return /* @__PURE__ */
|
|
3166
|
-
/* @__PURE__ */
|
|
3167
|
-
/* @__PURE__ */
|
|
3168
|
-
layout.collapsed ? /* @__PURE__ */
|
|
3169
|
-
/* @__PURE__ */
|
|
3598
|
+
return /* @__PURE__ */ jsx7(ToastContext.Provider, { value: showToast, children: /* @__PURE__ */ jsxs7("div", { className: "cs-app flex h-full flex-col bg-background text-foreground", children: [
|
|
3599
|
+
/* @__PURE__ */ jsx7(ConnectionBanner, {}),
|
|
3600
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex min-h-0 flex-1", children: [
|
|
3601
|
+
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: [
|
|
3602
|
+
/* @__PURE__ */ jsx7(
|
|
3170
3603
|
"button",
|
|
3171
3604
|
{
|
|
3172
3605
|
type: "button",
|
|
@@ -3174,10 +3607,10 @@ function Shell() {
|
|
|
3174
3607
|
onClick: () => layout.setCollapsed(false),
|
|
3175
3608
|
"aria-label": "Show the sidebar (\u2318B)",
|
|
3176
3609
|
title: "Show sidebar \u2318B",
|
|
3177
|
-
children: /* @__PURE__ */
|
|
3610
|
+
children: /* @__PURE__ */ jsx7(SidebarIcon, { size: 15 })
|
|
3178
3611
|
}
|
|
3179
3612
|
),
|
|
3180
|
-
/* @__PURE__ */
|
|
3613
|
+
/* @__PURE__ */ jsx7(
|
|
3181
3614
|
"button",
|
|
3182
3615
|
{
|
|
3183
3616
|
type: "button",
|
|
@@ -3185,11 +3618,11 @@ function Shell() {
|
|
|
3185
3618
|
onClick: () => setNewOpen(true),
|
|
3186
3619
|
"aria-label": "New session",
|
|
3187
3620
|
title: "New session \u2325\u2318N",
|
|
3188
|
-
children: /* @__PURE__ */
|
|
3621
|
+
children: /* @__PURE__ */ jsx7(PlusIcon, { size: 15 })
|
|
3189
3622
|
}
|
|
3190
3623
|
)
|
|
3191
|
-
] }) : /* @__PURE__ */
|
|
3192
|
-
/* @__PURE__ */
|
|
3624
|
+
] }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3625
|
+
/* @__PURE__ */ jsx7(
|
|
3193
3626
|
Sidebar,
|
|
3194
3627
|
{
|
|
3195
3628
|
selection,
|
|
@@ -3199,14 +3632,14 @@ function Shell() {
|
|
|
3199
3632
|
width: layout.width,
|
|
3200
3633
|
searchRef,
|
|
3201
3634
|
onFound: (d) => setFound((f) => ({ ...f, [`${d.provider}:${d.providerSessionId}`]: d })),
|
|
3202
|
-
footer: /* @__PURE__ */
|
|
3635
|
+
footer: /* @__PURE__ */ jsx7(
|
|
3203
3636
|
ProvidersFooter,
|
|
3204
3637
|
{
|
|
3205
3638
|
theme,
|
|
3206
3639
|
setTheme,
|
|
3207
|
-
extra: /* @__PURE__ */
|
|
3208
|
-
/* @__PURE__ */
|
|
3209
|
-
/* @__PURE__ */
|
|
3640
|
+
extra: /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3641
|
+
/* @__PURE__ */ jsx7(NotifyToggle, {}),
|
|
3642
|
+
/* @__PURE__ */ jsx7(
|
|
3210
3643
|
"button",
|
|
3211
3644
|
{
|
|
3212
3645
|
type: "button",
|
|
@@ -3214,7 +3647,7 @@ function Shell() {
|
|
|
3214
3647
|
onClick: () => setShortcutsOpen(true),
|
|
3215
3648
|
"aria-label": "Keyboard shortcuts (\u2318/)",
|
|
3216
3649
|
title: "Keyboard shortcuts \u2318/",
|
|
3217
|
-
children: /* @__PURE__ */
|
|
3650
|
+
children: /* @__PURE__ */ jsx7(KeyboardIcon, { size: 14 })
|
|
3218
3651
|
}
|
|
3219
3652
|
)
|
|
3220
3653
|
] })
|
|
@@ -3222,11 +3655,11 @@ function Shell() {
|
|
|
3222
3655
|
)
|
|
3223
3656
|
}
|
|
3224
3657
|
),
|
|
3225
|
-
/* @__PURE__ */
|
|
3658
|
+
/* @__PURE__ */ jsx7(Resizer, { width: layout.width, setWidth: layout.setWidth })
|
|
3226
3659
|
] }),
|
|
3227
|
-
/* @__PURE__ */
|
|
3660
|
+
/* @__PURE__ */ jsx7("main", { className: "flex min-w-0 flex-1", children: main })
|
|
3228
3661
|
] }),
|
|
3229
|
-
/* @__PURE__ */
|
|
3662
|
+
/* @__PURE__ */ jsx7(
|
|
3230
3663
|
NewSessionDialog,
|
|
3231
3664
|
{
|
|
3232
3665
|
open: newOpen,
|
|
@@ -3237,12 +3670,12 @@ function Shell() {
|
|
|
3237
3670
|
}
|
|
3238
3671
|
}
|
|
3239
3672
|
),
|
|
3240
|
-
/* @__PURE__ */
|
|
3241
|
-
/* @__PURE__ */
|
|
3673
|
+
/* @__PURE__ */ jsx7(ShortcutsDialog, { open: shortcutsOpen, onOpenChange: setShortcutsOpen }),
|
|
3674
|
+
/* @__PURE__ */ jsx7(Toast, { text: toast })
|
|
3242
3675
|
] }) });
|
|
3243
3676
|
}
|
|
3244
3677
|
function CodingSessionsApp({ transport }) {
|
|
3245
|
-
return /* @__PURE__ */
|
|
3678
|
+
return /* @__PURE__ */ jsx7(CodingSessionsProvider, { transport, children: /* @__PURE__ */ jsx7(Shell, {}) });
|
|
3246
3679
|
}
|
|
3247
3680
|
export {
|
|
3248
3681
|
CodingSessionsApp,
|