@hellcoder/companion 0.111.0 → 0.111.1
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-DO5MiZyp.js → AgentsPage-Dc23pQBM.js} +1 -1
- package/dist/assets/{CronManager-BSNkRBGn.js → CronManager-CKvnO3df.js} +1 -1
- package/dist/assets/{DashboardPage-DqwmmyJ6.js → DashboardPage-_gU5oXmV.js} +1 -1
- package/dist/assets/{IntegrationsPage-CxavpMnn.js → IntegrationsPage-zBdnuEDO.js} +1 -1
- package/dist/assets/{LinearOAuthSettingsPage-Bs_FXqPA.js → LinearOAuthSettingsPage-v4LYNLyW.js} +1 -1
- package/dist/assets/{LinearSettingsPage-zerN3EmK.js → LinearSettingsPage-C-Gm_aeW.js} +1 -1
- package/dist/assets/{Playground-DNlOjOnC.js → Playground-BheM7iin.js} +1 -1
- package/dist/assets/{PromptsPage-D20LKwla.js → PromptsPage-Bt2idDR8.js} +1 -1
- package/dist/assets/{RunsPage-ho-uEj6h.js → RunsPage-ib31kftd.js} +1 -1
- package/dist/assets/{SandboxManager-BY2NPfsU.js → SandboxManager-Ch0-1iE8.js} +1 -1
- package/dist/assets/SettingsPage-fqy7b9b8.js +1 -0
- package/dist/assets/{TailscalePage-pv47ZX2f.js → TailscalePage-Cf9_ENdO.js} +1 -1
- package/dist/assets/{index-C7qt99R_.js → index-Baw3PrqK.js} +52 -52
- package/dist/assets/{sw-register-DZ08pZIJ.js → sw-register-D-9XveNW.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/sw.js +1 -1
- package/package.json +1 -1
- package/server/auto-namer.test.ts +4 -0
- package/server/claude-adapter.test.ts +111 -6
- package/server/claude-adapter.ts +106 -0
- package/server/linear-connections.test.ts +4 -0
- package/server/routes/settings-routes.ts +10 -0
- package/server/routes.test.ts +27 -0
- package/server/session-orchestrator.test.ts +3 -0
- package/server/settings-manager.test.ts +3 -0
- package/server/settings-manager.ts +14 -1
- package/server/ws-bridge-codex.test.ts +6 -0
- package/dist/assets/SettingsPage-CvYCqkm1.js +0 -1
package/server/routes.test.ts
CHANGED
|
@@ -1159,6 +1159,7 @@ describe("GET /api/sessions/:id/archive-info", () => {
|
|
|
1159
1159
|
dockerAutoUpdate: false,
|
|
1160
1160
|
proactiveKeepaliveEnabled: true,
|
|
1161
1161
|
wedgeKillEnabled: true,
|
|
1162
|
+
silenceProbeEnabled: true,
|
|
1162
1163
|
updatedAt: 0,
|
|
1163
1164
|
});
|
|
1164
1165
|
const res = await app.request("/api/sessions/s1/archive-info", { method: "GET" });
|
|
@@ -1535,6 +1536,7 @@ describe("GET /api/settings", () => {
|
|
|
1535
1536
|
dockerAutoUpdate: false,
|
|
1536
1537
|
proactiveKeepaliveEnabled: true,
|
|
1537
1538
|
wedgeKillEnabled: true,
|
|
1539
|
+
silenceProbeEnabled: true,
|
|
1538
1540
|
updatedAt: 123,
|
|
1539
1541
|
});
|
|
1540
1542
|
|
|
@@ -1569,6 +1571,7 @@ describe("GET /api/settings", () => {
|
|
|
1569
1571
|
dockerAutoUpdate: false,
|
|
1570
1572
|
proactiveKeepaliveEnabled: true,
|
|
1571
1573
|
wedgeKillEnabled: true,
|
|
1574
|
+
silenceProbeEnabled: true,
|
|
1572
1575
|
});
|
|
1573
1576
|
});
|
|
1574
1577
|
|
|
@@ -1603,6 +1606,7 @@ describe("GET /api/settings", () => {
|
|
|
1603
1606
|
dockerAutoUpdate: false,
|
|
1604
1607
|
proactiveKeepaliveEnabled: true,
|
|
1605
1608
|
wedgeKillEnabled: true,
|
|
1609
|
+
silenceProbeEnabled: true,
|
|
1606
1610
|
updatedAt: 123,
|
|
1607
1611
|
});
|
|
1608
1612
|
|
|
@@ -1637,6 +1641,7 @@ describe("GET /api/settings", () => {
|
|
|
1637
1641
|
dockerAutoUpdate: false,
|
|
1638
1642
|
proactiveKeepaliveEnabled: true,
|
|
1639
1643
|
wedgeKillEnabled: true,
|
|
1644
|
+
silenceProbeEnabled: true,
|
|
1640
1645
|
});
|
|
1641
1646
|
});
|
|
1642
1647
|
|
|
@@ -1672,6 +1677,7 @@ describe("GET /api/settings", () => {
|
|
|
1672
1677
|
dockerAutoUpdate: false,
|
|
1673
1678
|
proactiveKeepaliveEnabled: true,
|
|
1674
1679
|
wedgeKillEnabled: true,
|
|
1680
|
+
silenceProbeEnabled: true,
|
|
1675
1681
|
updatedAt: 100,
|
|
1676
1682
|
});
|
|
1677
1683
|
|
|
@@ -1715,6 +1721,7 @@ describe("PUT /api/settings", () => {
|
|
|
1715
1721
|
dockerAutoUpdate: false,
|
|
1716
1722
|
proactiveKeepaliveEnabled: true,
|
|
1717
1723
|
wedgeKillEnabled: true,
|
|
1724
|
+
silenceProbeEnabled: true,
|
|
1718
1725
|
updatedAt: 456,
|
|
1719
1726
|
});
|
|
1720
1727
|
|
|
@@ -1771,6 +1778,7 @@ describe("PUT /api/settings", () => {
|
|
|
1771
1778
|
dockerAutoUpdate: false,
|
|
1772
1779
|
proactiveKeepaliveEnabled: true,
|
|
1773
1780
|
wedgeKillEnabled: true,
|
|
1781
|
+
silenceProbeEnabled: true,
|
|
1774
1782
|
});
|
|
1775
1783
|
});
|
|
1776
1784
|
|
|
@@ -1805,6 +1813,7 @@ describe("PUT /api/settings", () => {
|
|
|
1805
1813
|
dockerAutoUpdate: false,
|
|
1806
1814
|
proactiveKeepaliveEnabled: true,
|
|
1807
1815
|
wedgeKillEnabled: true,
|
|
1816
|
+
silenceProbeEnabled: true,
|
|
1808
1817
|
updatedAt: 789,
|
|
1809
1818
|
});
|
|
1810
1819
|
|
|
@@ -1856,6 +1865,7 @@ describe("PUT /api/settings", () => {
|
|
|
1856
1865
|
dockerAutoUpdate: false,
|
|
1857
1866
|
proactiveKeepaliveEnabled: true,
|
|
1858
1867
|
wedgeKillEnabled: true,
|
|
1868
|
+
silenceProbeEnabled: true,
|
|
1859
1869
|
updatedAt: 999,
|
|
1860
1870
|
});
|
|
1861
1871
|
|
|
@@ -2007,6 +2017,7 @@ describe("PUT /api/settings", () => {
|
|
|
2007
2017
|
dockerAutoUpdate: false,
|
|
2008
2018
|
proactiveKeepaliveEnabled: true,
|
|
2009
2019
|
wedgeKillEnabled: true,
|
|
2020
|
+
silenceProbeEnabled: true,
|
|
2010
2021
|
updatedAt: 500,
|
|
2011
2022
|
});
|
|
2012
2023
|
|
|
@@ -2264,6 +2275,7 @@ describe("GET /api/linear/issues", () => {
|
|
|
2264
2275
|
dockerAutoUpdate: false,
|
|
2265
2276
|
proactiveKeepaliveEnabled: true,
|
|
2266
2277
|
wedgeKillEnabled: true,
|
|
2278
|
+
silenceProbeEnabled: true,
|
|
2267
2279
|
updatedAt: 0,
|
|
2268
2280
|
});
|
|
2269
2281
|
vi.mocked(resolveApiKey).mockReturnValue(null);
|
|
@@ -2305,6 +2317,7 @@ describe("GET /api/linear/issues", () => {
|
|
|
2305
2317
|
dockerAutoUpdate: false,
|
|
2306
2318
|
proactiveKeepaliveEnabled: true,
|
|
2307
2319
|
wedgeKillEnabled: true,
|
|
2320
|
+
silenceProbeEnabled: true,
|
|
2308
2321
|
updatedAt: 0,
|
|
2309
2322
|
});
|
|
2310
2323
|
|
|
@@ -2399,6 +2412,7 @@ describe("GET /api/linear/issues", () => {
|
|
|
2399
2412
|
dockerAutoUpdate: false,
|
|
2400
2413
|
proactiveKeepaliveEnabled: true,
|
|
2401
2414
|
wedgeKillEnabled: true,
|
|
2415
|
+
silenceProbeEnabled: true,
|
|
2402
2416
|
updatedAt: 0,
|
|
2403
2417
|
});
|
|
2404
2418
|
|
|
@@ -2500,6 +2514,7 @@ describe("GET /api/linear/issues", () => {
|
|
|
2500
2514
|
dockerAutoUpdate: false,
|
|
2501
2515
|
proactiveKeepaliveEnabled: true,
|
|
2502
2516
|
wedgeKillEnabled: true,
|
|
2517
|
+
silenceProbeEnabled: true,
|
|
2503
2518
|
updatedAt: 0,
|
|
2504
2519
|
});
|
|
2505
2520
|
|
|
@@ -2566,6 +2581,7 @@ describe("GET /api/linear/connection", () => {
|
|
|
2566
2581
|
dockerAutoUpdate: false,
|
|
2567
2582
|
proactiveKeepaliveEnabled: true,
|
|
2568
2583
|
wedgeKillEnabled: true,
|
|
2584
|
+
silenceProbeEnabled: true,
|
|
2569
2585
|
updatedAt: 0,
|
|
2570
2586
|
});
|
|
2571
2587
|
vi.mocked(resolveApiKey).mockReturnValue(null);
|
|
@@ -2607,6 +2623,7 @@ describe("GET /api/linear/connection", () => {
|
|
|
2607
2623
|
dockerAutoUpdate: false,
|
|
2608
2624
|
proactiveKeepaliveEnabled: true,
|
|
2609
2625
|
wedgeKillEnabled: true,
|
|
2626
|
+
silenceProbeEnabled: true,
|
|
2610
2627
|
updatedAt: 0,
|
|
2611
2628
|
});
|
|
2612
2629
|
|
|
@@ -2670,6 +2687,7 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2670
2687
|
dockerAutoUpdate: false,
|
|
2671
2688
|
proactiveKeepaliveEnabled: true,
|
|
2672
2689
|
wedgeKillEnabled: true,
|
|
2690
|
+
silenceProbeEnabled: true,
|
|
2673
2691
|
updatedAt: 0,
|
|
2674
2692
|
});
|
|
2675
2693
|
|
|
@@ -2715,6 +2733,7 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2715
2733
|
dockerAutoUpdate: false,
|
|
2716
2734
|
proactiveKeepaliveEnabled: true,
|
|
2717
2735
|
wedgeKillEnabled: true,
|
|
2736
|
+
silenceProbeEnabled: true,
|
|
2718
2737
|
updatedAt: 0,
|
|
2719
2738
|
});
|
|
2720
2739
|
|
|
@@ -2759,6 +2778,7 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2759
2778
|
dockerAutoUpdate: false,
|
|
2760
2779
|
proactiveKeepaliveEnabled: true,
|
|
2761
2780
|
wedgeKillEnabled: true,
|
|
2781
|
+
silenceProbeEnabled: true,
|
|
2762
2782
|
updatedAt: 0,
|
|
2763
2783
|
});
|
|
2764
2784
|
vi.mocked(resolveApiKey).mockReturnValue(null);
|
|
@@ -2805,6 +2825,7 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2805
2825
|
dockerAutoUpdate: false,
|
|
2806
2826
|
proactiveKeepaliveEnabled: true,
|
|
2807
2827
|
wedgeKillEnabled: true,
|
|
2828
|
+
silenceProbeEnabled: true,
|
|
2808
2829
|
updatedAt: 0,
|
|
2809
2830
|
});
|
|
2810
2831
|
|
|
@@ -2885,6 +2906,7 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2885
2906
|
dockerAutoUpdate: false,
|
|
2886
2907
|
proactiveKeepaliveEnabled: true,
|
|
2887
2908
|
wedgeKillEnabled: true,
|
|
2909
|
+
silenceProbeEnabled: true,
|
|
2888
2910
|
updatedAt: 0,
|
|
2889
2911
|
});
|
|
2890
2912
|
|
|
@@ -2944,6 +2966,7 @@ describe("GET /api/linear/projects", () => {
|
|
|
2944
2966
|
dockerAutoUpdate: false,
|
|
2945
2967
|
proactiveKeepaliveEnabled: true,
|
|
2946
2968
|
wedgeKillEnabled: true,
|
|
2969
|
+
silenceProbeEnabled: true,
|
|
2947
2970
|
updatedAt: 0,
|
|
2948
2971
|
});
|
|
2949
2972
|
vi.mocked(resolveApiKey).mockReturnValue(null);
|
|
@@ -2985,6 +3008,7 @@ describe("GET /api/linear/projects", () => {
|
|
|
2985
3008
|
dockerAutoUpdate: false,
|
|
2986
3009
|
proactiveKeepaliveEnabled: true,
|
|
2987
3010
|
wedgeKillEnabled: true,
|
|
3011
|
+
silenceProbeEnabled: true,
|
|
2988
3012
|
updatedAt: 0,
|
|
2989
3013
|
});
|
|
2990
3014
|
|
|
@@ -3056,6 +3080,7 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
3056
3080
|
dockerAutoUpdate: false,
|
|
3057
3081
|
proactiveKeepaliveEnabled: true,
|
|
3058
3082
|
wedgeKillEnabled: true,
|
|
3083
|
+
silenceProbeEnabled: true,
|
|
3059
3084
|
updatedAt: 0,
|
|
3060
3085
|
});
|
|
3061
3086
|
vi.mocked(resolveApiKey).mockReturnValue(null);
|
|
@@ -3097,6 +3122,7 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
3097
3122
|
dockerAutoUpdate: false,
|
|
3098
3123
|
proactiveKeepaliveEnabled: true,
|
|
3099
3124
|
wedgeKillEnabled: true,
|
|
3125
|
+
silenceProbeEnabled: true,
|
|
3100
3126
|
updatedAt: 0,
|
|
3101
3127
|
});
|
|
3102
3128
|
|
|
@@ -3183,6 +3209,7 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
3183
3209
|
dockerAutoUpdate: false,
|
|
3184
3210
|
proactiveKeepaliveEnabled: true,
|
|
3185
3211
|
wedgeKillEnabled: true,
|
|
3212
|
+
silenceProbeEnabled: true,
|
|
3186
3213
|
updatedAt: 0,
|
|
3187
3214
|
});
|
|
3188
3215
|
|
|
@@ -51,6 +51,7 @@ vi.mock("./settings-manager.js", () => ({
|
|
|
51
51
|
onboardingCompleted: false,
|
|
52
52
|
proactiveKeepaliveEnabled: true,
|
|
53
53
|
wedgeKillEnabled: true,
|
|
54
|
+
silenceProbeEnabled: true,
|
|
54
55
|
})),
|
|
55
56
|
}));
|
|
56
57
|
|
|
@@ -249,6 +250,7 @@ describe("SessionOrchestrator", () => {
|
|
|
249
250
|
onboardingCompleted: false,
|
|
250
251
|
proactiveKeepaliveEnabled: true,
|
|
251
252
|
wedgeKillEnabled: true,
|
|
253
|
+
silenceProbeEnabled: true,
|
|
252
254
|
} as any);
|
|
253
255
|
vi.mocked(containerManager.createContainer).mockReturnValue({
|
|
254
256
|
containerId: "cid-1",
|
|
@@ -1834,6 +1836,7 @@ describe("SessionOrchestrator", () => {
|
|
|
1834
1836
|
...settingsManager.getSettings(),
|
|
1835
1837
|
proactiveKeepaliveEnabled: false,
|
|
1836
1838
|
wedgeKillEnabled: true,
|
|
1839
|
+
silenceProbeEnabled: true,
|
|
1837
1840
|
});
|
|
1838
1841
|
deps.launcher.getSession.mockReturnValue({
|
|
1839
1842
|
archived: false,
|
|
@@ -54,6 +54,7 @@ describe("settings-manager", () => {
|
|
|
54
54
|
dockerAutoUpdate: false,
|
|
55
55
|
proactiveKeepaliveEnabled: true,
|
|
56
56
|
wedgeKillEnabled: true,
|
|
57
|
+
silenceProbeEnabled: true,
|
|
57
58
|
cliBridgeMode: "loopback",
|
|
58
59
|
claudeBridgeMode: "none",
|
|
59
60
|
claudeBridgeIngressUrl: "",
|
|
@@ -119,6 +120,7 @@ describe("settings-manager", () => {
|
|
|
119
120
|
dockerAutoUpdate: false,
|
|
120
121
|
proactiveKeepaliveEnabled: true,
|
|
121
122
|
wedgeKillEnabled: true,
|
|
123
|
+
silenceProbeEnabled: true,
|
|
122
124
|
cliBridgeMode: "loopback",
|
|
123
125
|
claudeBridgeMode: "none",
|
|
124
126
|
claudeBridgeIngressUrl: "",
|
|
@@ -210,6 +212,7 @@ describe("settings-manager", () => {
|
|
|
210
212
|
dockerAutoUpdate: false,
|
|
211
213
|
proactiveKeepaliveEnabled: true,
|
|
212
214
|
wedgeKillEnabled: true,
|
|
215
|
+
silenceProbeEnabled: true,
|
|
213
216
|
cliBridgeMode: "loopback",
|
|
214
217
|
claudeBridgeMode: "none",
|
|
215
218
|
claudeBridgeIngressUrl: "",
|
|
@@ -104,6 +104,16 @@ export interface CompanionSettings {
|
|
|
104
104
|
* to exit on its own instead of being SIGTERMed.
|
|
105
105
|
*/
|
|
106
106
|
wedgeKillEnabled: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* When true (default), a CLI that goes silent while its stdout stays OPEN is
|
|
109
|
+
* probed with a control request and, if it does not answer, treated as
|
|
110
|
+
* disconnected so the session relaunches and replays its in-flight turn.
|
|
111
|
+
*
|
|
112
|
+
* This covers the case no stdout-EOF logic can see: the stream never closes,
|
|
113
|
+
* the process stays healthy, and the session would otherwise hang forever
|
|
114
|
+
* with no error surfaced. Disable to leave silent sessions alone.
|
|
115
|
+
*/
|
|
116
|
+
silenceProbeEnabled: boolean;
|
|
107
117
|
/** See CliBridgeMode. Defaults to "loopback". Optional in fixtures; normalize() applies the default. */
|
|
108
118
|
cliBridgeMode?: CliBridgeMode;
|
|
109
119
|
/** See ClaudeBridgeMode. Defaults to "none". Persists across companion restarts. */
|
|
@@ -149,6 +159,7 @@ let settings: CompanionSettings = {
|
|
|
149
159
|
dockerAutoUpdate: false,
|
|
150
160
|
proactiveKeepaliveEnabled: true,
|
|
151
161
|
wedgeKillEnabled: true,
|
|
162
|
+
silenceProbeEnabled: true,
|
|
152
163
|
cliBridgeMode: "loopback",
|
|
153
164
|
claudeBridgeMode: "none",
|
|
154
165
|
claudeBridgeIngressUrl: "",
|
|
@@ -201,6 +212,7 @@ function normalize(raw: Partial<CompanionSettings> | null | undefined): Companio
|
|
|
201
212
|
dockerAutoUpdate: typeof raw?.dockerAutoUpdate === "boolean" ? raw.dockerAutoUpdate : false,
|
|
202
213
|
proactiveKeepaliveEnabled: typeof raw?.proactiveKeepaliveEnabled === "boolean" ? raw.proactiveKeepaliveEnabled : true,
|
|
203
214
|
wedgeKillEnabled: typeof raw?.wedgeKillEnabled === "boolean" ? raw.wedgeKillEnabled : true,
|
|
215
|
+
silenceProbeEnabled: typeof raw?.silenceProbeEnabled === "boolean" ? raw.silenceProbeEnabled : true,
|
|
204
216
|
cliBridgeMode: raw?.cliBridgeMode === "jsonHandoff" ? "jsonHandoff" : "loopback",
|
|
205
217
|
claudeBridgeMode: raw?.claudeBridgeMode === "patched" ? "patched" : "none",
|
|
206
218
|
claudeBridgeIngressUrl: typeof raw?.claudeBridgeIngressUrl === "string" ? raw.claudeBridgeIngressUrl : "",
|
|
@@ -234,7 +246,7 @@ export function getSettings(): CompanionSettings {
|
|
|
234
246
|
}
|
|
235
247
|
|
|
236
248
|
export function updateSettings(
|
|
237
|
-
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" | "wedgeKillEnabled" | "cliBridgeMode" | "claudeBridgeMode" | "claudeBridgeIngressUrl" | "claudeCompatBannerDismissedVersion">>,
|
|
249
|
+
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" | "wedgeKillEnabled" | "silenceProbeEnabled" | "cliBridgeMode" | "claudeBridgeMode" | "claudeBridgeIngressUrl" | "claudeCompatBannerDismissedVersion">>,
|
|
238
250
|
): CompanionSettings {
|
|
239
251
|
ensureLoaded();
|
|
240
252
|
settings = normalize({
|
|
@@ -267,6 +279,7 @@ export function updateSettings(
|
|
|
267
279
|
dockerAutoUpdate: patch.dockerAutoUpdate ?? settings.dockerAutoUpdate,
|
|
268
280
|
proactiveKeepaliveEnabled: patch.proactiveKeepaliveEnabled ?? settings.proactiveKeepaliveEnabled,
|
|
269
281
|
wedgeKillEnabled: patch.wedgeKillEnabled ?? settings.wedgeKillEnabled,
|
|
282
|
+
silenceProbeEnabled: patch.silenceProbeEnabled ?? settings.silenceProbeEnabled,
|
|
270
283
|
cliBridgeMode: patch.cliBridgeMode ?? settings.cliBridgeMode,
|
|
271
284
|
claudeBridgeMode: patch.claudeBridgeMode ?? settings.claudeBridgeMode,
|
|
272
285
|
claudeBridgeIngressUrl: patch.claudeBridgeIngressUrl ?? settings.claudeBridgeIngressUrl,
|
|
@@ -141,6 +141,7 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
141
141
|
dockerAutoUpdate: false,
|
|
142
142
|
proactiveKeepaliveEnabled: true,
|
|
143
143
|
wedgeKillEnabled: true,
|
|
144
|
+
silenceProbeEnabled: true,
|
|
144
145
|
updatedAt: 0,
|
|
145
146
|
});
|
|
146
147
|
});
|
|
@@ -1133,6 +1134,7 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1133
1134
|
dockerAutoUpdate: false,
|
|
1134
1135
|
proactiveKeepaliveEnabled: true,
|
|
1135
1136
|
wedgeKillEnabled: true,
|
|
1137
|
+
silenceProbeEnabled: true,
|
|
1136
1138
|
updatedAt: 0,
|
|
1137
1139
|
});
|
|
1138
1140
|
}
|
|
@@ -1315,6 +1317,7 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1315
1317
|
dockerAutoUpdate: false,
|
|
1316
1318
|
proactiveKeepaliveEnabled: true,
|
|
1317
1319
|
wedgeKillEnabled: true,
|
|
1320
|
+
silenceProbeEnabled: true,
|
|
1318
1321
|
updatedAt: 0,
|
|
1319
1322
|
});
|
|
1320
1323
|
|
|
@@ -1367,6 +1370,7 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1367
1370
|
dockerAutoUpdate: false,
|
|
1368
1371
|
proactiveKeepaliveEnabled: true,
|
|
1369
1372
|
wedgeKillEnabled: true,
|
|
1373
|
+
silenceProbeEnabled: true,
|
|
1370
1374
|
updatedAt: 0,
|
|
1371
1375
|
});
|
|
1372
1376
|
|
|
@@ -1484,6 +1488,7 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1484
1488
|
dockerAutoUpdate: false,
|
|
1485
1489
|
proactiveKeepaliveEnabled: true,
|
|
1486
1490
|
wedgeKillEnabled: true,
|
|
1491
|
+
silenceProbeEnabled: true,
|
|
1487
1492
|
updatedAt: 0,
|
|
1488
1493
|
});
|
|
1489
1494
|
|
|
@@ -1620,6 +1625,7 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1620
1625
|
dockerAutoUpdate: false,
|
|
1621
1626
|
proactiveKeepaliveEnabled: true,
|
|
1622
1627
|
wedgeKillEnabled: true,
|
|
1628
|
+
silenceProbeEnabled: true,
|
|
1623
1629
|
updatedAt: 0,
|
|
1624
1630
|
});
|
|
1625
1631
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as s,u as o,g as bt,a as n,j as e,n as ft,b as gt,s as vt}from"./index-C7qt99R_.js";const le=[{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:"dashboard",label:"Dashboard"},{id:"updates",label:"Updates"},{id:"telemetry",label:"Telemetry"},{id:"environments",label:"Environments"}];function jt({embedded:de=!1}){const[p,ue]=s.useState(""),[xe,pe]=s.useState("claude-sonnet-4-6"),[d,me]=s.useState(!1),[w,Je]=s.useState(!0),[f,S]=s.useState(!1),[he,g]=s.useState(""),[be,v]=s.useState(!1),Xe=o(t=>t.darkMode),Ze=o(t=>t.toggleDarkMode),fe=o(t=>t.diffBase),et=o(t=>t.setDiffBase),tt=o(t=>t.notificationSound),st=o(t=>t.toggleNotificationSound),ge=o(t=>t.notificationDesktop),ve=o(t=>t.setNotificationDesktop),r=o(t=>t.updateInfo),P=o(t=>t.setUpdateInfo),at=o(t=>t.setUpdateOverlayActive),nt=typeof Notification<"u",[x,y]=s.useState("stable"),[C,V]=s.useState(!1),[A,O]=s.useState(!0),[E,D]=s.useState(!0),[ye,K]=s.useState("loopback"),[M,je]=s.useState(!1),[L,Ne]=s.useState(!1),[ke,j]=s.useState(""),[we,U]=s.useState(""),[Se,ct]=s.useState(bt()),[T,$]=s.useState(!1),[F,H]=s.useState(!0),[B,Q]=s.useState(!1),[_,G]=s.useState(!1),[Ce,W]=s.useState("claude-haiku-4-5"),[Ae,q]=s.useState(3),[Ee,Y]=s.useState(30),[I,z]=s.useState(""),[Ue,Te]=s.useState("general"),[ot,Ie]=s.useState(!1),[J,Re]=s.useState(!1),[N,m]=s.useState(null),[h,Pe]=s.useState(""),[X,Ve]=s.useState(!1),[b,Oe]=s.useState(""),[Z,De]=s.useState(!1),[ee,Ke]=s.useState(!1),[rt,te]=s.useState(!1),[Me,Le]=s.useState(""),[it,$e]=s.useState(!1),[lt,Fe]=s.useState(!1),[k,He]=s.useState(null),[se,Be]=s.useState(!1),[u,Qe]=s.useState(null),[R,dt]=s.useState(0),[ae,_e]=s.useState(!1),[ne,Ge]=s.useState(!1),[ut,We]=s.useState(!1),qe=s.useRef(null),ce=s.useRef({});s.useEffect(()=>{const t=qe.current;if(!t)return;const a=new IntersectionObserver(c=>{var ze;let i=null;for(const ie of c)ie.isIntersecting&&(!i||ie.boundingClientRect.top<i.boundingClientRect.top)&&(i=ie);(ze=i==null?void 0:i.target)!=null&&ze.id&&Te(i.target.id)},{root:t,rootMargin:"-10% 0px -70% 0px",threshold:0});for(const c of le){const i=ce.current[c.id];i&&a.observe(i)}return()=>a.disconnect()},[w]);const Ye=s.useCallback(t=>{Te(t);const a=ce.current[t];a&&a.scrollIntoView({behavior:"smooth",block:"start"})},[]);s.useEffect(()=>{n.getSettings().then(t=>{me(t.anthropicApiKeyConfigured),Ve(t.claudeCodeOAuthTokenConfigured),De(t.openaiApiKeyConfigured),pe(t.anthropicModel||"claude-sonnet-4-6"),typeof t.aiValidationEnabled=="boolean"&&$(t.aiValidationEnabled),typeof t.aiValidationAutoApprove=="boolean"&&H(t.aiValidationAutoApprove),typeof t.aiValidationAutoDeny=="boolean"&&Q(t.aiValidationAutoDeny),typeof t.dashboardEnabled=="boolean"&&G(t.dashboardEnabled),typeof t.dashboardModel=="string"&&t.dashboardModel&&W(t.dashboardModel),typeof t.dashboardRunHour=="number"&&q(t.dashboardRunHour),typeof t.dashboardMaxSessionsPerRun=="number"&&Y(t.dashboardMaxSessionsPerRun),(t.updateChannel==="stable"||t.updateChannel==="prerelease")&&y(t.updateChannel),typeof t.dockerAutoUpdate=="boolean"&&V(t.dockerAutoUpdate),typeof t.proactiveKeepaliveEnabled=="boolean"&&O(t.proactiveKeepaliveEnabled),typeof t.wedgeKillEnabled=="boolean"&&D(t.wedgeKillEnabled),(t.cliBridgeMode==="loopback"||t.cliBridgeMode==="jsonHandoff")&&K(t.cliBridgeMode),typeof t.publicUrl=="string"&&(z(t.publicUrl),o.getState().setPublicUrl(t.publicUrl))}).catch(t=>g(t instanceof Error?t.message:String(t))).finally(()=>Je(!1)),n.getAuthToken().then(t=>He(t.token)).catch(()=>{})},[]);async function xt(t){t.preventDefault(),S(!0),g(""),v(!1);try{const a=p.trim(),c={anthropicModel:xe.trim()||"claude-sonnet-4-6"};a&&(c.anthropicApiKey=a);const i=await n.updateSettings(c);me(i.anthropicApiKeyConfigured),ue(""),v(!0),setTimeout(()=>v(!1),1800)}catch(a){g(a instanceof Error?a.message:String(a))}finally{S(!1)}}async function oe(t){const a=t==="aiValidationEnabled"?T:t==="aiValidationAutoApprove"?F:B,c=!a;t==="aiValidationEnabled"?$(c):t==="aiValidationAutoApprove"?H(c):Q(c);try{await n.updateSettings({[t]:c})}catch{t==="aiValidationEnabled"?$(a):t==="aiValidationAutoApprove"?H(a):Q(a)}}async function pt(){const t=_;G(!t);try{await n.updateSettings({dashboardEnabled:!t})}catch{G(t)}}async function re(t,a){try{await n.updateSettings(t)}catch{a()}}async function mt(){je(!0),j(""),U("");try{const t=await n.forceCheckForUpdate();P(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{je(!1)}}async function ht(){Ne(!0),j(""),U("");try{localStorage.setItem("companion_docker_prompt_pending","1");const t=await n.triggerUpdate();j(t.message),at(!0)}catch(t){localStorage.removeItem("companion_docker_prompt_pending"),U(t instanceof Error?t.message:String(t)),Ne(!1)}}const l=s.useCallback(t=>a=>{ce.current[t]=a},[]);return e.jsxs("div",{className:`${de?"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."})]}),!de&&e.jsx("button",{onClick:()=>{const t=o.getState().currentSessionId;t?ft(t):gt()},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:le.map(t=>e.jsx("button",{type:"button",onClick:()=>Ye(t.id),className:`shrink-0 px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${Ue===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:le.map(t=>e.jsx("button",{type:"button",onClick:()=>Ye(t.id),className:`text-left px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${Ue===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:qe,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:Ze,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:Xe?"Dark":"Light"})]}),e.jsxs("button",{type:"button",onClick:()=>et(fe==="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:fe==="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:ye,onChange:async t=>{const a=t.target.value==="jsonHandoff"?"jsonHandoff":"loopback",c=ye;K(a);try{await n.updateSettings({cliBridgeMode:a})}catch{K(c)}},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,a=A;O(t);try{await n.updateSettings({proactiveKeepaliveEnabled:t})}catch{O(a)}},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("div",{className:"pt-3 border-t border-cc-border",children:[e.jsxs("button",{type:"button",role:"switch","aria-checked":E,"aria-label":"Kill wedged CLI processes",onClick:async()=>{const t=!E,a=E;D(t);try{await n.updateSettings({wedgeKillEnabled:t})}catch{D(a)}},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:"Kill wedged CLI processes"}),e.jsx("span",{className:"text-xs text-cc-muted",children:E?"On":"Off"})]}),e.jsx("p",{className:"mt-1 text-xs text-cc-muted px-1",children:"When on (default), a CLI whose output stream closes but which does not exit is treated as wedged and killed so the session can recover. This was built for older CLI behaviour, and every process sampled since has turned out to be healthy — usually one supervising a background command. Turn off to test whether the wedge still happens at all: sessions still relaunch, but processes are left to exit on their own instead of being terminated."})]})]})]}),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:I,onChange:t=>z(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:I?`Using: ${I}`:`Fallback: ${typeof window<"u"?window.location.origin:"http://localhost:3456"}`})]}),e.jsx("button",{type:"button",onClick:async()=>{S(!0),g("");try{const t=await n.updateSettings({publicUrl:I.trim()});z(t.publicUrl),o.getState().setPublicUrl(t.publicUrl),v(!0),setTimeout(()=>v(!1),1800)}catch(t){g(t instanceof Error?t.message:String(t))}finally{S(!1)}},disabled:f,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:f?"Saving...":be?"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:k?se?k:"••••••••••••••••":e.jsx("span",{className:"text-cc-muted",children:"Loading..."})}),e.jsx("button",{type:"button",onClick:()=>Be(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:se?"Hide token":"Show token",children:se?"Hide":"Show"}),e.jsx("button",{type:"button",onClick:()=>{k&&navigator.clipboard.writeText(k).then(()=>{We(!0),setTimeout(()=>We(!1),1500)})},disabled:!k,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:ut?"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,a)=>e.jsx("button",{type:"button",onClick:()=>dt(a),className:`px-3 py-1.5 rounded-md text-xs font-medium transition-colors cursor-pointer ${a===R?"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[R].qrDataUrl,alt:`QR code for ${u[R].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[R].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()=>{_e(!0);try{const t=await n.getAuthQr();Qe(t.qrCodes)}catch{}finally{_e(!1)}},disabled:ae,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${ae?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:ae?"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.")){Ge(!0);try{const t=await n.regenerateAuthToken();He(t.token),Be(!0),Qe(null)}catch{}finally{Ge(!1)}}},disabled:ne,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${ne?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-error/10 hover:bg-cc-error/20 text-cc-error cursor-pointer"}`,children:ne?"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:st,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:tt?"On":"Off"})]}),nt&&e.jsxs("button",{type:"button",onClick:async()=>{if(ge)ve(!1);else{if(Notification.permission!=="granted"&&await Notification.requestPermission()!=="granted")return;ve(!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:ge?"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:X&&!it&&!h?"••••••••••••••••":h,onChange:t=>Pe(t.target.value),onFocus:()=>$e(!0),onBlur:()=>$e(!1),placeholder:X?"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:X?"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:Z&&!lt&&!b?"••••••••••••••••":b,onChange:t=>Oe(t.target.value),onFocus:()=>Fe(!0),onBlur:()=>Fe(!1),placeholder:Z?"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:Z?"OpenAI key configured":"OpenAI key not configured"})]}),Me&&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:Me}),rt&&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:ee||!h.trim()&&!b.trim(),onClick:async()=>{Ke(!0),Le(""),te(!1);try{const t={};h.trim()&&(t.claudeCodeOAuthToken=h.trim()),b.trim()&&(t.openaiApiKey=b.trim());const a=await n.updateSettings(t);Ve(a.claudeCodeOAuthTokenConfigured),De(a.openaiApiKeyConfigured),Pe(""),Oe(""),te(!0),setTimeout(()=>te(!1),1800)}catch(t){Le(t instanceof Error?t.message:String(t))}finally{Ke(!1)}},className:`px-4 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${ee||!h.trim()&&!b.trim()?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:ee?"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:xt,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&&!ot&&!p?"••••••••••••••••":p,onChange:t=>{ue(t.target.value),m(null)},onFocus:()=>Ie(!0),onBlur:()=>Ie(!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:xe,onChange:t=>pe(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"})]}),he&&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:he}),be&&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:J||!p.trim(),onClick:async()=>{Re(!0),m(null);try{const t=await n.verifyAnthropicKey(p.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{Re(!1)}},className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${J||!p.trim()?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:J?"Verifying...":"Verify"}),e.jsx("button",{type:"submit",disabled:f||w,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${f||w?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:f?"Saving...":"Save"})]})]}),N&&e.jsx("div",{className:`px-3 py-2 rounded-lg text-xs ${N.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:N.valid?"API key is valid.":`Invalid API key${N.error?`: ${N.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:()=>oe("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:()=>oe("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 ${F?"text-cc-success":"text-cc-muted"}`,children:F?"On":"Off"})]}),e.jsxs("button",{type:"button",onClick:()=>oe("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 ${B?"text-cc-success":"text-cc-muted"}`,children:B?"On":"Off"})]})]})]})]}),e.jsxs("section",{id:"dashboard",ref:l("dashboard"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Project Dashboard"}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("p",{className:"text-xs text-cc-muted leading-relaxed",children:["A nightly job summarizes every session with recent activity so the"," ",e.jsx("a",{href:"#/dashboard",className:"underline hover:no-underline",children:"dashboard"})," ",'can show where each project stands. It runs through the Claude Code CLI with the same login your normal sessions use — no separate API key needed. This is opt-in because it spends tokens every night. You can always refresh manually with "Update now" on the dashboard, even when the nightly run is off.']}),e.jsxs("button",{type:"button",onClick:pt,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.jsx("span",{className:"text-sm",children:"Nightly dashboard updates"}),e.jsx("span",{className:`text-xs font-medium ${_?"text-cc-success":"text-cc-muted"}`,children:_?"On":"Off"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",htmlFor:"dashboard-model",children:"Summarization model"}),e.jsxs("select",{id:"dashboard-model",value:Ce,onChange:t=>{const a=Ce;W(t.target.value),re({dashboardModel:t.target.value},()=>W(a))},className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg focus:outline-none focus:ring-1 focus:ring-cc-primary/40 transition-shadow",children:[e.jsx("option",{value:"claude-haiku-4-5",children:"Claude Haiku 4.5 — cheapest, recommended"}),e.jsx("option",{value:"claude-sonnet-4-6",children:"Claude Sonnet 4.6"}),e.jsx("option",{value:"claude-sonnet-5",children:"Claude Sonnet 5"})]}),e.jsx("p",{className:"mt-1.5 text-xs text-cc-muted",children:"Summarize-and-classify doesn't need an expensive model — Haiku keeps the nightly cost low."})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",htmlFor:"dashboard-run-hour",children:"Run at"}),e.jsx("select",{id:"dashboard-run-hour",value:Ae,onChange:t=>{const a=Ae,c=Number(t.target.value);q(c),re({dashboardRunHour:c},()=>q(a))},className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg focus:outline-none focus:ring-1 focus:ring-cc-primary/40 transition-shadow",children:Array.from({length:24},(t,a)=>e.jsxs("option",{value:a,children:[String(a).padStart(2,"0"),":00"]},a))})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",htmlFor:"dashboard-max-sessions",children:"Max sessions per run"}),e.jsx("select",{id:"dashboard-max-sessions",value:Ee,onChange:t=>{const a=Ee,c=Number(t.target.value);Y(c),re({dashboardMaxSessionsPerRun:c},()=>Y(a))},className:"w-full px-3 py-2.5 min-h-[44px] text-sm bg-cc-bg rounded-lg text-cc-fg focus:outline-none focus:ring-1 focus:ring-cc-primary/40 transition-shadow",children:[10,20,30,50,100,200].map(t=>e.jsx("option",{value:t,children:t},t))})]})]})]})]}),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:[r?e.jsxs("p",{className:"text-xs text-cc-muted",children:["Current version: v",r.currentVersion,r.latestVersion?` • Latest: v${r.latestVersion}`:"",r.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":x==="stable",onClick:async()=>{if(x!=="stable"){y("stable");try{await n.updateSettings({updateChannel:"stable"})}catch{y("prerelease");return}try{const t=await n.forceCheckForUpdate();P(t)}catch{}}},className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${x==="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":x==="prerelease",onClick:async()=>{if(x!=="prerelease"){y("prerelease");try{await n.updateSettings({updateChannel:"prerelease"})}catch{y("stable");return}try{const t=await n.forceCheckForUpdate();P(t)}catch{}}},className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${x==="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:x==="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":C,onClick:async()=>{const t=!C;V(t);try{await n.updateSettings({dockerAutoUpdate:t})}catch{V(!t)}},className:`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${C?"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 ${C?"translate-x-5":"translate-x-0"}`})})]}),we&&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:we}),ke&&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:ke}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:mt,disabled:M,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${M?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:M?"Checking...":"Check for updates"}),r!=null&&r.isServiceMode?e.jsx("button",{type:"button",onClick:ht,disabled:L||r.updateInProgress||!r.updateAvailable,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${L||r.updateInProgress||!r.updateAvailable?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:L||r.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=!Se;vt(t),ct(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:Se?"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{jt as SettingsPage};
|