claude-code-session-manager 0.109.0 → 0.110.0
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/{AgentLibrary-Br4Ispr4.js → AgentLibrary-Cm6MrOnF.js} +1 -1
- package/dist/assets/{Button-C8Mc6MEP.js → Button-CGVncJ6a.js} +1 -1
- package/dist/assets/{DataModel-Bz0MypYO.js → DataModel-C3hlMoa8.js} +1 -1
- package/dist/assets/{History-DT26Iy38.js → History-CTyfGNKn.js} +1 -1
- package/dist/assets/{Hooks-e4xUGEf-.js → Hooks-BXxCBibx.js} +3 -3
- package/dist/assets/{Library-B3rzEhvN.js → Library-aCs7zxAg.js} +1 -1
- package/dist/assets/{ListDetail-BAvci_aP.js → ListDetail-B9Hqk1_f.js} +1 -1
- package/dist/assets/{MarkdownEditor-DBWTGgRz.js → MarkdownEditor-Djfgp32k.js} +1 -1
- package/dist/assets/{McpServers-C-grBN21.js → McpServers-8HQC6QgR.js} +2 -2
- package/dist/assets/{Memory-BmM0Fz-C.js → Memory-c4SVE3l2.js} +1 -1
- package/dist/assets/{Panel-Dc6F8wb4.js → Panel-BEQTwE4z.js} +1 -1
- package/dist/assets/{Permissions-m_NnldFh.js → Permissions-BaYzgZtc.js} +3 -3
- package/dist/assets/{Plugins-BB0TLUC9.js → Plugins-DnXsVau7.js} +2 -2
- package/dist/assets/{ProvenanceBadge-k9PH0S2n.js → ProvenanceBadge-CT2vWps1.js} +1 -1
- package/dist/assets/RemoteMachines-DHJZfdJC.js +3 -0
- package/dist/assets/{SaveBar-DSMnbUVI.js → SaveBar-DwcHt3iR.js} +1 -1
- package/dist/assets/{Scheduler-CbIcJEfM.js → Scheduler-D6Gcuo0M.js} +7 -7
- package/dist/assets/{ScopeSwitcher-tHtloWbN.js → ScopeSwitcher-CgvWDc9Y.js} +1 -1
- package/dist/assets/Settings-CJoogVAB.js +4 -0
- package/dist/assets/{SkillReferenceGraph-Dndl1tzr.js → SkillReferenceGraph-4fq01kxq.js} +1 -1
- package/dist/assets/{Skills-CGnxroik.js → Skills-BU4ZX4h4.js} +1 -1
- package/dist/assets/{SystemPrompt-B3A3rHNp.js → SystemPrompt-BCEyMSEq.js} +1 -1
- package/dist/assets/{TagLibrary-k4CTiAYo.js → TagLibrary-m3It8Oal.js} +1 -1
- package/dist/assets/{TiptapBody-C2LfNQXw.js → TiptapBody-DVyBsfsT.js} +1 -1
- package/dist/assets/{Toggle-CTXTU1q5.js → Toggle-In_AExPV.js} +1 -1
- package/dist/assets/{ViewTabs-CfEfOSE1.js → ViewTabs-BLHjKUv-.js} +1 -1
- package/dist/assets/{historyTotals-Db0xy2Fg.js → historyTotals-BXDd3EzP.js} +1 -1
- package/dist/assets/index-CuiU3I-8.js +3077 -0
- package/dist/assets/{index-C8Smiz7z.css → index-Dutcsly-.css} +1 -1
- package/dist/assets/{settingsSchema-xxO9p4yF.js → settingsSchema-DD4bc5cT.js} +1 -1
- package/dist/assets/{useAgentsDirWatch-DLS1_moj.js → useAgentsDirWatch-DMQ_XZtr.js} +1 -1
- package/dist/assets/useRemotePeers-C9NfteSD.js +1 -0
- package/dist/index.html +2 -2
- package/package.json +2 -1
- package/plugins/session-manager-dev/skills/develop/SKILL.md +3 -1
- package/plugins/session-manager-dev/skills/send-feedback/SKILL.md +48 -15
- package/scripts/scheduler-mcp-server.cjs +29 -2
- package/src/main/build-info.json +4 -4
- package/src/main/chatRunner.cjs +7 -0
- package/src/main/index.cjs +6 -0
- package/src/main/ipcSchemas.cjs +28 -0
- package/src/main/lib/autoUpdater.cjs +190 -0
- package/src/main/lib/crossProjectFeedback.cjs +143 -6
- package/src/main/lib/mcpToolCatalog.cjs +12 -3
- package/src/main/lib/reaperHelpers.cjs +13 -1
- package/src/main/lib/relayClientAuth.cjs +133 -0
- package/src/main/lib/remoteClientSessions.cjs +84 -0
- package/src/main/lib/updaterSettings.cjs +64 -0
- package/src/main/remoteClient.cjs +42 -13
- package/src/main/remoteClientIpc.cjs +33 -1
- package/src/main/scheduler.cjs +16 -0
- package/src/main/updaterIpc.cjs +110 -0
- package/src/main/webRemote.cjs +276 -132
- package/src/preload/api.d.ts +55 -2
- package/src/preload/index.cjs +24 -1
- package/dist/assets/Settings-CW3w7knp.js +0 -6
- package/dist/assets/index-fJxuoRvi.js +0 -3077
package/src/preload/api.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import type { PromptSession } from '../renderer/state/promptSessions';
|
|
2
2
|
|
|
3
3
|
/** Mirrors the item shape returned by main/lib/prereqs.cjs checkPrereqs(). */
|
|
4
|
+
export type AutoUpdaterState =
|
|
5
|
+
| 'unsupported' | 'disabled' | 'idle' | 'checking'
|
|
6
|
+
| 'downloading' | 'ready' | 'deferred' | 'error';
|
|
7
|
+
|
|
8
|
+
export type AutoUpdaterStatus = {
|
|
9
|
+
state: AutoUpdaterState;
|
|
10
|
+
current: string;
|
|
11
|
+
latest: string | null;
|
|
12
|
+
progress: number | null;
|
|
13
|
+
error: string | null;
|
|
14
|
+
busyReason: string | null;
|
|
15
|
+
lastCheckedAt: number | null;
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
4
19
|
export interface PrereqItem {
|
|
5
20
|
id: string;
|
|
6
21
|
label: string;
|
|
@@ -1601,11 +1616,22 @@ export interface RemoteMachinePeer {
|
|
|
1601
1616
|
pairedAt: string;
|
|
1602
1617
|
clientPublicKey: string;
|
|
1603
1618
|
verifiedDevicePubKey: string | null;
|
|
1619
|
+
/** process.platform of the remote machine, last known (null until first authenticated). */
|
|
1620
|
+
os: string | null;
|
|
1604
1621
|
status: string;
|
|
1605
1622
|
reason: string | null;
|
|
1606
1623
|
sas: string | null;
|
|
1607
1624
|
}
|
|
1608
1625
|
|
|
1626
|
+
export interface RemoteClientDevice {
|
|
1627
|
+
deviceId: string;
|
|
1628
|
+
email: string;
|
|
1629
|
+
issuedAt: string;
|
|
1630
|
+
expiresAt: string;
|
|
1631
|
+
isOnline: boolean;
|
|
1632
|
+
devicePubKey: string;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1609
1635
|
export interface RemoteClientStatus {
|
|
1610
1636
|
peerId: string;
|
|
1611
1637
|
status: string;
|
|
@@ -1630,9 +1656,18 @@ export interface WebRemoteStatus {
|
|
|
1630
1656
|
e2eState: 'idle' | 'pending_sas' | 'authenticated' | 'failed';
|
|
1631
1657
|
/** 6-digit Short Authentication String pending user confirmation, or null. */
|
|
1632
1658
|
pendingSas: string | null;
|
|
1659
|
+
/** Every connected client's E2E state (no key material). */
|
|
1660
|
+
clients: WebRemoteClientStatus[];
|
|
1633
1661
|
devices: WebRemoteDevice[];
|
|
1634
1662
|
}
|
|
1635
1663
|
|
|
1664
|
+
export interface WebRemoteClientStatus {
|
|
1665
|
+
key: string;
|
|
1666
|
+
clientId: string | null;
|
|
1667
|
+
state: 'idle' | 'pending_sas' | 'authenticated' | 'failed';
|
|
1668
|
+
pendingSas: string | null;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1636
1671
|
export interface WebRemotePairResult {
|
|
1637
1672
|
ok: boolean;
|
|
1638
1673
|
deviceId?: string;
|
|
@@ -2144,10 +2179,23 @@ export interface SessionManagerAPI {
|
|
|
2144
2179
|
connect: (peerId: string) => Promise<{ status: string; reason: string | null; sas: string | null }>;
|
|
2145
2180
|
confirmSas: (peerId: string) => Promise<{ ok: boolean; reason?: string }>;
|
|
2146
2181
|
remove: (peerId: string) => Promise<{ ok: boolean }>;
|
|
2182
|
+
authStatus: () => Promise<{ paired: boolean; clientId: string | null }>;
|
|
2183
|
+
pair: (code: string, clientName?: string) => Promise<{ ok: boolean; clientId?: string; error?: string }>;
|
|
2184
|
+
unpair: () => Promise<{ ok: boolean }>;
|
|
2185
|
+
devices: () => Promise<{ ok: boolean; devices?: RemoteClientDevice[]; error?: string }>;
|
|
2186
|
+
add: (deviceId: string, machineName: string) => Promise<RemoteMachinePeer>;
|
|
2147
2187
|
send: (peerId: string, type: string, payload?: unknown) => Promise<unknown>;
|
|
2148
2188
|
onStatus: (handler: (status: RemoteClientStatus) => void) => () => void;
|
|
2149
2189
|
onEvent: (handler: (ev: RemoteClientEvent) => void) => () => void;
|
|
2150
2190
|
};
|
|
2191
|
+
updater: {
|
|
2192
|
+
status: () => Promise<AutoUpdaterStatus>;
|
|
2193
|
+
check: () => Promise<AutoUpdaterStatus>;
|
|
2194
|
+
install: (force?: boolean) => Promise<{ ok: boolean; error?: string }>;
|
|
2195
|
+
cancelDeferred: () => Promise<AutoUpdaterStatus>;
|
|
2196
|
+
setEnabled: (enabled: boolean) => Promise<AutoUpdaterStatus>;
|
|
2197
|
+
onStatus: (handler: (status: AutoUpdaterStatus) => void) => () => void;
|
|
2198
|
+
};
|
|
2151
2199
|
webRemote: {
|
|
2152
2200
|
getStatus: () => Promise<WebRemoteStatus>;
|
|
2153
2201
|
enable: () => Promise<WebRemoteMutationResult>;
|
|
@@ -2166,8 +2214,9 @@ export interface SessionManagerAPI {
|
|
|
2166
2214
|
/** Subscribe to the completion event broadcast after revokeAll. */
|
|
2167
2215
|
onRevokedAll: (handler: (ev: { revokedCount: number }) => void) => () => void;
|
|
2168
2216
|
/** Confirm that the SAS shown on the desktop matches the browser — marks the
|
|
2169
|
-
* E2E session as authenticated and unblocks MUTATE-tier commands.
|
|
2170
|
-
|
|
2217
|
+
* E2E session as authenticated and unblocks MUTATE-tier commands. Pass the
|
|
2218
|
+
* client's `key` when several clients are pending (else `ambiguous_pending_sas`). */
|
|
2219
|
+
confirmSas: (clientKey?: string) => Promise<WebRemoteMutationResult>;
|
|
2171
2220
|
};
|
|
2172
2221
|
chat: {
|
|
2173
2222
|
/** Spawn a headless `claude -p` run for a tab. Results arrive via the on* listeners. */
|
|
@@ -2187,6 +2236,10 @@ export interface SessionManagerAPI {
|
|
|
2187
2236
|
* tool) pushes a prompt into an open tab's queue from outside the
|
|
2188
2237
|
* renderer (PRD 753). */
|
|
2189
2238
|
onExternalSend: (handler: (e: ChatExternalSendEvent) => void) => () => void;
|
|
2239
|
+
/** Fires when a paired phone asks main to start a new Session (payload pre-validated in main). */
|
|
2240
|
+
onExternalNewSession: (
|
|
2241
|
+
handler: (e: { cwd: string; agentName: string; tag: AgentPersonaTag; title: string; prompt: string }) => void,
|
|
2242
|
+
) => () => void;
|
|
2190
2243
|
/** Classify a queued PromptTicket's text as 'inline' (run through
|
|
2191
2244
|
* chatRunner) or 'develop' (dispatch to /develop for PRD decomposition).
|
|
2192
2245
|
* A single bounded `claude -p` call, never a scheduler job. */
|
package/src/preload/index.cjs
CHANGED
|
@@ -405,6 +405,11 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
405
405
|
/** Confirm the short authentication string matches the remote machine. */
|
|
406
406
|
confirmSas: (peerId) => ipcRenderer.invoke('remoteClient:confirm-sas', { peerId }),
|
|
407
407
|
remove: (peerId) => ipcRenderer.invoke('remoteClient:remove', { peerId }),
|
|
408
|
+
authStatus: () => ipcRenderer.invoke('remoteClient:auth-status'),
|
|
409
|
+
pair: (code, clientName) => ipcRenderer.invoke('remoteClient:pair', { code, clientName }),
|
|
410
|
+
unpair: () => ipcRenderer.invoke('remoteClient:unpair'),
|
|
411
|
+
devices: () => ipcRenderer.invoke('remoteClient:devices'),
|
|
412
|
+
add: (deviceId, machineName) => ipcRenderer.invoke('remoteClient:add', { deviceId, machineName }),
|
|
408
413
|
send: (peerId, type, payload) => ipcRenderer.invoke('remoteClient:send', { peerId, type, payload }),
|
|
409
414
|
onStatus: (handler) => {
|
|
410
415
|
const listener = (_e, payload) => handler(payload);
|
|
@@ -417,6 +422,18 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
417
422
|
return () => ipcRenderer.removeListener('remoteClient:event', listener);
|
|
418
423
|
},
|
|
419
424
|
},
|
|
425
|
+
updater: {
|
|
426
|
+
status: () => ipcRenderer.invoke('updater:status'),
|
|
427
|
+
check: () => ipcRenderer.invoke('updater:check'),
|
|
428
|
+
install: (force) => ipcRenderer.invoke('updater:install', { force: force === true }),
|
|
429
|
+
cancelDeferred: () => ipcRenderer.invoke('updater:cancel-deferred'),
|
|
430
|
+
setEnabled: (enabled) => ipcRenderer.invoke('updater:set-enabled', { enabled }),
|
|
431
|
+
onStatus: (handler) => {
|
|
432
|
+
const listener = (_e, payload) => handler(payload);
|
|
433
|
+
ipcRenderer.on('updater:status', listener);
|
|
434
|
+
return () => ipcRenderer.removeListener('updater:status', listener);
|
|
435
|
+
},
|
|
436
|
+
},
|
|
420
437
|
webRemote: {
|
|
421
438
|
/** Current connection state (no token values). */
|
|
422
439
|
getStatus: () => ipcRenderer.invoke('webRemote:get-status'),
|
|
@@ -448,7 +465,7 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
448
465
|
},
|
|
449
466
|
/** Revoke ALL paired devices and tear down every session immediately. */
|
|
450
467
|
revokeAll: () => ipcRenderer.invoke('webRemote:revoke-all'),
|
|
451
|
-
confirmSas: () => ipcRenderer.invoke('webRemote:confirm-sas'),
|
|
468
|
+
confirmSas: (clientKey) => ipcRenderer.invoke('webRemote:confirm-sas', clientKey ? { clientKey } : undefined),
|
|
452
469
|
/** Push event when revokeAll completes (main broadcasts webRemote:revoked-all). */
|
|
453
470
|
onRevokedAll: (handler) => {
|
|
454
471
|
const listener = (_e, payload) => handler(payload);
|
|
@@ -509,6 +526,12 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
509
526
|
ipcRenderer.on('chat:external-send', listener);
|
|
510
527
|
return () => ipcRenderer.removeListener('chat:external-send', listener);
|
|
511
528
|
},
|
|
529
|
+
/** Fires when a paired phone asks main to start a new Session. */
|
|
530
|
+
onExternalNewSession: (handler) => {
|
|
531
|
+
const listener = (_e, payload) => handler(payload);
|
|
532
|
+
ipcRenderer.on('chat:external-new-session', listener);
|
|
533
|
+
return () => ipcRenderer.removeListener('chat:external-new-session', listener);
|
|
534
|
+
},
|
|
512
535
|
/** Classify a queued PromptTicket's text as 'inline' or 'develop'. */
|
|
513
536
|
classifyTicket: (payload) => ipcRenderer.invoke('chat:classify-ticket', payload),
|
|
514
537
|
/** Author a mechanical draft PRD from a queued PromptTicket classified 'develop'. */
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import{aD as l,an as e,S as P,A as H,n as K,a2 as Re,aU as ue,bb as Z,bi as Ie,W as Ae,D as ne,_ as Te,a as L,a0 as Pe,b6 as Oe,b3 as De,aY as $e,c as ae,aB as Me,b0 as Le,ba as re,b2 as Fe,aW as q,ap as _e,au as Be,J as He,H as ie,aL as Ue}from"./index-fJxuoRvi.js";import{P as ze}from"./Panel-Dc6F8wb4.js";import{S as Ge}from"./ScopeSwitcher-tHtloWbN.js";import{S as pe}from"./SaveBar-DSMnbUVI.js";import{u as Je,s as oe,E as Ke}from"./settingsSchema-xxO9p4yF.js";import{V as We}from"./ViewTabs-CfEfOSE1.js";import{T as Y}from"./Toggle-CTXTU1q5.js";import"./monaco-editor-BsIlgG7c.js";import"./claude-settings-schema-COigsajx.js";const Ve=[{id:"essentials",title:"Essentials",summary:"The knobs you reach for first.",keys:["model","language","outputStyle","permissions"]},{id:"git",title:"Git & Commits",summary:"How Claude writes commits and pull requests on your behalf.",keys:["attribution","includeGitInstructions","includeCoAuthoredBy"]},{id:"memory",title:"Memory & Plans",summary:"Context Claude keeps between sessions and where it files plans.",keys:["autoMemoryEnabled","plansDirectory","claudeMdExcludes","respectGitignore"]},{id:"model",title:"Model & Reasoning",summary:"Model allow/override lists, reasoning depth, and fast-mode toggles — machine-wide, with no per-Epic override yet. An Epic's Agent persona model (Agent Library) still wins over Essentials' plain model default.",advanced:!0,keys:["availableModels","modelOverrides","effortLevel","fastMode","fastModePerSessionOptIn","alwaysThinkingEnabled","fallbackModel","enforceAvailableModels","teammateDefaultModel","advisorModel"]},{id:"interface",title:"Interface",summary:"Visual polish — spinners, progress bars, motion.",keys:["spinnerTipsEnabled","spinnerTipsOverride","spinnerVerbs","terminalProgressBarEnabled","showTurnDuration","prefersReducedMotion","companyAnnouncements","statusLine","teammateMode"]},{id:"updates",title:"Updates & Cleanup",summary:"Release channel and how long transcripts stick around.",keys:["autoUpdatesChannel","cleanupPeriodDays"]},{id:"env",title:"Environment & Auth",summary:"Environment variables and auth-helper scripts.",keys:["env","apiKeyHelper","awsCredentialExport","awsAuthRefresh"]},{id:"hooks",title:"Hooks",summary:"Scripts Claude runs before/after tool use.",keys:["hooks","disableAllHooks","allowedHttpHookUrls","httpHookAllowedEnvVars"]},{id:"mcp",title:"MCP Servers",summary:"External tool providers Claude can talk to.",keys:["enableAllProjectMcpServers","enabledMcpjsonServers","disabledMcpjsonServers"]},{id:"plugins",title:"Plugins",summary:"Installed plugins, marketplaces, and per-plugin configuration.",keys:["enabledPlugins","extraKnownMarketplaces","skippedPlugins","skippedMarketplaces","pluginConfigs"]},{id:"filesystem",title:"File Picker & Sandbox",summary:"How Claude browses files and the sandbox it runs in.",keys:["fileSuggestion","sandbox","worktree"]},{id:"login",title:"Login",summary:"Which login method to force on startup.",keys:["forceLoginMethod","forceLoginOrgUUID"]},{id:"feedback",title:"Feedback",summary:"Session-quality surveys.",keys:["feedbackSurveyRate"]},{id:"advanced",title:"Advanced / Enterprise",summary:"Managed-settings-only keys and enterprise allow/denylists.",advanced:!0,keys:["allowedMcpServers","deniedMcpServers","allowManagedHooksOnly","allowManagedPermissionRulesOnly","allowManagedMcpServersOnly","strictKnownMarketplaces","blockedMarketplaces","pluginTrustMessage","otelHeadersHelper","skipWebFetchPreflight"]}],qe={mcp:"MCP",url:"URL",urls:"URLs",http:"HTTP",ui:"UI",id:"ID",uuid:"UUID",api:"API",aws:"AWS",otel:"OTel",json:"JSON"};function fe(t){return t.replace(/^\$/,"").replace(/([a-z])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").toLowerCase().split(/\s+/).filter(Boolean).map((o,r)=>{const a=qe[o];return a||(r===0?o.charAt(0).toUpperCase()+o.slice(1):o)}).join(" ")}function he(t){const s=new Set,n=[];for(const r of Ve){const a=r.keys.filter(c=>t.has(c));a.forEach(c=>s.add(c)),a.length!==0&&n.push({id:r.id,title:r.title,summary:r.summary,advanced:!!r.advanced,keys:a})}const o=Array.from(t).filter(r=>!s.has(r)&&r!=="$schema").sort();return o.length>0&&n.push({id:"other",title:"Other",summary:"Keys not yet grouped.",advanced:!1,keys:o}),n}function Xe(t,s){return he(t).map(n=>({id:n.id,title:n.title,advanced:n.advanced,total:n.keys.length,setCount:n.keys.filter(o=>s.has(o)).length}))}const Ye={};function ge(t,s){if(s)return{text:s,authored:!1};const n=Ye[t];return n?{text:n,authored:!0}:null}const Ze={essentials:"star",git:"link",memory:"memory",model:"sparkle",interface:"eye",updates:"reload",env:"keys",hooks:"hooks",mcp:"mcp",plugins:"plugins",filesystem:"folder",login:"lock",feedback:"send",advanced:"shield",other:"dot"},Qe=["user","project","local","default"],et={user:"user",project:"project",local:"local",default:"default"};function tt({node:t,targetScope:s,onOverride:n,schema:o}){const[r,a]=l.useState(""),[c,p]=l.useState(!1),[b,j]=l.useState(!0),i=t.kind==="object"?t:null,u=i?Object.keys(i.children):[],g=o.rootKeys(),y=new Set([...u,...g]),f=l.useMemo(()=>he(y),[Array.from(y).sort().join(",")]),w=l.useMemo(()=>Xe(y,new Set(u)),[Array.from(y).sort().join(","),u.join(",")]),[R,S]=l.useState(null),m=l.useRef(null),N=h=>{const k=f.find(E=>E.id===h);k!=null&&k.advanced&&!c&&p(!0),S(h)};l.useEffect(()=>{if(!R)return;S(null);const h=m.current,k=document.getElementById(`settings-group-${R}`);if(!h||!k)return;const E=k.getBoundingClientRect().top-h.getBoundingClientRect().top;h.scrollBy({top:E,behavior:"smooth"})},[R]);const I=l.useMemo(()=>f.filter(h=>c||!h.advanced).map(h=>({...h,keys:h.keys.filter(k=>{const E=(i==null?void 0:i.children[k])!==void 0;if(!b&&!E)return!1;if(!r.trim())return!0;const v=o.at([k]);return[k,fe(k),(v==null?void 0:v.description)??""].join(" ").toLowerCase().includes(r.toLowerCase())})})).filter(h=>h.keys.length>0),[f,r,c,b,i,o]);return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsxs("div",{className:"shrink-0 border-b border-line bg-bg-elev px-3 py-1.5 flex items-center gap-3 text-xs",children:[e.jsxs("span",{className:"text-fg-faint",children:["writing overrides to"," ",e.jsx("span",{className:"text-fg-dim font-medium",children:P[s].label})]}),e.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:b,onChange:h=>j(h.target.checked),className:"accent-accent"}),"show not-yet-configured"]}),e.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:c,onChange:h=>p(h.target.checked),className:"accent-accent"}),"show advanced"]}),e.jsx("div",{className:"flex-1"}),e.jsx("input",{value:r,onChange:h=>a(h.target.value),placeholder:"search settings…",className:"bg-bg border border-line rounded px-2 py-1 text-xs text-fg w-64"})]}),e.jsxs("div",{className:"flex-1 flex overflow-hidden",children:[e.jsx(st,{groups:w,onJump:N}),e.jsxs("div",{ref:m,className:"flex-1 overflow-auto py-3",children:[I.map(h=>e.jsx(nt,{id:h.id,title:h.title,summary:h.summary,advanced:h.advanced,children:h.keys.map(k=>{const E=i==null?void 0:i.children[k],v=o.at([k]);return e.jsx(at,{keyName:k,node:E,info:v,targetScope:s,onOverride:(d,C)=>n([k],d,C)},k)})},h.id)),I.length===0&&e.jsxs("div",{className:"px-6 py-12 text-center text-fg-faint text-sm",children:['no settings match "',r,'"']})]})]})]})}function st({groups:t,onJump:s}){return e.jsx("nav",{className:"shrink-0 w-48 border-r border-line bg-bg-elev/30 overflow-y-auto py-3",children:t.map(n=>e.jsxs("button",{onClick:()=>s(n.id),className:"w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-bg-hi transition-colors",title:`jump to ${n.title}`,children:[e.jsx(H,{name:Ze[n.id]??"dot",size:15,className:"text-fg-faint shrink-0"}),e.jsx("span",{className:"flex-1 min-w-0 truncate text-xs text-fg-dim",children:n.title}),e.jsxs("span",{className:"text-[10px] text-fg-faint font-mono shrink-0",children:[n.setCount,"/",n.total]})]},n.id))})}function nt({id:t,title:s,summary:n,advanced:o,children:r}){const[a,c]=l.useState(!0);return e.jsxs("section",{id:`settings-group-${t}`,className:"mx-4 mb-4 rounded-lg border border-line shadow-sm bg-bg-elev/50 overflow-hidden",children:[e.jsxs("header",{className:"px-4 py-3 bg-bg-elev cursor-pointer hover:bg-bg-hi flex items-center gap-3 border-b border-line",onClick:()=>c(!a),children:[e.jsx("span",{className:"text-fg-faint w-3",children:a?"▾":"▸"}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-fg text-base font-semibold",children:s}),o&&e.jsx("span",{className:"text-[9px] px-1.5 py-0 rounded border border-yellow-900/40 bg-yellow-950/30 text-yellow-500/80 uppercase tracking-wide",children:"advanced"})]}),e.jsx("p",{className:"text-fg-dim text-sm mt-0.5",children:n})]})]}),a&&e.jsx("div",{className:"divide-y divide-line/60",children:r})]})}function at({keyName:t,node:s,info:n,targetScope:o,onOverride:r}){const[a,c]=l.useState(!1),[p,b]=l.useState(!1),j=fe(t),i=s!==void 0,g=(s==null?void 0:s.kind)==="leaf"?s:null,y=(s==null?void 0:s.kind)==="object"||(s==null?void 0:s.kind)==="array",f=n==null?void 0:n.default,w=g&&f!==void 0&&ye(g.value,f),R=mt({isSet:i,leafNode:g,defaultVal:f,isDefault:!!w,node:s}),S=rt(g,f),m=S.length>=2,N=!!g&&!w,I=ge(t,n==null?void 0:n.description);return e.jsx("div",{className:"px-4 py-3 hover:bg-bg-elev/20",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("button",{onClick:()=>c(!a),className:"text-fg-faint hover:text-fg w-3 mt-0.5",title:a?"collapse":"expand",children:a?"▾":"▸"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-baseline gap-2 flex-wrap",children:[e.jsx("h3",{className:"text-fg text-sm",children:j}),e.jsx(ut,{kind:R.kind,label:R.label}),m&&e.jsxs("button",{onClick:h=>{h.stopPropagation(),a||c(!0),b(k=>!k)},className:"text-[9px] px-1.5 py-0 rounded border border-blue-900/40 bg-blue-950/30 text-blue-300/90 uppercase tracking-wide hover:bg-blue-900/40",title:"this key is defined in multiple scopes — click to expand",children:["drift · ",S.map(h=>et[h]).join(" · ")]}),N&&g&&e.jsx("button",{onClick:h=>{h.stopPropagation(),r(void 0,g.winner)},className:"text-[9px] px-1.5 py-0 rounded border border-line bg-bg-elev text-fg-faint uppercase tracking-wide hover:text-fg hover:bg-bg-hi",title:`reset · delete from ${P[g.winner].label}`,children:"↺ reset"}),(n==null?void 0:n.deprecated)&&e.jsx("span",{className:"text-[9px] px-1 py-0 rounded border border-yellow-900/40 bg-yellow-950/30 text-yellow-500/80 uppercase tracking-wide",children:"deprecated"}),(n==null?void 0:n.required)&&!i&&e.jsx("span",{className:"text-[9px] px-1 py-0 rounded border border-red-900/40 bg-red-950/30 text-red-400/80 uppercase tracking-wide",children:"required"})]}),I&&e.jsx("p",{className:`text-fg-dim text-xs mt-0.5 leading-relaxed ${I.authored?"inline-block border-b border-dotted border-fg-faint/70 cursor-help":""}`,title:I.authored?"In-app-authored description — not from the official Claude Code schema":void 0,children:pt(I.text)}),a&&p&&g&&e.jsx(it,{leaf:g,defaultVal:f,onReset:h=>r(void 0,h)}),a&&e.jsx(ot,{keyName:t,node:s,info:n,targetScope:o,onOverride:h=>r(h)})]}),e.jsx("div",{className:"shrink-0",children:!a&&e.jsx(xt,{node:s,info:n,onSet:h=>{r(h)},disabled:y&&i})})]})})}function rt(t,s){if(!t)return[];const n=new Set;n.add(t.winner);for(const o of t.shadowed)n.add(o.scope);return s!==void 0&&n.add("default"),Qe.filter(o=>n.has(o))}function it({leaf:t,defaultVal:s,onReset:n}){const o={};o[t.winner]={value:t.value,winner:!0};for(const r of t.shadowed)o[r.scope]={value:r.value,winner:!1};return e.jsxs("div",{className:"mt-2 border border-line rounded bg-bg-elev/40 text-xs",children:[e.jsx("div",{className:"px-2 py-1 text-fg-faint border-b border-line/60",children:"Values across all scopes (winner highlighted · reset removes that scope's value):"}),e.jsxs("div",{className:"divide-y divide-line/60",children:[["user","project","local"].map(r=>{const a=o[r],c=a!==void 0;return e.jsxs("div",{className:"grid grid-cols-[5rem_1fr_auto] gap-2 px-2 py-1 items-center",children:[e.jsx("span",{className:"text-fg-faint",children:P[r].label}),e.jsx("span",{className:`font-mono truncate ${a!=null&&a.winner?"text-accent":"text-fg-dim"}`,children:c?B(a.value):e.jsx("span",{className:"text-fg-faint",children:"—"})}),c?e.jsx("button",{onClick:()=>n(r),className:"text-[9px] px-1.5 py-0 rounded border border-line text-fg-faint uppercase tracking-wide hover:text-fg hover:bg-bg-hi",title:`delete this key from ${P[r].label}`,children:"↺"}):e.jsx("span",{})]},r)}),e.jsxs("div",{className:"grid grid-cols-[5rem_1fr_auto] gap-2 px-2 py-1 items-center",children:[e.jsx("span",{className:"text-fg-faint",children:"Default"}),e.jsx("span",{className:"font-mono text-fg-dim truncate",children:s!==void 0?B(s):e.jsx("span",{className:"text-fg-faint",children:"—"})}),e.jsx("span",{})]})]})]})}function ot({keyName:t,node:s,info:n,targetScope:o,onOverride:r}){const c=(s==null?void 0:s.kind)==="leaf"?s:null,p=ge(t,n==null?void 0:n.description);return e.jsxs("div",{className:"mt-3 space-y-2 text-xs",children:[p&&e.jsx("p",{className:`text-fg-dim leading-relaxed whitespace-pre-wrap ${p.authored?"inline-block border-b border-dotted border-fg-faint/70 cursor-help":""}`,title:p.authored?"In-app-authored description — not from the official Claude Code schema":void 0,children:p.text}),e.jsxs("dl",{className:"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-fg-faint",children:[(n==null?void 0:n.type)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Type"}),e.jsx("dd",{className:"text-fg-dim font-mono",children:Array.isArray(n.type)?n.type.join(" | "):n.type})]}),(n==null?void 0:n.default)!==void 0&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Default"}),e.jsx("dd",{className:"text-fg-dim font-mono",children:B(n.default)})]}),(n==null?void 0:n.enum)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Options"}),e.jsx("dd",{className:"text-fg-dim font-mono",children:n.enum.map(b=>String(b)).join(" | ")})]}),c&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Current"}),e.jsxs("dd",{className:"font-mono",children:[e.jsx("span",{className:"text-fg-dim",children:B(c.value)}),e.jsxs("span",{className:"ml-2 text-fg-faint",children:["from ",P[c.winner].label]})]})]}),c&&c.shadowed.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Shadowed"}),e.jsx("dd",{className:"space-y-0.5",children:c.shadowed.map((b,j)=>e.jsxs("div",{className:"font-mono text-fg-faint line-through",children:[B(b.value)," —"," ",e.jsx("span",{className:"no-underline",children:P[b.scope].label})]},j))})]}),(s==null?void 0:s.kind)==="array"&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Accumulated"}),e.jsxs("dd",{className:"text-fg-dim",children:[s.items.length," items across all scopes"]})]})]}),e.jsx("div",{className:"pt-2 flex items-center gap-2 flex-wrap border-t border-line/60",children:e.jsx(lt,{keyName:t,node:s,info:n,onChange:r,targetScope:o})})]})}function lt({node:t,info:s,onChange:n,targetScope:o}){const a=(t==null?void 0:t.kind)==="leaf"?t.value:s==null?void 0:s.default,c=be(s==null?void 0:s.type);if(c==="boolean"){const p=a===!0;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-fg-faint",children:"Set to:"}),e.jsx("div",{className:"inline-flex rounded border border-line overflow-hidden",children:[{v:!0,label:"on"},{v:!1,label:"off"}].map(({v:b,label:j})=>e.jsx("button",{onClick:()=>n(b),className:`px-3 py-0.5 text-xs transition-colors ${p===b?"bg-accent text-bg":"bg-bg-elev text-fg-dim hover:bg-bg-hi hover:text-fg"}`,children:j},j))}),e.jsxs("span",{className:"text-fg-faint",children:["→ ",P[o].label]})]})}return s!=null&&s.enum?e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("span",{className:"text-fg-faint",children:"Choose:"}),s.enum.map(p=>{const b=ye(a,p);return e.jsx("button",{onClick:()=>n(p),className:`px-2 py-0.5 text-xs rounded border ${b?"bg-accent text-bg border-accent":"bg-bg-elev text-fg-dim border-line hover:text-fg hover:bg-bg-hi"}`,children:String(p)},String(p))}),e.jsxs("span",{className:"text-fg-faint",children:["→ ",P[o].label]})]}):c==="integer"||c==="number"?e.jsx(ct,{value:typeof a=="number"?a:void 0,integer:c==="integer",onCommit:n,target:P[o].label}):c==="string"?e.jsx(dt,{value:typeof a=="string"?a:"",onCommit:n,target:P[o].label}):e.jsxs("div",{className:"text-fg-faint",children:["Complex value (",c??"object/array",") — use the"," ",e.jsx("span",{className:"text-fg-dim",children:"Raw"})," tab to edit."]})}function ct({value:t,integer:s,onCommit:n,target:o}){const[r,a]=l.useState(t!==void 0?String(t):""),c=()=>{const p=s?parseInt(r,10):parseFloat(r);Number.isNaN(p)||n(p)};return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-fg-faint",children:"Set to:"}),e.jsx("input",{type:"number",value:r,onChange:p=>a(p.target.value),onBlur:c,onKeyDown:p=>{p.key==="Enter"&&p.target.blur()},className:"w-24 bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg"}),e.jsxs("button",{onClick:c,className:"px-2 py-0.5 text-xs border border-accent/50 rounded text-accent hover:bg-accent hover:text-bg",children:["save → ",o]})]})}function dt({value:t,onCommit:s,target:n}){const[o,r]=l.useState(t);return e.jsxs("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:[e.jsx("span",{className:"text-fg-faint shrink-0",children:"Set to:"}),e.jsx("input",{type:"text",value:o,onChange:a=>r(a.target.value),onKeyDown:a=>{a.key==="Enter"&&s(o)},className:"flex-1 min-w-0 bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg"}),e.jsxs("button",{onClick:()=>s(o),className:"shrink-0 px-2 py-0.5 text-xs border border-accent/50 rounded text-accent hover:bg-accent hover:text-bg",children:["save → ",n]})]})}function xt({node:t,info:s,onSet:n,disabled:o}){const r=(t==null?void 0:t.kind)==="leaf",a=be(s==null?void 0:s.type);if(o)return null;if(a==="boolean"){const c=r&&t.value===!0;return e.jsx("button",{onClick:()=>n(!c),className:`px-2.5 py-0.5 text-xs rounded border transition-colors ${c?"bg-accent/15 text-accent border-accent/40 hover:bg-accent hover:text-bg":"bg-bg-elev text-fg-dim border-line hover:text-fg hover:bg-bg-hi"}`,title:"toggle",children:c?"on":"off"})}return null}function mt({isSet:t,leafNode:s,defaultVal:n,isDefault:o,node:r}){return t?(r==null?void 0:r.kind)==="array"?{kind:"accumulated",label:`${r.items.length} items`}:(r==null?void 0:r.kind)==="object"?{kind:"set",label:"configured"}:s?o?{kind:"default",label:`= default · ${P[s.winner].label}`}:s.shadowed.length>0?{kind:"override",label:`overriding ${s.shadowed.length} scope(s)`}:{kind:"set",label:`set in ${P[s.winner].label}`}:{kind:"set",label:"configured"}:n!==void 0?{kind:"default",label:`using default: ${B(n)}`}:{kind:"unset",label:"not configured"}}function ut({kind:t,label:s}){const n={set:"bg-accent/15 text-accent border-accent/30",default:"bg-bg-hi text-fg-dim border-line",unset:"bg-bg-elev text-fg-faint border-line",override:"bg-purple-950/30 text-purple-400/80 border-purple-900/40",accumulated:"bg-blue-950/30 text-blue-400/80 border-blue-900/40"}[t];return e.jsx("span",{className:`text-[9px] px-1.5 py-0 rounded border uppercase tracking-wide ${n}`,children:s})}function be(t){if(t)return Array.isArray(t)?t.find(n=>n!=="null")??t[0]:t}function ye(t,s){return t===s?!0:typeof t!=typeof s?!1:t&&s&&typeof t=="object"?JSON.stringify(t)===JSON.stringify(s):!1}function pt(t){const s=t.trim().split(`
|
|
2
|
-
`)[0],n=s.match(/^([^.!?]+[.!?])/);return n?n[1]:s.length>120?s.slice(0,120)+"…":s}function B(t){if(typeof t=="string")return t===""?'""':JSON.stringify(t);if(t===null)return"null";if(t===void 0)return"—";if(typeof t=="object"){const s=JSON.stringify(t);return s.length>60?s.slice(0,60)+"…":s}return String(t)}const ft=1440*60*1e3;function le(t){if(!t)return"never";const s=new Date(t).getTime();return Number.isNaN(s)?"never":new Date(s).toLocaleString()}function ce(t){return t?new Date(t).toLocaleString():"never"}function ht(){return e.jsxs("div",{className:"p-4 max-w-3xl space-y-8 text-sm",children:[e.jsx(gt,{}),e.jsx("hr",{className:"border-line"}),e.jsx(bt,{})]})}function gt(){const[t,s]=l.useState(null),[n,o]=l.useState(null),[r,a]=l.useState(null),[c,p]=l.useState(null),[b,j]=l.useState(!1),[i,u]=l.useState(null),[g,y]=l.useState(null);if(l.useEffect(()=>{let m=!1;return Promise.all([window.api.otel.getConfig(),window.api.otel.status(),window.api.otel.configPath()]).then(([N,I,h])=>{m||(s(N),a(N),o(I),p(h))}).catch(N=>{console.warn("[telemetry] load failed:",N==null?void 0:N.message)}),()=>{m=!0}},[]),!r||!t)return e.jsx(K,{title:"loading…"});const f=JSON.stringify(r)!==JSON.stringify(t),w=(m,N)=>{u(null),a({...r,[m]:N})},R=async()=>{j(!0),u(null);try{const m=await window.api.otel.setConfig(r);!m.ok&&m.error&&u(m.error),s(m.config),a(m.config),o(m.status),y(Date.now())}catch(m){u(m instanceof Error?m.message:String(m))}finally{j(!1)}},S=()=>{u(null),a(t)};return e.jsxs("div",{className:"space-y-5",children:[e.jsxs("header",{className:"space-y-1",children:[e.jsx("h2",{className:"text-fg text-base font-medium",children:"OpenTelemetry export"}),e.jsx("p",{className:"text-fg-dim text-xs leading-relaxed",children:"When enabled, every classified transcript event (tool_use, todo_write, plan, usage, agent_spawn) is mirrored as a 0-duration OTLP/HTTP span. Point this at a local collector (Jaeger, Grafana Tempo, SigNoz, Honeycomb) for cross-session analysis."}),c&&e.jsxs("p",{className:"text-fg-faint text-[11px]",children:["stored at ",e.jsx("span",{className:"font-mono",children:c})]})]}),e.jsxs("section",{className:"border border-line rounded p-3 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-fg",children:"Export transcripts to OTEL"}),e.jsx("div",{className:"text-fg-faint text-xs",children:"Toggle off to disable all span emission immediately."})]}),e.jsx(Y,{checked:r.enabled,onChange:m=>w("enabled",m),label:r.enabled?"on":"off"})]}),e.jsxs("label",{className:"block space-y-1",children:[e.jsx("span",{className:"text-fg-dim text-xs",children:"OTLP/HTTP traces endpoint"}),e.jsx("input",{type:"text",value:r.endpoint,onChange:m=>w("endpoint",m.target.value),placeholder:"http://localhost:4318/v1/traces",className:"w-full bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs"})]}),e.jsxs("label",{className:"block space-y-1",children:[e.jsxs("span",{className:"text-fg-dim text-xs",children:["Headers (newline-separated ",e.jsx("span",{className:"font-mono",children:"Key: Value"}),")"]}),e.jsx("textarea",{value:r.headers,onChange:m=>w("headers",m.target.value),placeholder:"x-honeycomb-team: YOUR_API_KEY",rows:3,className:"w-full bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs"})]}),e.jsxs("label",{className:"block space-y-1",children:[e.jsx("span",{className:"text-fg-dim text-xs",children:"Service name"}),e.jsx("input",{type:"text",value:r.serviceName,onChange:m=>w("serviceName",m.target.value),placeholder:"session-manager",className:"w-full bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs"})]}),e.jsxs("div",{className:"flex items-start justify-between gap-3 pt-1",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-fg",children:"Include content (PII)"}),e.jsxs("div",{className:"text-fg-faint text-xs leading-relaxed",children:["Adds tool inputs, plan text, and agent prompts to span attributes. Off by default — matches upstream Claude Code's ",e.jsx("span",{className:"font-mono",children:"OTEL_LOG_USER_PROMPTS"})," opt-in."]})]}),e.jsx(Y,{checked:r.includeContent,onChange:m=>w("includeContent",m),label:r.includeContent?"on":"off"})]})]}),n&&e.jsxs("section",{className:"border border-line rounded p-3 text-xs space-y-1",children:[e.jsx("div",{className:"text-fg-dim",children:"Runtime status"}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"enabled:"})," ",e.jsx("span",{className:n.enabled?"text-accent":"text-fg-dim",children:String(n.enabled)})]}),n.error&&e.jsxs("div",{className:"text-red-400 break-words",children:[e.jsx("span",{className:"text-fg-faint",children:"error:"})," ",n.error]}),!n.error&&n.enabled&&e.jsx("div",{className:"text-fg-faint",children:"spans batched and exported in the background. Verify by enabling and pointing at a local Jaeger."})]}),e.jsxs("footer",{className:"flex items-center gap-3 pt-2 border-t border-line",children:[e.jsx("button",{onClick:R,disabled:!f||b,className:"px-3 py-1 text-xs rounded bg-accent text-bg disabled:opacity-50 disabled:cursor-not-allowed",children:b?"saving…":"Save"}),e.jsx("button",{onClick:S,disabled:!f||b,className:"px-3 py-1 text-xs rounded border border-line text-fg-dim hover:text-fg disabled:opacity-50 disabled:cursor-not-allowed",children:"Revert"}),i&&e.jsx("span",{className:"text-red-400 text-xs",children:i}),!i&&g&&!f&&e.jsx("span",{className:"text-fg-faint text-xs",children:"saved"})]})]})}function bt(){const[t,s]=l.useState(null),[n,o]=l.useState(null),[r,a]=l.useState("Copy"),[c,p]=l.useState(!1),[b,j]=l.useState(null),[i,u]=l.useState(null),[g,y]=l.useState(null),[f,w]=l.useState(!1),R=()=>{window.api.telemetry.status().then(o).catch(v=>{console.warn("[product-telemetry] status reload failed:",v==null?void 0:v.message)})};if(l.useEffect(()=>{let v=!1;return Promise.all([window.api.telemetry.getConfig(),window.api.telemetry.status()]).then(([d,C])=>{v||(s(d),o(C))}).catch(d=>{console.warn("[product-telemetry] load failed:",d==null?void 0:d.message)}),()=>{v=!0}},[]),!t||!n)return e.jsx(K,{title:"loading…"});const S=async v=>{u(null);try{const d=await window.api.telemetry.setConfig(v);s(d.config),o(d.status)}catch(d){u(d instanceof Error?d.message:String(d))}},m=v=>{S({...t,enabled:v})},N=v=>{S({...t,enabled:v.turnOff?!1:t.enabled,noticeAckedAt:new Date().toISOString()})},I=async()=>{await Re(t.installId)?(a("Copied"),setTimeout(()=>a("Copy"),1500)):ue.error("Could not copy install id to the clipboard")},h=async()=>{p(!0),j(null);try{const v=await window.api.telemetry.flushNow();j(`sent ${v.sent.length}, failed ${v.failed.length}`),R()}catch(v){j(v instanceof Error?v.message:String(v))}finally{p(!1)}},k=async()=>{if(f){w(!1);return}try{const v=await window.api.telemetry.recentRecords();y(v),w(!0)}catch(v){console.warn("[product-telemetry] recentRecords failed:",v instanceof Error?v.message:v)}},E=t.lastDailyFlushAt?new Date(t.lastDailyFlushAt).getTime()+ft:null;return e.jsxs("div",{className:"space-y-5","data-testid":"product-telemetry-section",children:[e.jsxs("header",{className:"space-y-1",children:[e.jsx("h2",{className:"text-fg text-base font-medium",children:"Product telemetry (bilko.run)"}),e.jsxs("p",{className:"text-fg-dim text-xs leading-relaxed",children:["Anonymous, strictly non-identifying usage/error reporting that helps improve this app. On by default; switchable off in one click. See"," ",e.jsx("span",{className:"font-mono",children:"session-manager-operations/architecture/telemetry.md"})," for the full data model."]})]}),!t.noticeAckedAt&&e.jsxs("section",{"data-testid":"telemetry-first-run-notice",className:"border border-accent rounded p-3 space-y-2 text-xs",children:[e.jsx("div",{className:"text-fg font-medium",children:"This app sends anonymous product telemetry"}),e.jsx("p",{className:"text-fg-dim leading-relaxed",children:"Collected: a coarse machine profile (OS/arch/app version, no hardware id), error and warning counts, and session counts — sent on start-up, after an update, and once a day."}),e.jsx("p",{className:"text-fg-dim leading-relaxed",children:"Never collected: prompts, transcripts, file paths, project names, email, or username."}),e.jsxs("div",{className:"flex items-center gap-2 pt-1",children:[e.jsx("button",{onClick:()=>N({turnOff:!1}),className:"px-3 py-1 rounded bg-accent text-bg",children:"OK"}),e.jsx("button",{onClick:()=>N({turnOff:!0}),className:"px-3 py-1 rounded border border-line text-fg-dim hover:text-fg",children:"Turn off"})]})]}),e.jsxs("section",{className:"border border-line rounded p-3 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-fg",children:"Send anonymous product telemetry"}),e.jsx("div",{className:"text-fg-faint text-xs",children:"Sent on start-up, after an update, and once a day. Strictly anonymous — an install id only, never an email, name, or other identifier."})]}),e.jsx(Y,{checked:t.enabled,onChange:m,label:t.enabled?"on":"off"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-fg-dim text-xs",children:"Anonymous install id"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",readOnly:!0,value:t.installId,"aria-label":"Anonymous install identifier",className:"flex-1 bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs"}),e.jsx("button",{onClick:I,className:"px-2 py-1 text-xs rounded border border-line text-fg-dim hover:text-fg",children:r})]})]}),e.jsxs("div",{className:"space-y-1 text-xs",children:[e.jsx("div",{className:"text-fg-faint",children:"Endpoint"}),e.jsx("div",{className:"font-mono text-fg-dim break-all",children:t.endpoint})]}),e.jsxs("div",{className:"space-y-1 text-xs",children:[e.jsx("div",{className:"text-fg-faint",children:"Send cadence"}),e.jsx("div",{className:"text-fg-dim",children:"on start-up, after an update, and once a day"})]}),i&&e.jsx("div",{className:"text-red-400 text-xs",children:i})]}),n.pendingCount>0&&n.sentCount===0&&e.jsxs("section",{"data-testid":"telemetry-never-delivered-warning",className:"border border-red-400 rounded p-3 text-xs space-y-1 text-red-400",children:[e.jsx("div",{className:"font-medium",children:"Never delivered"}),e.jsxs("div",{className:"leading-relaxed",children:[n.pendingCount," record",n.pendingCount===1?"":"s",' queued but none have ever been sent to bilko.run on this install. Check the endpoint/network, or click "Send now" below.']})]}),e.jsxs("section",{className:"border border-line rounded p-3 text-xs space-y-1.5",children:[e.jsx("div",{className:"text-fg-dim",children:"Runtime status"}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"last send:"})," ",ce(n.lastFlushAt)]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"next daily send due:"})," ",le(E?new Date(E).toISOString():null)]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"queued records:"})," ",n.pendingCount]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"delivered so far:"})," ",n.sentCount]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"de-duplicated:"})," ",n.dedupedAppends]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"evicted:"})," ",n.evictedCount]}),n.backlog&&e.jsxs("div",{className:"text-fg-faint",children:["last backlog drain (",n.backlog.reason,", ",le(n.backlog.ranAt),"):"," ",n.backlog.linesEnqueued," enqueued, ",n.backlog.linesConfirmed," confirmed,"," ",n.backlog.watermarksRewound," watermarks rewound"]}),n.lastError&&e.jsxs("div",{className:"text-red-400 break-words",children:[e.jsx("span",{className:"text-fg-faint",children:"last error:"})," ",n.lastError.message," ","(",ce(n.lastError.at),")"]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{onClick:h,disabled:c,className:"px-3 py-1 text-xs rounded bg-accent text-bg disabled:opacity-50 disabled:cursor-not-allowed",children:c?"sending…":"Send now"}),b&&e.jsx("span",{className:"text-fg-faint text-xs",children:b})]}),e.jsxs("section",{className:"space-y-2",children:[e.jsx("button",{onClick:k,className:"px-3 py-1 text-xs rounded border border-line text-fg-dim hover:text-fg",children:f?"Hide last records":"Inspect last records sent"}),f&&e.jsx("pre",{"data-testid":"telemetry-inspector-json",className:"bg-bg border border-line rounded p-2 text-[11px] font-mono overflow-auto max-h-96 whitespace-pre-wrap",children:JSON.stringify(g??[],null,2)})]})]})}function _({children:t,right:s}){return e.jsxs("div",{className:"flex items-baseline justify-between mb-2.5",children:[e.jsx("span",{className:"text-[11.5px] font-bold uppercase tracking-[0.8px] text-fg-faint",children:t}),s]})}function D({kind:t="soft",icon:s,children:n,onClick:o,disabled:r,testId:a}){return e.jsxs("button",{type:"button","data-testid":a,onClick:o,disabled:r,className:`shrink-0 inline-flex items-center gap-2 rounded-lg px-3.5 py-2 text-[13px] font-semibold transition-colors disabled:opacity-50 ${t==="soft"?"bg-bg-hi border border-line text-fg hover:bg-bg":"text-fg-dim hover:text-fg"}`,children:[s&&e.jsx(H,{name:s,size:15}),n]})}function Q({icon:t,title:s,subtitle:n,badge:o,action:r,testId:a}){return e.jsxs("div",{"data-testid":a,className:"flex items-center gap-3.5 bg-bg-hi border border-line rounded-xl px-[18px] py-3.5",children:[e.jsx("span",{className:"w-[34px] h-[34px] rounded-lg bg-bg border border-line grid place-items-center text-fg-dim shrink-0",children:e.jsx(H,{name:t,size:17})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2.5 mb-0.5",children:[e.jsx("span",{className:"text-sm font-semibold text-fg truncate",children:s}),o]}),e.jsx("div",{className:"font-mono text-[11.5px] text-fg-faint truncate",children:n})]}),r]})}function je({onClick:t,disabled:s,testId:n,children:o="Revoke"}){return e.jsx("button",{"data-testid":n,onClick:t,disabled:s,className:"shrink-0 rounded-lg border border-line bg-bg text-accent px-3.5 py-1.5 text-[12.5px] font-semibold hover:bg-bg-hi disabled:opacity-50 transition-colors",children:o})}function ve({code:t,onConfirm:s,testId:n,codeTestId:o,confirmTestId:r,peer:a="browser"}){return e.jsxs("div",{"data-testid":n,className:"flex items-start gap-3.5 px-5 py-4 rounded-2xl border border-accent/40 bg-accent/[0.06]",children:[e.jsx("span",{className:"w-[38px] h-[38px] rounded-[11px] shrink-0 grid place-items-center bg-bg-hi text-accent",children:e.jsx(H,{name:"shield",size:20})}),e.jsxs("div",{className:"flex-1 min-w-0 text-sm text-fg",children:[e.jsx("strong",{className:"font-semibold",children:"Verify E2E session."})," Compare this code with the ",a," — they must match.",e.jsx("div",{"data-testid":o,className:"my-2 text-3xl font-mono tracking-[0.3em] text-center text-accent select-all",children:t}),e.jsx("p",{className:"text-[12.5px] text-fg-faint mb-3",children:"If the codes match, confirm below. Mutating commands are blocked until confirmed."}),e.jsx("button",{"data-testid":r,onClick:s,className:"rounded-lg bg-accent text-white px-4 py-2 text-[13px] font-semibold hover:opacity-90 transition-opacity",children:"Codes match — confirm"})]})]})}function W({children:t,testId:s}){return e.jsx("div",{"data-testid":s,className:"bg-bg-hi border border-line rounded-xl p-5 text-center text-[13.5px] text-fg-faint italic font-serif",children:t})}const yt=260;function jt({peerId:t,machineName:s,cwd:n,onClose:o}){const r=l.useRef(null),a=l.useRef(null),c=Z(i=>i.show),[p,b]=l.useState(!1);l.useEffect(()=>{const i=r.current;if(!i)return;const u=crypto.randomUUID();let g=!0,y=!1,f=!1;const w=(d,C)=>{g&&c("error",`Remote terminal ${d} failed: ${C instanceof Error?C.message:String(C)}`)},R=(d,C)=>window.api.remoteClient.send(t,d,C),S=new Ie.Terminal({fontFamily:'"IBM Plex Mono", JetBrains Mono, ui-monospace, Menlo, monospace',fontSize:ne.fontSize,lineHeight:1.2,cursorBlink:!0,allowProposedApi:!0,theme:Ae[ne.theme]}),m=new Te.FitAddon;S.loadAddon(m);const N=()=>{if(Pe(i.clientWidth,i.clientHeight))try{m.fit()}catch{}};S.open(i),N(),S.focus();const I=window.api.remoteClient.onEvent(d=>{if(d.peerId!==t)return;const C=d.payload??{};C.tabId===u&&(d.type==="event:pty:data"?typeof C.data=="string"&&S.write(C.data):d.type==="event:pty:exit"&&(y=!0,S.options.disableStdin=!0,S.write(`\r
|
|
3
|
-
\x1B[38;5;240m[remote session exited code=${C.exitCode??"?"}]\x1B[0m\r
|
|
4
|
-
`),b(!0)))}),h=S.onData(d=>{y||R("cmd:pty:write",{tabId:u,data:d}).catch(C=>w("write",C))}),k=S.onResize(({cols:d,rows:C})=>{y||R("cmd:pty:resize",{tabId:u,cols:d,rows:C}).catch(T=>w("resize",T))});R("cmd:pty:spawn",{tabId:u,cwd:n,cols:S.cols,rows:S.rows}).catch(d=>w("spawn",d)),a.current=()=>{f||(f=!0,R("cmd:pty:kill",{tabId:u}).catch(d=>w("kill",d)))};const E=()=>N();window.addEventListener("resize",E);const v=new ResizeObserver(()=>N());return v.observe(i),()=>{var d;window.removeEventListener("resize",E),v.disconnect(),I(),h.dispose(),k.dispose(),(d=a.current)==null||d.call(a),a.current=null,g=!1,S.dispose()}},[t,n,c]);const j=()=>{var i;(i=a.current)==null||i.call(a),o()};return e.jsxs("div",{"data-testid":"remote-terminal-panel",className:"bg-bg-hi border border-line rounded-xl overflow-hidden",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3 px-[18px] pt-3.5 pb-2",children:[e.jsxs("div",{className:"flex items-center gap-2.5 min-w-0",children:[e.jsx(_,{children:"Remote terminal"}),e.jsx(L,{tone:"accent",children:e.jsxs("span",{"data-testid":"remote-terminal-badge",children:["Remote: ",s]})}),p&&e.jsx(L,{tone:"dim",children:"exited"})]}),e.jsx(D,{kind:"ghost",onClick:j,testId:"remote-terminal-close",children:"Close"})]}),e.jsx("div",{ref:r,"data-testid":"remote-terminal-host",className:"w-full bg-bg",style:{height:yt}})]})}function de(t){return t instanceof Error?t.message:String(t)}function vt({peerId:t,machineName:s}){const n=Z(m=>m.show),[o,r]=l.useState([]),[a,c]=l.useState("loading"),[p,b]=l.useState(null),[j,i]=l.useState(""),[u,g]=l.useState(!1),y=l.useRef(0),f=l.useCallback(async()=>{const m=++y.current;c("loading");try{const N=await window.api.remoteClient.send(t,"cmd:sessions:load",{});if(m!==y.current)return;r(Array.isArray(N==null?void 0:N.tabs)?N.tabs:[]),c("ready")}catch(N){if(m!==y.current)return;c("error"),n("error",`Could not load sessions from ${s}: ${de(N)}`)}},[t,s,n]);l.useEffect(()=>(f(),()=>{y.current++}),[f]);const w=j.trim(),R=p!==null&&w.length>0&&!u,S=l.useCallback(async()=>{if(!(p===null||j.trim().length===0)){g(!0);try{await window.api.remoteClient.send(t,"cmd:chat:send",{tabId:p,prompt:j}),i("")}catch(m){n("error",`Could not send prompt to ${s}: ${de(m)}`)}finally{g(!1)}}},[t,s,p,j,n]);return e.jsxs("div",{"data-testid":"remote-sessions-panel",className:"flex flex-col gap-3",children:[e.jsx(_,{right:e.jsx(L,{tone:"accent",className:"",title:`Sessions on ${s}`,children:e.jsxs("span",{"data-testid":"remote-sessions-badge",children:["Remote: ",s]})}),children:"Remote sessions"}),e.jsx("div",{className:"flex justify-end",children:e.jsx(D,{icon:"history",testId:"remote-sessions-refresh",onClick:()=>{f()},disabled:a==="loading",children:"Refresh"})}),a==="loading"&&e.jsx(W,{testId:"remote-sessions-loading",children:"Loading sessions…"}),a==="error"&&e.jsxs(W,{testId:"remote-sessions-error",children:["Could not load sessions from ",s,"."]}),a==="ready"&&o.length===0&&e.jsxs(W,{testId:"remote-sessions-empty",children:["No sessions open on ",s,"."]}),a==="ready"&&o.map(m=>e.jsx(Q,{testId:`remote-session-${m.sessionId}`,icon:"terminal",title:m.label||m.cwd,subtitle:m.cwd,action:e.jsx(D,{kind:p===m.sessionId?"soft":"ghost",testId:`remote-session-select-${m.sessionId}`,onClick:()=>b(m.sessionId),children:p===m.sessionId?"Selected":"Select"})},m.sessionId)),a==="ready"&&o.length>0&&e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("textarea",{"data-testid":"remote-sessions-prompt",value:j,onChange:m=>i(m.target.value),rows:3,placeholder:p?`Prompt for the selected session on ${s}`:"Select a session first",className:"w-full rounded-lg bg-bg-hi border border-line px-3 py-2 text-[13px] text-fg placeholder:text-fg-faint"}),e.jsx("div",{className:"flex justify-end",children:e.jsx(D,{icon:"play",testId:"remote-sessions-send",onClick:()=>{S()},disabled:!R,children:"Send"})})]})]})}const wt="relay_client_auth_unavailable",X=t=>(t==null?void 0:t.message)||String(t);function Nt({peer:t,panel:s,onConnect:n,onRevoke:o,onTogglePanel:r,onConfirmSas:a}){const c=t.status==="authenticated",p=t.status==="failed"&&t.reason===wt,b=t.status==="connecting",j=new Date(t.pairedAt).toLocaleString(),i=(s==null?void 0:s.peerId)===t.peerId?s.kind:null;return e.jsxs("div",{className:"space-y-2","data-testid":"remote-machine-row",children:[e.jsx(Q,{testId:"remote-machine",icon:"terminal",title:t.machineName,badge:c?e.jsx(L,{tone:"default",className:"!text-sage !border-sage/40",children:"online"}):void 0,subtitle:`${t.peerId} · last seen ${j}`,action:e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[c?e.jsxs(e.Fragment,{children:[e.jsx(D,{testId:"remote-machine-terminal",icon:"terminal",onClick:()=>r(t.peerId,"terminal"),children:"Open terminal"}),e.jsx(D,{testId:"remote-machine-sessions",onClick:()=>r(t.peerId,"sessions"),children:"Sessions"})]}):!p&&t.status!=="pending_sas"?e.jsx(D,{testId:"remote-machine-connect",disabled:b,onClick:()=>n(t.peerId),children:b?"Connecting…":"Connect"}):null,e.jsx(je,{testId:"remote-machine-revoke",onClick:()=>o(t.peerId),children:"Revoke"})]})}),p&&e.jsx("p",{"data-testid":"remote-machine-unavailable",className:"text-[12.5px] leading-snug text-fg-faint",children:"The bilko.run relay does not support desktop clients yet"}),t.status==="pending_sas"&&t.sas&&e.jsx(ve,{peer:"other machine",testId:"remote-machine-sas",codeTestId:"remote-machine-sas-code",confirmTestId:"remote-machine-sas-confirm",code:t.sas,onConfirm:()=>a(t.peerId)}),i==="terminal"&&e.jsx(jt,{peerId:t.peerId,machineName:t.machineName,cwd:"",onClose:()=>r(t.peerId,"terminal")}),i==="sessions"&&e.jsx(vt,{peerId:t.peerId,machineName:t.machineName})]})}function kt(){const t=Z(i=>i.show),[s,n]=l.useState([]),[o,r]=l.useState(null),a=l.useCallback(async()=>{try{n(await window.api.remoteClient.list())}catch(i){t("error",X(i))}},[t]);l.useEffect(()=>{a();const i=window.api.remoteClient.onStatus(u=>{n(g=>g.map(y=>y.peerId===u.peerId?{...y,status:u.status,reason:u.reason,sas:u.sas}:y))});return()=>{i()}},[a]);const c=l.useCallback(async i=>{try{const u=await window.api.remoteClient.connect(i);n(g=>g.map(y=>y.peerId===i?{...y,status:u.status,reason:u.reason,sas:u.sas}:y))}catch(u){t("error",X(u))}},[t]),p=l.useCallback(async i=>{try{const u=await window.api.remoteClient.confirmSas(i);u.ok||t("error",u.reason??"SAS confirmation failed"),await a()}catch(u){t("error",X(u))}},[t,a]),b=l.useCallback(async i=>{try{await window.api.remoteClient.remove(i),r(u=>(u==null?void 0:u.peerId)===i?null:u),await a()}catch(u){t("error",X(u))}},[t,a]),j=l.useCallback((i,u)=>{r(g=>(g==null?void 0:g.peerId)===i&&g.kind===u?null:{peerId:i,kind:u})},[]);return e.jsxs("div",{"data-testid":"remote-machines",children:[e.jsx(_,{right:s.length>0?e.jsxs("span",{className:"text-[11.5px] text-fg-faint",children:[s.length," paired"]}):void 0,children:"Remote machines"}),s.length===0?e.jsx(W,{testId:"remote-machines-empty",children:"No machines paired yet."}):e.jsx("div",{className:"space-y-2",children:s.map(i=>e.jsx(Nt,{peer:i,panel:o,onConnect:c,onRevoke:b,onTogglePanel:j,onConfirmSas:p},i.peerId))})]})}function xe({label:t,hint:s,on:n,onChange:o,warn:r,disabled:a,first:c,testId:p}){return e.jsxs("div",{className:`flex items-center justify-between gap-4 px-[18px] py-[15px] ${c?"":"border-t border-rule"} ${a?"opacity-50":""}`,children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm font-semibold text-fg mb-0.5",children:t}),e.jsxs("div",{className:`text-[12.5px] leading-snug flex items-center gap-1.5 ${r?"text-honey-dark":"text-fg-faint"}`,children:[r&&e.jsx("span",{"aria-hidden":!0,children:"⚠"}),s]})]}),e.jsx("span",{"data-testid":p,className:"inline-flex",children:e.jsx(Y,{checked:n,onChange:a?()=>{}:o,disabled:a})})]})}function St({device:t,online:s,onRevoke:n,revoking:o}){const r=t.lastConnectedAt?new Date(t.lastConnectedAt).toLocaleString():`paired ${new Date(t.issuedAt).toLocaleDateString()}`;return e.jsx(Q,{testId:"settings-remote-device",icon:"wifi",title:t.deviceName,badge:s?e.jsx(L,{tone:"default",className:"!text-sage !border-sage/40",children:"online"}):void 0,subtitle:`${t.deviceId} · last seen ${r}`,action:e.jsx(je,{testId:"settings-remote-revoke",onClick:()=>n(t.deviceId),disabled:o})})}const M=t=>(t==null?void 0:t.message)||String(t);function Ct(){var se;const t=Z(x=>x.show),[s,n]=l.useState(null),[o,r]=l.useState(!0),[a,c]=l.useState(!1),[p,b]=l.useState(!1),[j,i]=l.useState("idle"),[u,g]=l.useState(""),[y,f]=l.useState(null),[w,R]=l.useState(!1),[S,m]=l.useState([]),[N,I]=l.useState(!1),h=l.useRef(null);l.useEffect(()=>{let x=!1;const A=()=>window.api.webRemote.getStatus().then($=>{x||n($)}).catch(()=>{});window.api.webRemote.getStatus().then($=>{x||(n($),r(!1))}).catch($=>{x||(t("error",`Remote status: ${M($)}`),r(!1))});const Se=window.api.webRemote.onStatus($=>n($)),Ce=window.api.webRemote.onTokenRevoked(()=>{t("warn","Remote device token was revoked. Re-pair to reconnect."),A()}),Ee=window.api.webRemote.onRevokedAll(({revokedCount:$})=>{t("info",`Panic: all ${$} device(s) revoked and sessions torn down.`),A()});return()=>{x=!0,Se(),Ce(),Ee()}},[t]),l.useEffect(()=>{if(j!=="enter-otp")return;const x=setTimeout(()=>{var A;return(A=h.current)==null?void 0:A.focus()},50);return()=>clearTimeout(x)},[j]);const k=async()=>n(await window.api.webRemote.getStatus()),E=async()=>{if(s){c(!0);try{const x=s.enabled?await window.api.webRemote.disable():await window.api.webRemote.enable();x&&x.ok===!1&&t("error",x.error||"Failed to change remote state."),await k()}catch(x){t("error",`Failed: ${M(x)}`)}finally{c(!1)}}},v=async()=>{if(s){b(!0);try{const x=s.remoteControlEnabled?await window.api.webRemote.disableControl():await window.api.webRemote.enableControl();x&&x.ok===!1&&t("error",x.error||"Failed to change command writes."),await k()}catch(x){t("error",`Failed: ${M(x)}`)}finally{b(!1)}}},d=async()=>{const x=u.trim().toUpperCase();if(!/^[A-Z0-9]{8}$/.test(x)){t("warn","Pairing code must be 8 alphanumeric characters.");return}i("pairing");try{const A=await window.api.webRemote.pair(x);if(!A.ok){t("error",A.error||"Pairing failed."),i("enter-otp");return}t("info","Device paired successfully."),g(""),i("idle"),await k()}catch(A){t("error",`Pairing error: ${M(A)}`),i("enter-otp")}},C=async x=>{f(x);try{const A=await window.api.webRemote.revokeDevice(x);if(!A.ok){t("error",A.error||"Revoke failed.");return}await k()}catch(A){t("error",`Revoke error: ${M(A)}`)}finally{f(null)}},T=async()=>{R(!0);try{const x=await window.api.webRemote.revokeAll();x.ok||t("error",x.error||"Panic revoke failed.")}catch(x){t("error",`Panic revoke error: ${M(x)}`)}finally{R(!1)}},ee=async()=>{if(N){I(!1);return}try{const x=await window.api.webRemote.auditTail(100);if(!x.ok){t("error",`Audit log: ${x.error||"unavailable"}`);return}m(x.lines??[]),I(!0)}catch(x){t("error",`Audit log: ${M(x)}`)}},U=async()=>{try{const x=await window.api.webRemote.confirmSas();x!=null&&x.ok||t("error",`SAS confirm failed: ${(x==null?void 0:x.error)??"unexpected state — reconnect the mobile app"}`)}catch(x){t("error",`SAS confirm failed: ${M(x)}`)}};if(o)return e.jsx("div",{className:"p-6 text-fg-faint text-sm",children:"Loading…"});const O=(s==null?void 0:s.enabled)??!1,F=(s==null?void 0:s.remoteControlEnabled)??!1,V=(s==null?void 0:s.connected)??!1,z=(s==null?void 0:s.e2eActive)??!1,we=(s==null?void 0:s.e2eAuthenticated)??!1,Ne=(s==null?void 0:s.e2eState)??"idle",te=(s==null?void 0:s.pendingSas)??null,G=(s==null?void 0:s.devices)??[],J=O&&V,ke=V?((se=G.reduce((x,A)=>A.lastConnectedAt&&(!x||(x.lastConnectedAt??"")<A.lastConnectedAt)?A:x,null))==null?void 0:se.deviceId)??null:null;return e.jsxs("div",{"data-testid":"settings-remote",className:"p-4 max-w-[760px] space-y-[22px]",children:[te&&e.jsx(ve,{testId:"settings-remote-sas",codeTestId:"settings-remote-sas-code",confirmTestId:"settings-remote-sas-confirm",code:te,onConfirm:U}),Ne==="failed"&&e.jsxs("div",{className:"flex items-center gap-3.5 px-5 py-4 rounded-2xl border border-[#eccdbe] bg-[#f8e8e0]",children:[e.jsx("span",{className:"w-4 h-4 rounded-full bg-accent text-white grid place-items-center text-[11px] font-bold shrink-0",children:"!"}),e.jsxs("div",{className:"text-[13px] text-[#9a3f1f]",children:[e.jsx("strong",{className:"font-semibold",children:"E2E key exchange failed."})," ",e.jsx("span",{className:"text-fg-dim",children:"The session key could not be established. Reconnect the mobile app to retry."})]})]}),e.jsxs("div",{className:`flex items-center gap-3.5 px-5 py-4 rounded-2xl border ${J?"border-[#e8cdb9] bg-[#f5e9df]":"border-line bg-bg-hi"}`,children:[e.jsx("span",{className:`w-[38px] h-[38px] rounded-[11px] shrink-0 grid place-items-center ${J?"bg-[#f0d9c8] text-accent":"bg-[#e4ebd6] text-sage"}`,children:e.jsx(H,{name:J?"wifi":"shield",size:20})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"text-[14.5px] font-semibold text-fg mb-0.5",children:J?"Remote control is active":O?"Remote control is idle":"Remote control is off"}),e.jsx("div",{className:"text-[13px] text-fg-dim leading-snug",children:J?"A web session can send commands to this machine. Revoke below if unexpected.":O?"The relay is on but no device is connected. Pair a device to begin.":"The relay connection is closed — no remote commands are accepted. Enable it below only when you need it."})]}),z&&we?e.jsx(L,{tone:"default",className:"!text-sage !border-sage/40",children:"E2E authenticated"}):z?e.jsx(L,{tone:"warn",children:"E2E · awaiting SAS"}):e.jsx(L,{tone:"dim",children:"relay only · not E2E yet"})]}),e.jsxs("div",{children:[e.jsx(_,{children:"Remote control"}),e.jsxs("div",{className:"bg-bg-hi border border-line rounded-2xl overflow-hidden",children:[e.jsx(xe,{first:!0,testId:"settings-remote-enable",label:"Allow remote control from the web",hint:"Master switch. When off, the relay refuses every connection.",on:O,disabled:a,onChange:()=>{a||E()}}),e.jsx(xe,{testId:"settings-remote-control",label:"Allow command writes (pty + scheduler)",hint:F?"A paired device can run shell commands and queue jobs on this machine.":"Paired devices can watch session output but cannot send commands.",warn:F,disabled:!O||p,on:F&&O,onChange:()=>{O&&!p&&v()}})]})]}),e.jsxs("div",{children:[e.jsx(_,{children:"Pair a device"}),j==="idle"?e.jsxs("div",{className:"flex items-center justify-between gap-4 bg-bg-hi border border-line rounded-2xl px-5 py-[18px]",children:[e.jsxs("div",{"data-testid":"settings-remote-pair-hint",className:"text-[13.5px] text-fg-dim leading-relaxed max-w-[420px]",children:["On your phone open ",e.jsx("strong",{className:"text-fg font-semibold",children:"bilko.run/projects/session-manager"}),", sign in, and tap"," ",e.jsx("strong",{className:"text-fg font-semibold",children:"Generate pairing code"}),". Enter the 8-character code here."]}),e.jsx(D,{testId:"settings-remote-pair-start",kind:"soft",icon:"link",onClick:()=>i("enter-otp"),children:"Pair Device…"})]}):e.jsxs("div",{className:"flex items-center gap-5 bg-bg-hi border border-accent/40 rounded-2xl px-6 py-[22px]",children:[e.jsx("span",{className:"w-[52px] h-[52px] rounded-xl bg-bg border border-line grid place-items-center text-accent shrink-0",children:e.jsx(H,{name:"link",size:24})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"text-[11.5px] font-bold uppercase tracking-[0.8px] text-fg-faint mb-2",children:"Enter the code from your phone"}),e.jsx("input",{ref:h,"data-testid":"settings-remote-otp",value:u,onChange:x=>g(x.target.value.toUpperCase().replace(/[^A-Z0-9]/g,"")),onKeyDown:x=>{x.key==="Enter"&&d()},maxLength:8,placeholder:"XXXXXXXX",disabled:j==="pairing",className:"w-full bg-transparent border-0 outline-none font-mono text-[30px] font-semibold tracking-[6px] text-fg placeholder:text-fg-faint/40 disabled:opacity-50"})]}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsx(D,{testId:"settings-remote-pair-confirm",kind:"soft",onClick:d,disabled:j==="pairing"||u.length<8,children:j==="pairing"?"Pairing…":"Confirm"}),e.jsx(D,{kind:"ghost",onClick:()=>{i("idle"),g("")},disabled:j==="pairing",children:"cancel"})]})]})]}),e.jsxs("div",{children:[e.jsx(_,{right:G.length>0?e.jsxs("span",{className:"text-[11.5px] text-fg-faint",children:[G.length," paired"]}):void 0,children:"Paired devices"}),G.length===0?e.jsx(W,{children:"No devices paired yet."}):e.jsx("div",{className:"space-y-2",children:G.map(x=>e.jsx(St,{device:x,online:x.deviceId===ke,onRevoke:C,revoking:y===x.deviceId},x.deviceId))})]}),e.jsx(kt,{}),e.jsxs("div",{children:[e.jsx(_,{right:e.jsx("button",{"data-testid":"settings-remote-audit-toggle",onClick:ee,className:"text-[12px] text-fg-faint hover:text-fg-dim transition-colors",children:N?"Hide":"Show last 100 · 0600, stays on this machine"}),children:"Audit log"}),N&&e.jsx("div",{className:"bg-bg-hi border border-line rounded-xl overflow-auto max-h-64 mb-2",children:S.length===0?e.jsx("p",{className:"p-4 text-[12.5px] text-fg-faint",children:"No entries today."}):e.jsx("pre",{"data-testid":"settings-remote-audit",className:"p-4 text-[12px] text-fg-dim font-mono whitespace-pre-wrap leading-relaxed",children:S.join(`
|
|
5
|
-
`)})}),e.jsxs("p",{className:"text-[12px] text-fg-faint",children:["Full log at"," ",e.jsx("code",{className:"font-mono text-fg-faint",children:"~/.claude/session-manager/logs/remote-audit-YYYY-MM-DD.log"})," ","(0600, never leaves this machine)"]})]}),e.jsxs("div",{className:"flex items-center justify-between gap-4 bg-[#f8e8e0] border border-[#eccdbe] rounded-2xl px-5 py-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx("span",{className:"w-4 h-4 rounded-full bg-accent text-white grid place-items-center text-[11px] font-bold shrink-0",children:"!"}),e.jsx("span",{className:"text-sm font-semibold text-[#9a3f1f]",children:"Panic — disconnect & revoke everything"})]}),e.jsx("div",{className:"text-[12.5px] text-fg-dim leading-snug max-w-[440px]",children:"Tears down every active session and invalidates all paired-device tokens. Devices must re-pair. Use if you suspect compromise."})]}),e.jsx("button",{"data-testid":"settings-remote-revoke-all",onClick:T,disabled:w,className:"shrink-0 rounded-lg bg-accent text-white px-[18px] py-2 text-[13px] font-semibold hover:opacity-90 disabled:opacity-50 transition-opacity",children:w?"Revoking…":"Revoke all"})]})]})}const Et={compact:"Compact",roomy:"Roomy"};function Rt(){const{model:t,setModel:s}=Oe(),{catalog:n}=De(null),{density:o,setDensity:r}=$e();return e.jsxs("div",{className:"p-4 max-w-3xl space-y-5 text-sm",children:[e.jsxs("header",{className:"space-y-1",children:[e.jsx("h2",{className:"text-fg text-base font-medium",children:"Session Manager preferences"}),e.jsx("p",{className:"text-fg-dim text-xs leading-relaxed",children:"Native app preferences, stored locally — not part of Claude Code's own settings."})]}),e.jsxs("section",{className:"border border-line rounded p-3 space-y-3",children:[e.jsxs("div",{className:"block space-y-1",children:[e.jsx("span",{className:"text-fg-dim text-xs",children:"Default model for raw sessions"}),e.jsx(ae,{options:Me(n),value:t,onChange:s,mono:!0}),e.jsx("span",{className:"text-fg-faint text-[11px]",children:"Used when opening a raw interactive session without an explicit per-launch override."})]}),e.jsxs("div",{className:"block space-y-1",children:[e.jsx("span",{className:"text-fg-dim text-xs",children:"Density"}),e.jsx(ae,{options:["compact","roomy"],value:o,onChange:a=>r(a),labels:Et}),e.jsx("span",{className:"text-fg-faint text-[11px]",children:"Compact tightens spacing across the app's chrome; Roomy is the default."})]})]})]})}function It({cwd:t}){const[s,n]=l.useState(!1),[o,r]=l.useState(!1),[a,c]=l.useState(!1),[p,b]=l.useState(!1);l.useEffect(()=>{var y,f;let g=!1;return n(!1),Promise.resolve((f=(y=window.api.promptSessions)==null?void 0:y.getWorktreeDisabled)==null?void 0:f.call(y,{cwd:t})).then(w=>{g||(r((w==null?void 0:w.disabled)??!1),c((w==null?void 0:w.disabled)??!1),n(!0))},()=>{g||n(!0)}),()=>{g=!0}},[t]);const j=s&&a!==o,i=()=>{var g,y;b(!0),Promise.resolve((y=(g=window.api.promptSessions)==null?void 0:g.setWorktreeDisabled)==null?void 0:y.call(g,{cwd:t,disabled:a})).then(f=>{r((f==null?void 0:f.disabled)??a),c((f==null?void 0:f.disabled)??a)}).catch(f=>ue.error(f instanceof Error?f.message:String(f))).finally(()=>b(!1))},u=()=>c(o);return e.jsxs("div",{"data-testid":"settings-epic-isolation",className:"border-b border-line bg-bg-elev px-3 py-2.5 text-[11.5px] leading-snug",children:[e.jsxs("label",{className:"flex items-start gap-2",children:[e.jsx("input",{type:"checkbox",checked:a,disabled:!s||p,onChange:g=>c(g.target.checked),"data-testid":"settings-epic-isolation-checkbox",className:"mt-0.5"}),e.jsxs("span",{children:[e.jsx("span",{className:"font-semibold text-fg",children:"Disable Epic worktree isolation for this project"}),e.jsxs("span",{className:"block text-fg-dim",children:["Off by default — each active Epic runs in its own isolated ",e.jsx("code",{children:"git worktree"})," (branch"," ",e.jsx("code",{children:"sm-epic/<id>"}),"), merged back to main at an explicit checkpoint. Turning this on makes every new Epic in this project run directly in the shared working tree instead, same as before this feature existed."]})]})]}),j&&e.jsx(pe,{dirty:j,busy:p,onSave:i,onRevert:u})]})}const me={user:{title:"Global settings",body:"This is the real ~/.claude/settings.json on disk — the same file the claude CLI reads on every session it starts. Edits apply machine-wide, to every project and every session."},project:{title:"Project settings",body:"This is the real <project>/.claude/settings.json on disk, checked into git. Edits apply to every current and future session in this project, for anyone who clones it."},local:{title:"Local settings",body:"This is the real <project>/.claude/settings.local.json on disk, gitignored. Edits apply to every current and future session in this project, on this machine only."}};function At(){const t=Le(),s=re(d=>d.tabs),n=re(d=>d.activeTabId),o=s.find(d=>d.id===n)??null,r=(o==null?void 0:o.cwd)??null,a=Fe(d=>d.navFace),c=l.useRef(!1),p=l.useRef(a),[b,j]=l.useState(()=>a==="project"&&r?"project":"user"),[i,u]=l.useState("effective");l.useEffect(()=>{if(p.current!==a){if(p.current=a,c.current){c.current=!1;return}j(a==="project"&&r?"project":"user")}},[a,r]),l.useEffect(()=>{a==="project"&&(i==="telemetry"||i==="remote"||i==="app")&&u("effective")},[a,i]);const g=d=>{c.current=!0,j(d)},y=Je(ie,t,r),f=y[b]??null,w=q(d=>d.files),R=q(d=>d.setDraft),S=q(d=>d.saveJson),m=q(d=>d.revert),[N,I]=l.useState(null),h=l.useMemo(()=>_e(Be(w,y)),[w,y]),k=(d,C,T)=>{var z;const U=y[T??b];if(!U)return;I(null);const O=((z=w[U])==null?void 0:z.draftRaw)??"";let F={};if(O.trim())try{F=JSON.parse(O)}catch{F={}}const V=Ue(F,d,C);R(U,JSON.stringify(V,null,2)+`
|
|
6
|
-
`)};if(!t)return e.jsx(K,{title:"loading…"});const E=f?w[f]:null,v=d=>d!=="user"&&!r;return e.jsx(ze,{toolbar:e.jsxs(e.Fragment,{children:[e.jsx(We,{options:[{key:"effective",label:"Guided"},{key:"tree",label:"Tree"},{key:"raw",label:"Raw"},...a==="home"?[{key:"telemetry",label:"Telemetry"},{key:"remote",label:"Phone remote"},{key:"app",label:"Session Manager"}]:[]],active:i,onChange:u}),i!=="telemetry"&&i!=="remote"&&i!=="app"&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"mx-2 text-fg-faint",children:"·"}),e.jsx(Ge,{scopes:ie.scopes,active:b,onChange:g,annotate:d=>{if(v(d))return{exists:!1};const C=y[d];if(!C)return null;const T=w[C];return{exists:(T==null?void 0:T.exists)??!1,dirty:(T==null?void 0:T.dirty)??!1}}}),e.jsx("span",{className:"ml-3 text-fg-faint truncate",children:i==="effective"?`overrides → ${f??"—"}`:f??"—"})]}),e.jsx("div",{className:"flex-1"}),e.jsx("a",{href:"https://code.claude.com/docs/en/settings",target:"_blank",rel:"noreferrer",className:"text-fg-faint hover:text-fg-dim underline-offset-2 hover:underline",children:"schema reference ↗"})]}),footer:i!=="telemetry"&&i!=="remote"&&i!=="app"&&f&&E?e.jsx(pe,{dirty:E.dirty,busy:E.busy,parseError:N||E.parseError,lastSavedAt:E.lastSavedAt,leading:E.exists?null:e.jsx("span",{children:"file will be created on save"}),onSave:async()=>{I(null);const d=await S(f);d.ok||I(d.error??"save failed")},onRevert:()=>{I(null),m(f)}}):null,children:i==="telemetry"?e.jsx(ht,{}):i==="remote"?e.jsx(Ct,{}):i==="app"?e.jsx(Rt,{}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{"data-testid":"settings-scope-note",className:"sticky top-0 z-10 border-b border-line bg-bg-elev px-3 py-2 text-[11.5px] leading-snug",children:[e.jsx("span",{className:"font-semibold text-fg",children:me[b].title}),e.jsx("span",{className:"mx-1.5 text-fg-faint",children:"·"}),e.jsx("span",{className:"text-fg-dim",children:me[b].body}),f&&e.jsx("span",{className:"ml-1.5 font-mono text-fg-faint",children:f})]}),b==="project"&&r&&e.jsx(It,{cwd:r}),v(b)?e.jsx(K,{title:"no active project",hint:"open a tab in a project directory to edit project or local settings"}):i==="effective"?e.jsx(tt,{node:h,targetScope:b,onOverride:k,schema:oe()}):i==="tree"?e.jsx(Ke,{node:h,targetScope:b,onOverride:k,schema:oe()}):f&&E?e.jsx(He,{path:f,value:E.draftRaw,onChange:d=>{I(null),R(f,d)}}):e.jsx(K,{title:"resolving…"})]})})}const Bt=l.memo(At);export{me as SETTINGS_SCOPE_NOTES,Bt as Settings};
|