@hellcoder/companion 0.107.0 → 0.107.1-preview.20260719040931.f983b4d
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/dist/assets/{AgentsPage-t4s7ZO2P.js → AgentsPage-DI5hdCnz.js} +5 -5
- package/dist/assets/{CronManager-C_0weC_z.js → CronManager-yX8i4C_S.js} +1 -1
- package/dist/assets/DashboardPage-D1nc0wHf.js +1 -0
- package/dist/assets/{IntegrationsPage-Gte53t7Z.js → IntegrationsPage-iSfvR9vX.js} +1 -1
- package/dist/assets/{LinearOAuthSettingsPage-DHJ73rFh.js → LinearOAuthSettingsPage-omExXsGc.js} +1 -1
- package/dist/assets/{LinearSettingsPage-D7ZHYkum.js → LinearSettingsPage-C4oBf1iO.js} +1 -1
- package/dist/assets/{Playground-DBWsv4R6.js → Playground-CjiZI9QY.js} +1 -1
- package/dist/assets/{PromptsPage-Cnjs3hD9.js → PromptsPage-CU6z49U6.js} +1 -1
- package/dist/assets/{RunsPage-B5PsNevy.js → RunsPage-mcU7OUoZ.js} +1 -1
- package/dist/assets/{SandboxManager-DpFA1it7.js → SandboxManager-BkYS-dK5.js} +1 -1
- package/dist/assets/SettingsPage-CyHMmTBB.js +1 -0
- package/dist/assets/{TailscalePage-CMG1g7e2.js → TailscalePage-CRyiyMcJ.js} +1 -1
- package/dist/assets/index-DMoY-FDD.css +1 -0
- package/dist/assets/index-DOle27vf.js +136 -0
- package/dist/assets/{sw-register-CS-6kwSW.js → sw-register-Dqdfho7x.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/package.json +1 -1
- package/server/auto-namer.test.ts +16 -0
- package/server/claude-cli-runner.ts +92 -0
- package/server/dashboard-scheduler.test.ts +73 -0
- package/server/dashboard-scheduler.ts +46 -0
- package/server/dashboard-store.test.ts +101 -0
- package/server/dashboard-store.ts +121 -0
- package/server/dashboard-summarizer.test.ts +216 -0
- package/server/dashboard-summarizer.ts +290 -0
- package/server/dashboard-types.ts +70 -0
- package/server/index.ts +4 -0
- package/server/linear-connections.test.ts +16 -0
- package/server/routes/dashboard-routes.test.ts +139 -0
- package/server/routes/dashboard-routes.ts +101 -0
- package/server/routes/settings-routes.ts +47 -1
- package/server/routes.test.ts +112 -0
- package/server/routes.ts +4 -0
- package/server/settings-manager.test.ts +12 -0
- package/server/settings-manager.ts +45 -1
- package/server/ws-bridge-codex.test.ts +24 -0
- package/dist/assets/SettingsPage-v8ndyXOz.js +0 -1
- package/dist/assets/index-Bp3e_166.js +0 -136
- package/dist/assets/index-D4AeOLki.css +0 -1
|
@@ -9,6 +9,19 @@ import { COMPANION_HOME } from "./paths.js";
|
|
|
9
9
|
|
|
10
10
|
export const DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-6";
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Nightly dashboard summarization runs over every active session, so it
|
|
14
|
+
* defaults to the cheapest capable model rather than the general default.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_DASHBOARD_MODEL = "claude-haiku-4-5";
|
|
17
|
+
export const DASHBOARD_MODEL_OPTIONS = [
|
|
18
|
+
"claude-haiku-4-5",
|
|
19
|
+
"claude-sonnet-4-6",
|
|
20
|
+
"claude-sonnet-5",
|
|
21
|
+
] as const;
|
|
22
|
+
export const DEFAULT_DASHBOARD_RUN_HOUR = 3;
|
|
23
|
+
export const DEFAULT_DASHBOARD_MAX_SESSIONS_PER_RUN = 30;
|
|
24
|
+
|
|
12
25
|
export type UpdateChannel = "stable" | "prerelease";
|
|
13
26
|
|
|
14
27
|
/**
|
|
@@ -62,6 +75,14 @@ export interface CompanionSettings {
|
|
|
62
75
|
aiValidationEnabled: boolean;
|
|
63
76
|
aiValidationAutoApprove: boolean;
|
|
64
77
|
aiValidationAutoDeny: boolean;
|
|
78
|
+
/** Opt-in for the nightly dashboard summarization job (burns tokens every night). */
|
|
79
|
+
dashboardEnabled: boolean;
|
|
80
|
+
/** Model used by the dashboard summarizer. Cheap-by-default (Haiku). */
|
|
81
|
+
dashboardModel: string;
|
|
82
|
+
/** Local hour (0-23) at which the nightly dashboard update runs. */
|
|
83
|
+
dashboardRunHour: number;
|
|
84
|
+
/** Cost safety valve: max sessions summarized per run. */
|
|
85
|
+
dashboardMaxSessionsPerRun: number;
|
|
65
86
|
publicUrl: string;
|
|
66
87
|
updateChannel: UpdateChannel;
|
|
67
88
|
dockerAutoUpdate: boolean;
|
|
@@ -107,6 +128,10 @@ let settings: CompanionSettings = {
|
|
|
107
128
|
aiValidationEnabled: false,
|
|
108
129
|
aiValidationAutoApprove: true,
|
|
109
130
|
aiValidationAutoDeny: false,
|
|
131
|
+
dashboardEnabled: false,
|
|
132
|
+
dashboardModel: DEFAULT_DASHBOARD_MODEL,
|
|
133
|
+
dashboardRunHour: DEFAULT_DASHBOARD_RUN_HOUR,
|
|
134
|
+
dashboardMaxSessionsPerRun: DEFAULT_DASHBOARD_MAX_SESSIONS_PER_RUN,
|
|
110
135
|
publicUrl: "",
|
|
111
136
|
updateChannel: "stable",
|
|
112
137
|
dockerAutoUpdate: false,
|
|
@@ -143,6 +168,21 @@ function normalize(raw: Partial<CompanionSettings> | null | undefined): Companio
|
|
|
143
168
|
aiValidationEnabled: typeof raw?.aiValidationEnabled === "boolean" ? raw.aiValidationEnabled : false,
|
|
144
169
|
aiValidationAutoApprove: typeof raw?.aiValidationAutoApprove === "boolean" ? raw.aiValidationAutoApprove : true,
|
|
145
170
|
aiValidationAutoDeny: typeof raw?.aiValidationAutoDeny === "boolean" ? raw.aiValidationAutoDeny : false,
|
|
171
|
+
dashboardEnabled: typeof raw?.dashboardEnabled === "boolean" ? raw.dashboardEnabled : false,
|
|
172
|
+
dashboardModel:
|
|
173
|
+
typeof raw?.dashboardModel === "string" && raw.dashboardModel.trim()
|
|
174
|
+
? raw.dashboardModel.trim()
|
|
175
|
+
: DEFAULT_DASHBOARD_MODEL,
|
|
176
|
+
dashboardRunHour:
|
|
177
|
+
typeof raw?.dashboardRunHour === "number" && Number.isInteger(raw.dashboardRunHour)
|
|
178
|
+
&& raw.dashboardRunHour >= 0 && raw.dashboardRunHour <= 23
|
|
179
|
+
? raw.dashboardRunHour
|
|
180
|
+
: DEFAULT_DASHBOARD_RUN_HOUR,
|
|
181
|
+
dashboardMaxSessionsPerRun:
|
|
182
|
+
typeof raw?.dashboardMaxSessionsPerRun === "number" && Number.isInteger(raw.dashboardMaxSessionsPerRun)
|
|
183
|
+
&& raw.dashboardMaxSessionsPerRun >= 1 && raw.dashboardMaxSessionsPerRun <= 200
|
|
184
|
+
? raw.dashboardMaxSessionsPerRun
|
|
185
|
+
: DEFAULT_DASHBOARD_MAX_SESSIONS_PER_RUN,
|
|
146
186
|
publicUrl: typeof raw?.publicUrl === "string" ? raw.publicUrl.trim().replace(/\/+$/, "") : "",
|
|
147
187
|
updateChannel: raw?.updateChannel === "prerelease" ? "prerelease" : "stable",
|
|
148
188
|
dockerAutoUpdate: typeof raw?.dockerAutoUpdate === "boolean" ? raw.dockerAutoUpdate : false,
|
|
@@ -180,7 +220,7 @@ export function getSettings(): CompanionSettings {
|
|
|
180
220
|
}
|
|
181
221
|
|
|
182
222
|
export function updateSettings(
|
|
183
|
-
patch: Partial<Pick<CompanionSettings, "anthropicApiKey" | "anthropicModel" | "claudeCodeOAuthToken" | "openaiApiKey" | "onboardingCompleted" | "linearApiKey" | "linearAutoTransition" | "linearAutoTransitionStateId" | "linearAutoTransitionStateName" | "linearArchiveTransition" | "linearArchiveTransitionStateId" | "linearArchiveTransitionStateName" | "linearOAuthClientId" | "linearOAuthClientSecret" | "linearOAuthWebhookSecret" | "linearOAuthAccessToken" | "linearOAuthRefreshToken" | "aiValidationEnabled" | "aiValidationAutoApprove" | "aiValidationAutoDeny" | "publicUrl" | "updateChannel" | "dockerAutoUpdate" | "proactiveKeepaliveEnabled" | "cliBridgeMode" | "claudeBridgeMode" | "claudeBridgeIngressUrl" | "claudeCompatBannerDismissedVersion">>,
|
|
223
|
+
patch: Partial<Pick<CompanionSettings, "anthropicApiKey" | "anthropicModel" | "claudeCodeOAuthToken" | "openaiApiKey" | "onboardingCompleted" | "linearApiKey" | "linearAutoTransition" | "linearAutoTransitionStateId" | "linearAutoTransitionStateName" | "linearArchiveTransition" | "linearArchiveTransitionStateId" | "linearArchiveTransitionStateName" | "linearOAuthClientId" | "linearOAuthClientSecret" | "linearOAuthWebhookSecret" | "linearOAuthAccessToken" | "linearOAuthRefreshToken" | "aiValidationEnabled" | "aiValidationAutoApprove" | "aiValidationAutoDeny" | "dashboardEnabled" | "dashboardModel" | "dashboardRunHour" | "dashboardMaxSessionsPerRun" | "publicUrl" | "updateChannel" | "dockerAutoUpdate" | "proactiveKeepaliveEnabled" | "cliBridgeMode" | "claudeBridgeMode" | "claudeBridgeIngressUrl" | "claudeCompatBannerDismissedVersion">>,
|
|
184
224
|
): CompanionSettings {
|
|
185
225
|
ensureLoaded();
|
|
186
226
|
settings = normalize({
|
|
@@ -204,6 +244,10 @@ export function updateSettings(
|
|
|
204
244
|
aiValidationEnabled: patch.aiValidationEnabled ?? settings.aiValidationEnabled,
|
|
205
245
|
aiValidationAutoApprove: patch.aiValidationAutoApprove ?? settings.aiValidationAutoApprove,
|
|
206
246
|
aiValidationAutoDeny: patch.aiValidationAutoDeny ?? settings.aiValidationAutoDeny,
|
|
247
|
+
dashboardEnabled: patch.dashboardEnabled ?? settings.dashboardEnabled,
|
|
248
|
+
dashboardModel: patch.dashboardModel ?? settings.dashboardModel,
|
|
249
|
+
dashboardRunHour: patch.dashboardRunHour ?? settings.dashboardRunHour,
|
|
250
|
+
dashboardMaxSessionsPerRun: patch.dashboardMaxSessionsPerRun ?? settings.dashboardMaxSessionsPerRun,
|
|
207
251
|
publicUrl: patch.publicUrl ?? settings.publicUrl,
|
|
208
252
|
updateChannel: patch.updateChannel ?? settings.updateChannel,
|
|
209
253
|
dockerAutoUpdate: patch.dockerAutoUpdate ?? settings.dockerAutoUpdate,
|
|
@@ -132,6 +132,10 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
132
132
|
aiValidationEnabled: false,
|
|
133
133
|
aiValidationAutoApprove: true,
|
|
134
134
|
aiValidationAutoDeny: false,
|
|
135
|
+
dashboardEnabled: false,
|
|
136
|
+
dashboardModel: "claude-haiku-4-5",
|
|
137
|
+
dashboardRunHour: 3,
|
|
138
|
+
dashboardMaxSessionsPerRun: 30,
|
|
135
139
|
publicUrl: "",
|
|
136
140
|
updateChannel: "stable",
|
|
137
141
|
dockerAutoUpdate: false,
|
|
@@ -1119,6 +1123,10 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1119
1123
|
aiValidationEnabled: true,
|
|
1120
1124
|
aiValidationAutoApprove: true,
|
|
1121
1125
|
aiValidationAutoDeny: true,
|
|
1126
|
+
dashboardEnabled: false,
|
|
1127
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1128
|
+
dashboardRunHour: 3,
|
|
1129
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1122
1130
|
publicUrl: "",
|
|
1123
1131
|
updateChannel: "stable",
|
|
1124
1132
|
dockerAutoUpdate: false,
|
|
@@ -1296,6 +1304,10 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1296
1304
|
aiValidationEnabled: false, // disabled
|
|
1297
1305
|
aiValidationAutoApprove: true,
|
|
1298
1306
|
aiValidationAutoDeny: true,
|
|
1307
|
+
dashboardEnabled: false,
|
|
1308
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1309
|
+
dashboardRunHour: 3,
|
|
1310
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1299
1311
|
publicUrl: "",
|
|
1300
1312
|
updateChannel: "stable",
|
|
1301
1313
|
dockerAutoUpdate: false,
|
|
@@ -1343,6 +1355,10 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1343
1355
|
aiValidationEnabled: true,
|
|
1344
1356
|
aiValidationAutoApprove: true,
|
|
1345
1357
|
aiValidationAutoDeny: true,
|
|
1358
|
+
dashboardEnabled: false,
|
|
1359
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1360
|
+
dashboardRunHour: 3,
|
|
1361
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1346
1362
|
publicUrl: "",
|
|
1347
1363
|
updateChannel: "stable",
|
|
1348
1364
|
dockerAutoUpdate: false,
|
|
@@ -1455,6 +1471,10 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1455
1471
|
aiValidationEnabled: true,
|
|
1456
1472
|
aiValidationAutoApprove: false, // disabled
|
|
1457
1473
|
aiValidationAutoDeny: true,
|
|
1474
|
+
dashboardEnabled: false,
|
|
1475
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1476
|
+
dashboardRunHour: 3,
|
|
1477
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1458
1478
|
publicUrl: "",
|
|
1459
1479
|
updateChannel: "stable",
|
|
1460
1480
|
dockerAutoUpdate: false,
|
|
@@ -1586,6 +1606,10 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1586
1606
|
aiValidationEnabled: true,
|
|
1587
1607
|
aiValidationAutoApprove: true,
|
|
1588
1608
|
aiValidationAutoDeny: false, // disabled
|
|
1609
|
+
dashboardEnabled: false,
|
|
1610
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1611
|
+
dashboardRunHour: 3,
|
|
1612
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1589
1613
|
publicUrl: "",
|
|
1590
1614
|
updateChannel: "stable",
|
|
1591
1615
|
dockerAutoUpdate: false,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as s,u as a,g as nt,a as n,j as e,n as at,b as ot,s as it}from"./index-Bp3e_166.js";const te=[{id:"general",label:"General"},{id:"webhooks",label:"Webhooks"},{id:"authentication",label:"Authentication"},{id:"notifications",label:"Notifications"},{id:"providers",label:"Providers"},{id:"anthropic",label:"Anthropic"},{id:"ai-validation",label:"AI Validation"},{id:"updates",label:"Updates"},{id:"telemetry",label:"Telemetry"},{id:"environments",label:"Environments"}];function lt({embedded:se=!1}){const[x,ce]=s.useState(""),[ne,ae]=s.useState("claude-sonnet-4-6"),[d,oe]=s.useState(!1),[w,Fe]=s.useState(!0),[g,C]=s.useState(!1),[ie,b]=s.useState(""),[re,v]=s.useState(!1),Me=a(t=>t.darkMode),Be=a(t=>t.toggleDarkMode),le=a(t=>t.diffBase),He=a(t=>t.setDiffBase),Qe=a(t=>t.notificationSound),_e=a(t=>t.toggleNotificationSound),de=a(t=>t.notificationDesktop),ue=a(t=>t.setNotificationDesktop),o=a(t=>t.updateInfo),V=a(t=>t.setUpdateInfo),Ge=a(t=>t.setUpdateOverlayActive),qe=typeof Notification<"u",[p,y]=s.useState("stable"),[S,P]=s.useState(!1),[A,R]=s.useState(!0),[pe,O]=s.useState("loopback"),[D,xe]=s.useState(!1),[$,me]=s.useState(!1),[he,j]=s.useState(""),[fe,U]=s.useState(""),[ge,We]=s.useState(nt()),[T,L]=s.useState(!1),[K,F]=s.useState(!0),[M,B]=s.useState(!1),[E,H]=s.useState(""),[be,ve]=s.useState("general"),[Ye,ye]=s.useState(!1),[Q,je]=s.useState(!1),[k,m]=s.useState(null),[h,ke]=s.useState(""),[_,Ne]=s.useState(!1),[f,we]=s.useState(""),[G,Ce]=s.useState(!1),[q,Se]=s.useState(!1),[Je,W]=s.useState(!1),[Ae,Ue]=s.useState(""),[ze,Te]=s.useState(!1),[Xe,Ee]=s.useState(!1),[N,Ie]=s.useState(null),[Y,Ve]=s.useState(!1),[u,Pe]=s.useState(null),[I,Ze]=s.useState(0),[J,Re]=s.useState(!1),[z,Oe]=s.useState(!1),[et,De]=s.useState(!1),$e=s.useRef(null),X=s.useRef({});s.useEffect(()=>{const t=$e.current;if(!t)return;const c=new IntersectionObserver(i=>{var Ke;let r=null;for(const ee of i)ee.isIntersecting&&(!r||ee.boundingClientRect.top<r.boundingClientRect.top)&&(r=ee);(Ke=r==null?void 0:r.target)!=null&&Ke.id&&ve(r.target.id)},{root:t,rootMargin:"-10% 0px -70% 0px",threshold:0});for(const i of te){const r=X.current[i.id];r&&c.observe(r)}return()=>c.disconnect()},[w]);const Le=s.useCallback(t=>{ve(t);const c=X.current[t];c&&c.scrollIntoView({behavior:"smooth",block:"start"})},[]);s.useEffect(()=>{n.getSettings().then(t=>{oe(t.anthropicApiKeyConfigured),Ne(t.claudeCodeOAuthTokenConfigured),Ce(t.openaiApiKeyConfigured),ae(t.anthropicModel||"claude-sonnet-4-6"),typeof t.aiValidationEnabled=="boolean"&&L(t.aiValidationEnabled),typeof t.aiValidationAutoApprove=="boolean"&&F(t.aiValidationAutoApprove),typeof t.aiValidationAutoDeny=="boolean"&&B(t.aiValidationAutoDeny),(t.updateChannel==="stable"||t.updateChannel==="prerelease")&&y(t.updateChannel),typeof t.dockerAutoUpdate=="boolean"&&P(t.dockerAutoUpdate),typeof t.proactiveKeepaliveEnabled=="boolean"&&R(t.proactiveKeepaliveEnabled),(t.cliBridgeMode==="loopback"||t.cliBridgeMode==="jsonHandoff")&&O(t.cliBridgeMode),typeof t.publicUrl=="string"&&(H(t.publicUrl),a.getState().setPublicUrl(t.publicUrl))}).catch(t=>b(t instanceof Error?t.message:String(t))).finally(()=>Fe(!1)),n.getAuthToken().then(t=>Ie(t.token)).catch(()=>{})},[]);async function tt(t){t.preventDefault(),C(!0),b(""),v(!1);try{const c=x.trim(),i={anthropicModel:ne.trim()||"claude-sonnet-4-6"};c&&(i.anthropicApiKey=c);const r=await n.updateSettings(i);oe(r.anthropicApiKeyConfigured),ce(""),v(!0),setTimeout(()=>v(!1),1800)}catch(c){b(c instanceof Error?c.message:String(c))}finally{C(!1)}}async function Z(t){const c=t==="aiValidationEnabled"?T:t==="aiValidationAutoApprove"?K:M,i=!c;t==="aiValidationEnabled"?L(i):t==="aiValidationAutoApprove"?F(i):B(i);try{await n.updateSettings({[t]:i})}catch{t==="aiValidationEnabled"?L(c):t==="aiValidationAutoApprove"?F(c):B(c)}}async function st(){xe(!0),j(""),U("");try{const t=await n.forceCheckForUpdate();V(t),t.updateAvailable&&t.latestVersion?j(`Update v${t.latestVersion} is available.`):j("You are up to date.")}catch(t){U(t instanceof Error?t.message:String(t))}finally{xe(!1)}}async function ct(){me(!0),j(""),U("");try{localStorage.setItem("companion_docker_prompt_pending","1");const t=await n.triggerUpdate();j(t.message),Ge(!0)}catch(t){localStorage.removeItem("companion_docker_prompt_pending"),U(t instanceof Error?t.message:String(t)),me(!1)}}const l=s.useCallback(t=>c=>{X.current[t]=c},[]);return e.jsxs("div",{className:`${se?"h-full":"h-[100dvh]"} bg-cc-bg text-cc-fg font-sans-ui antialiased flex flex-col`,children:[e.jsx("div",{className:"shrink-0 max-w-5xl w-full mx-auto px-4 sm:px-8 pt-6 sm:pt-10",children:e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold text-cc-fg",children:"Settings"}),e.jsx("p",{className:"mt-1 text-sm text-cc-muted",children:"Configure API access, notifications, appearance, and workspace defaults."})]}),!se&&e.jsx("button",{onClick:()=>{const t=a.getState().currentSessionId;t?at(t):ot()},className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer",children:"Back"})]})}),e.jsx("div",{className:"sm:hidden shrink-0 border-b border-cc-border",children:e.jsx("nav",{className:"flex gap-1 px-4 py-2 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden","aria-label":"Settings categories",children:te.map(t=>e.jsx("button",{type:"button",onClick:()=>Le(t.id),className:`shrink-0 px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${be===t.id?"text-cc-primary bg-cc-primary/8":"text-cc-muted hover:text-cc-fg hover:bg-cc-hover"}`,children:t.label},t.id))})}),e.jsxs("div",{className:"flex-1 min-h-0 flex max-w-5xl w-full mx-auto",children:[e.jsx("nav",{className:"hidden sm:flex flex-col gap-0.5 w-44 shrink-0 pt-2 pr-6 pl-8 sticky top-0 self-start","aria-label":"Settings categories",children:te.map(t=>e.jsx("button",{type:"button",onClick:()=>Le(t.id),className:`text-left px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${be===t.id?"text-cc-primary bg-cc-primary/8":"text-cc-muted hover:text-cc-fg hover:bg-cc-hover"}`,children:t.label},t.id))}),e.jsx("div",{ref:$e,className:"flex-1 min-w-0 overflow-y-auto px-4 sm:px-8 sm:pl-0 pb-safe",children:e.jsxs("div",{className:"space-y-10 py-4 sm:py-2",children:[e.jsxs("section",{id:"general",ref:l("general"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"General"}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("button",{type:"button",onClick:Be,className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg text-sm bg-cc-hover text-cc-fg hover:bg-cc-active transition-colors cursor-pointer",children:[e.jsx("span",{children:"Theme"}),e.jsx("span",{className:"text-xs text-cc-muted",children:Me?"Dark":"Light"})]}),e.jsxs("button",{type:"button",onClick:()=>He(le==="last-commit"?"default-branch":"last-commit"),className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg text-sm bg-cc-hover text-cc-fg hover:bg-cc-active transition-colors cursor-pointer",children:[e.jsx("span",{children:"Diff compare against"}),e.jsx("span",{className:"text-xs text-cc-muted",children:le==="last-commit"?"Last commit (HEAD)":"Default branch"})]}),e.jsx("p",{className:"text-xs text-cc-muted px-1",children:"Last commit shows only uncommitted changes. Default branch shows all changes since diverging from main."}),e.jsx("div",{className:"pt-3 border-t border-cc-border",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("span",{className:"block text-sm font-medium",children:"Claude Code bridge mode"}),e.jsx("p",{className:"mt-0.5 text-xs text-cc-muted",children:'How the Companion hands the bridge URL to the spawned Claude Code CLI. Loopback is the default fix for Claude Code v1.2.1+ which rejects the literal "localhost". JSON handoff is the more robust just-every/code-style approach: writes a temp descriptor with a one-shot token and passes its path via CLAUDE_BRIDGE_CONFIG.'})]}),e.jsxs("select",{"aria-label":"CLI bridge mode",value:pe,onChange:async t=>{const c=t.target.value==="jsonHandoff"?"jsonHandoff":"loopback",i=pe;O(c);try{await n.updateSettings({cliBridgeMode:c})}catch{O(i)}},className:"ml-3 px-2 py-1.5 text-xs bg-cc-bg rounded-lg border border-cc-border text-cc-fg focus:outline-none focus:ring-1 focus:ring-cc-primary",children:[e.jsx("option",{value:"loopback",children:"Loopback (default)"}),e.jsx("option",{value:"jsonHandoff",children:"JSON handoff (experimental)"})]})]})}),e.jsxs("div",{className:"pt-3 border-t border-cc-border",children:[e.jsxs("button",{type:"button",role:"switch","aria-checked":A,"aria-label":"Proactive keepalive relaunch",onClick:async()=>{const t=!A,c=A;R(t);try{await n.updateSettings({proactiveKeepaliveEnabled:t})}catch{R(c)}},className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg text-sm bg-cc-hover text-cc-fg hover:bg-cc-active transition-colors cursor-pointer",children:[e.jsx("span",{children:"Proactive keepalive relaunch"}),e.jsx("span",{className:"text-xs text-cc-muted",children:A?"On":"Off"})]}),e.jsx("p",{className:"mt-1 text-xs text-cc-muted px-1",children:"When on (default), a CLI process that exits unexpectedly with no browser attached is automatically relaunched to keep long-running sessions (agents, cron) alive. Turn off to experiment with letting dead sessions stay dead."})]})]})]}),e.jsxs("section",{id:"webhooks",ref:l("webhooks"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Webhooks"}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-xs text-cc-muted",children:"The public URL is used for webhook URLs that external services (Linear, GitHub) send events to. Set this to the externally-reachable address of your Companion instance."}),e.jsxs("p",{className:"text-xs text-cc-muted",children:["Tip:"," ",e.jsx("a",{href:"#/integrations/tailscale",className:"text-cc-primary hover:underline",children:"Use the Tailscale integration"})," ","to get an HTTPS URL automatically."]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-cc-fg mb-1.5",htmlFor:"public-url",children:"Public URL"}),e.jsx("input",{id:"public-url",type:"url","aria-label":"Public URL",value:E,onChange:t=>H(t.target.value),placeholder:"https://your-domain.example.com",className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg border border-cc-border text-cc-fg placeholder:text-cc-muted focus:outline-none focus:ring-1 focus:ring-cc-primary font-mono-code"}),e.jsx("p",{className:"mt-1.5 text-[10px] text-cc-muted",children:E?`Using: ${E}`:`Fallback: ${typeof window<"u"?window.location.origin:"http://localhost:3456"}`})]}),e.jsx("button",{type:"button",onClick:async()=>{C(!0),b("");try{const t=await n.updateSettings({publicUrl:E.trim()});H(t.publicUrl),a.getState().setPublicUrl(t.publicUrl),v(!0),setTimeout(()=>v(!1),1800)}catch(t){b(t instanceof Error?t.message:String(t))}finally{C(!1)}},disabled:g,className:"px-4 py-2 min-h-[44px] rounded-lg text-sm font-medium bg-cc-primary text-white hover:opacity-90 transition-opacity disabled:opacity-50 cursor-pointer",children:g?"Saving...":re?"Saved!":"Save Public URL"})]})]}),e.jsxs("section",{id:"authentication",ref:l("authentication"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Authentication"}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-xs text-cc-muted",children:"Use the auth token or QR code to connect additional devices (e.g. mobile over Tailscale)."}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",children:"Auth Token"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"flex-1 px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg font-mono-code select-all break-all flex items-center",children:N?Y?N:"••••••••••••••••":e.jsx("span",{className:"text-cc-muted",children:"Loading..."})}),e.jsx("button",{type:"button",onClick:()=>Ve(t=>!t),className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors cursor-pointer",title:Y?"Hide token":"Show token",children:Y?"Hide":"Show"}),e.jsx("button",{type:"button",onClick:()=>{N&&navigator.clipboard.writeText(N).then(()=>{De(!0),setTimeout(()=>De(!1),1500)})},disabled:!N,className:"px-3 py-2.5 min-h-[44px] rounded-lg text-sm bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",title:"Copy token to clipboard",children:et?"Copied":"Copy"})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",children:"Mobile Login QR"}),u&&u.length>0?e.jsxs("div",{className:"space-y-3",children:[u.length>1&&e.jsx("div",{className:"flex gap-1",children:u.map((t,c)=>e.jsx("button",{type:"button",onClick:()=>Ze(c),className:`px-3 py-1.5 rounded-md text-xs font-medium transition-colors cursor-pointer ${c===I?"bg-cc-primary text-white":"bg-cc-hover text-cc-muted hover:text-cc-fg"}`,children:t.label},t.label))}),e.jsx("div",{className:"inline-block rounded-lg bg-white p-2",children:e.jsx("img",{src:u[I].qrDataUrl,alt:`QR code for ${u[I].label} login`,className:"w-48 h-48"})}),e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-bg text-sm font-mono-code text-cc-fg break-all select-all",children:u[I].url}),e.jsx("p",{className:"text-xs text-cc-muted",children:"Scan with your phone's camera app — it will open the URL and auto-authenticate."})]}):u&&u.length===0?e.jsx("p",{className:"text-xs text-cc-muted",children:"No remote addresses detected (LAN or Tailscale). Connect to a network to generate a QR code."}):e.jsx("button",{type:"button",onClick:async()=>{Re(!0);try{const t=await n.getAuthQr();Pe(t.qrCodes)}catch{}finally{Re(!1)}},disabled:J,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${J?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:J?"Generating...":"Show QR Code"})]}),e.jsxs("div",{className:"pt-2",children:[e.jsx("button",{type:"button",onClick:async()=>{if(confirm("Regenerate auth token? All existing sessions on other devices will be signed out.")){Oe(!0);try{const t=await n.regenerateAuthToken();Ie(t.token),Ve(!0),Pe(null)}catch{}finally{Oe(!1)}}},disabled:z,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${z?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-error/10 hover:bg-cc-error/20 text-cc-error cursor-pointer"}`,children:z?"Regenerating...":"Regenerate Token"}),e.jsx("p",{className:"mt-1.5 text-xs text-cc-muted",children:"Creates a new token. All other signed-in devices will need to re-authenticate."})]})]})]}),e.jsxs("section",{id:"notifications",ref:l("notifications"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Notifications"}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("button",{type:"button",onClick:_e,className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg text-sm bg-cc-hover text-cc-fg hover:bg-cc-active transition-colors cursor-pointer",children:[e.jsx("span",{children:"Sound"}),e.jsx("span",{className:"text-xs text-cc-muted",children:Qe?"On":"Off"})]}),qe&&e.jsxs("button",{type:"button",onClick:async()=>{if(de)ue(!1);else{if(Notification.permission!=="granted"&&await Notification.requestPermission()!=="granted")return;ue(!0)}},className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg text-sm bg-cc-hover text-cc-fg hover:bg-cc-active transition-colors cursor-pointer",children:[e.jsx("span",{children:"Desktop Alerts"}),e.jsx("span",{className:"text-xs text-cc-muted",children:de?"On":"Off"})]})]})]}),e.jsxs("section",{id:"providers",ref:l("providers"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Providers"}),e.jsxs("div",{className:"space-y-6",children:[e.jsx("p",{className:"text-xs text-cc-muted",children:"Configure authentication tokens for Claude Code and Codex. These are injected into sessions automatically."}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"claude-code-token",children:"Claude Code OAuth Token"}),e.jsxs("p",{className:"text-xs text-cc-muted",children:["Run ",e.jsx("code",{className:"font-mono-code bg-cc-code-bg px-1 py-0.5 rounded text-cc-code-fg",children:"claude setup-token"})," in your terminal, then paste the token here."]}),e.jsx("input",{id:"claude-code-token",type:"password",value:_&&!ze&&!h?"••••••••••••••••":h,onChange:t=>ke(t.target.value),onFocus:()=>Te(!0),onBlur:()=>Te(!1),placeholder:_?"Enter a new token to replace":"Paste token from claude setup-token",className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg placeholder:text-cc-muted focus:outline-none focus:ring-1 focus:ring-cc-primary/40 transition-shadow"}),e.jsx("p",{className:"text-xs text-cc-muted",children:_?"Claude Code token configured":"Claude Code token not configured"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"openai-api-key",children:"OpenAI API Key (Codex)"}),e.jsxs("p",{className:"text-xs text-cc-muted",children:["Used to authenticate Codex sessions. You can also use ",e.jsx("code",{className:"font-mono-code bg-cc-code-bg px-1 py-0.5 rounded text-cc-code-fg",children:"codex --login"})," for device-based auth."]}),e.jsx("input",{id:"openai-api-key",type:"password",value:G&&!Xe&&!f?"••••••••••••••••":f,onChange:t=>we(t.target.value),onFocus:()=>Ee(!0),onBlur:()=>Ee(!1),placeholder:G?"Enter a new key to replace":"sk-...",className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg placeholder:text-cc-muted focus:outline-none focus:ring-1 focus:ring-cc-primary/40 transition-shadow"}),e.jsx("p",{className:"text-xs text-cc-muted",children:G?"OpenAI key configured":"OpenAI key not configured"})]}),Ae&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-error/10 border border-cc-error/20 text-xs text-cc-error",children:Ae}),Je&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-success/10 border border-cc-success/20 text-xs text-cc-success",children:"Provider settings saved."}),e.jsx("button",{type:"button",disabled:q||!h.trim()&&!f.trim(),onClick:async()=>{Se(!0),Ue(""),W(!1);try{const t={};h.trim()&&(t.claudeCodeOAuthToken=h.trim()),f.trim()&&(t.openaiApiKey=f.trim());const c=await n.updateSettings(t);Ne(c.claudeCodeOAuthTokenConfigured),Ce(c.openaiApiKeyConfigured),ke(""),we(""),W(!0),setTimeout(()=>W(!1),1800)}catch(t){Ue(t instanceof Error?t.message:String(t))}finally{Se(!1)}},className:`px-4 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${q||!h.trim()&&!f.trim()?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:q?"Saving...":"Save Provider Settings"})]})]}),e.jsxs("section",{id:"anthropic",ref:l("anthropic"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Anthropic"}),e.jsxs("form",{onSubmit:tt,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",htmlFor:"anthropic-key",children:"Anthropic API Key"}),e.jsx("input",{id:"anthropic-key",type:"password",value:d&&!Ye&&!x?"••••••••••••••••":x,onChange:t=>{ce(t.target.value),m(null)},onFocus:()=>ye(!0),onBlur:()=>ye(!1),placeholder:d?"Enter a new key to replace":"sk-ant-api03-...",className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg placeholder:text-cc-muted focus:outline-none focus:ring-1 focus:ring-cc-primary/40 transition-shadow"}),e.jsx("p",{className:"mt-1.5 text-xs text-cc-muted",children:"Auto-renaming is disabled until this key is configured."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",htmlFor:"anthropic-model",children:"Anthropic Model"}),e.jsx("input",{id:"anthropic-model",type:"text",value:ne,onChange:t=>ae(t.target.value),placeholder:"claude-sonnet-4-6",className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg placeholder:text-cc-muted focus:outline-none focus:ring-1 focus:ring-cc-primary/40 transition-shadow"})]}),ie&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-error/10 border border-cc-error/20 text-xs text-cc-error",children:ie}),re&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-success/10 border border-cc-success/20 text-xs text-cc-success",children:"Settings saved."}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-cc-muted",children:w?"Loading...":d?"Anthropic key configured":"Anthropic key not configured"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",disabled:Q||!x.trim(),onClick:async()=>{je(!0),m(null);try{const t=await n.verifyAnthropicKey(x.trim());m(t),setTimeout(()=>m(null),5e3)}catch(t){m({valid:!1,error:t instanceof Error?t.message:String(t)}),setTimeout(()=>m(null),5e3)}finally{je(!1)}},className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${Q||!x.trim()?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:Q?"Verifying...":"Verify"}),e.jsx("button",{type:"submit",disabled:g||w,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${g||w?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:g?"Saving...":"Save"})]})]}),k&&e.jsx("div",{className:`px-3 py-2 rounded-lg text-xs ${k.valid?"bg-cc-success/10 border border-cc-success/20 text-cc-success":"bg-cc-error/10 border border-cc-error/20 text-cc-error"}`,children:k.valid?"API key is valid.":`Invalid API key${k.error?`: ${k.error}`:"."}`})]})]}),e.jsxs("section",{id:"ai-validation",ref:l("ai-validation"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"AI Validation"}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-cc-muted leading-relaxed",children:"When enabled, an AI model evaluates tool calls before they execute. Safe operations are auto-approved, dangerous ones are blocked, and uncertain cases are shown to you with a recommendation. Requires an Anthropic API key. These settings serve as defaults for new sessions. Each session can override AI validation independently via the shield icon in the session header."}),e.jsxs("button",{type:"button",onClick:()=>Z("aiValidationEnabled"),disabled:!d,className:`w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg transition-colors ${d?"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer":"bg-cc-hover text-cc-muted cursor-not-allowed opacity-60"}`,children:[e.jsx("span",{className:"text-sm",children:"AI Validation Mode"}),e.jsx("span",{className:`text-xs font-medium ${T&&d?"text-cc-success":"text-cc-muted"}`,children:T&&d?"On":"Off"})]}),!d&&e.jsx("p",{className:"text-[11px] text-cc-warning",children:"Configure an Anthropic API key above to enable AI validation."}),T&&d&&e.jsxs(e.Fragment,{children:[e.jsxs("button",{type:"button",onClick:()=>Z("aiValidationAutoApprove"),className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors cursor-pointer",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm",children:"Auto-approve safe tools"}),e.jsx("p",{className:"text-[11px] text-cc-muted mt-0.5",children:"Automatically allow read-only tools and benign commands"})]}),e.jsx("span",{className:`text-xs font-medium ${K?"text-cc-success":"text-cc-muted"}`,children:K?"On":"Off"})]}),e.jsxs("button",{type:"button",onClick:()=>Z("aiValidationAutoDeny"),className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg bg-cc-hover hover:bg-cc-active text-cc-fg transition-colors cursor-pointer",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-sm",children:"Auto-deny dangerous tools"}),e.jsx("p",{className:"text-[11px] text-cc-muted mt-0.5",children:"Automatically block destructive commands like rm -rf"})]}),e.jsx("span",{className:`text-xs font-medium ${M?"text-cc-success":"text-cc-muted"}`,children:M?"On":"Off"})]})]})]})]}),e.jsxs("section",{id:"updates",ref:l("updates"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Updates"}),e.jsxs("div",{className:"space-y-3",children:[o?e.jsxs("p",{className:"text-xs text-cc-muted",children:["Current version: v",o.currentVersion,o.latestVersion?` • Latest: v${o.latestVersion}`:"",o.channel==="prerelease"?" (prerelease)":""]}):e.jsx("p",{className:"text-xs text-cc-muted",children:"Version information not loaded yet."}),e.jsxs("div",{children:[e.jsx("span",{id:"update-channel-label",className:"block text-sm font-medium mb-1.5",children:"Update Channel"}),e.jsxs("div",{className:"flex gap-1",role:"radiogroup","aria-labelledby":"update-channel-label",children:[e.jsx("button",{type:"button",role:"radio","aria-checked":p==="stable",onClick:async()=>{if(p!=="stable"){y("stable");try{await n.updateSettings({updateChannel:"stable"})}catch{y("prerelease");return}try{const t=await n.forceCheckForUpdate();V(t)}catch{}}},className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${p==="stable"?"bg-cc-primary text-white":"bg-cc-hover text-cc-muted hover:text-cc-fg hover:bg-cc-active"}`,children:"Stable"}),e.jsx("button",{type:"button",role:"radio","aria-checked":p==="prerelease",onClick:async()=>{if(p!=="prerelease"){y("prerelease");try{await n.updateSettings({updateChannel:"prerelease"})}catch{y("stable");return}try{const t=await n.forceCheckForUpdate();V(t)}catch{}}},className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${p==="prerelease"?"bg-cc-primary text-white":"bg-cc-hover text-cc-muted hover:text-cc-fg hover:bg-cc-active"}`,children:"Prerelease"})]}),e.jsx("p",{className:"mt-1.5 text-xs text-cc-muted",children:p==="prerelease"?"Tracking prerelease channel. You will receive preview builds from the latest main branch.":"Tracking stable channel. You will only receive versioned releases."})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("span",{className:"block text-sm font-medium",children:"Auto-update Docker image"}),e.jsx("p",{className:"mt-0.5 text-xs text-cc-muted",children:"Automatically re-pull the sandbox Docker image when updating The Companion"})]}),e.jsx("button",{type:"button",role:"switch","aria-checked":S,onClick:async()=>{const t=!S;P(t);try{await n.updateSettings({dockerAutoUpdate:t})}catch{P(!t)}},className:`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${S?"bg-cc-primary":"bg-cc-hover"}`,children:e.jsx("span",{className:`pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform transition-transform ${S?"translate-x-5":"translate-x-0"}`})})]}),fe&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-error/10 border border-cc-error/20 text-xs text-cc-error",children:fe}),he&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-success/10 border border-cc-success/20 text-xs text-cc-success",children:he}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:st,disabled:D,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${D?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:D?"Checking...":"Check for updates"}),o!=null&&o.isServiceMode?e.jsx("button",{type:"button",onClick:ct,disabled:$||o.updateInProgress||!o.updateAvailable,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${$||o.updateInProgress||!o.updateAvailable?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:$||o.updateInProgress?"Updating...":"Update & Restart"}):e.jsxs("p",{className:"text-xs text-cc-muted self-center",children:["Install service mode with ",e.jsx("code",{className:"font-mono-code bg-cc-code-bg px-1 py-0.5 rounded text-cc-code-fg",children:"the-companion install"})," to enable one-click updates."]})]})]})]}),e.jsxs("section",{id:"telemetry",ref:l("telemetry"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Telemetry"}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-cc-muted",children:"Anonymous product analytics and crash reports via PostHog to improve reliability."}),e.jsxs("button",{type:"button",onClick:()=>{const t=!ge;it(t),We(t)},className:"w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg text-sm bg-cc-hover text-cc-fg hover:bg-cc-active transition-colors cursor-pointer",children:[e.jsx("span",{children:"Usage analytics and errors"}),e.jsx("span",{className:"text-xs text-cc-muted",children:ge?"On":"Off"})]}),e.jsx("p",{className:"text-xs text-cc-muted",children:"Browser Do Not Track is respected automatically."})]})]}),e.jsxs("section",{id:"environments",ref:l("environments"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Environments"}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-cc-muted",children:"Manage reusable environment profiles used when creating sessions."}),e.jsx("button",{type:"button",onClick:()=>{window.location.hash="#/environments"},className:"px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium bg-cc-primary hover:bg-cc-primary-hover text-white transition-colors cursor-pointer",children:"Open Environments Page"})]})]})]})})]})]})}export{lt as SettingsPage};
|