@hellcoder/companion 0.119.1 → 0.120.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.
Files changed (34) hide show
  1. package/dist/assets/{AgentsPage-E73zA-6k.js → AgentsPage-V7NBPNSh.js} +5 -5
  2. package/dist/assets/CronManager-CGfXlVZS.js +1 -0
  3. package/dist/assets/{DashboardPage-Dk4z826H.js → DashboardPage-N7MWZiJQ.js} +1 -1
  4. package/dist/assets/{IntegrationsPage-C7cQyPBt.js → IntegrationsPage-DRP477b0.js} +1 -1
  5. package/dist/assets/{LinearOAuthSettingsPage-BG4-JYjD.js → LinearOAuthSettingsPage-CPW4TQuD.js} +1 -1
  6. package/dist/assets/{LinearSettingsPage-CBbKNZVH.js → LinearSettingsPage-BwVTEKqs.js} +1 -1
  7. package/dist/assets/{MagicUIDashboard-DpxmzOIx.js → MagicUIDashboard-exuRY5LQ.js} +1 -1
  8. package/dist/assets/MagicUIView-AKoy6jOb.js +1 -0
  9. package/dist/assets/{Playground-BdB18EpN.js → Playground-BiEa7THU.js} +1 -1
  10. package/dist/assets/{PromptsPage-C7vU_XHW.js → PromptsPage-BYtZdliB.js} +1 -1
  11. package/dist/assets/{RunsPage-BsIYybEZ.js → RunsPage-DD6KPNKm.js} +1 -1
  12. package/dist/assets/{SandboxManager-DKcCgC-r.js → SandboxManager-C8tBjBXY.js} +1 -1
  13. package/dist/assets/SettingsPage-77tDzDuD.js +1 -0
  14. package/dist/assets/{TailscalePage-BhGXhs0h.js → TailscalePage-B0TbcOPL.js} +1 -1
  15. package/dist/assets/{index-C0oFg9YU.js → index-BM8QkiV8.js} +58 -58
  16. package/dist/assets/{sw-register-CWqt9RnE.js → sw-register-Cr16zatT.js} +1 -1
  17. package/dist/index.html +1 -1
  18. package/dist/sw.js +1 -1
  19. package/package.json +1 -1
  20. package/server/codex-app-server.ts +61 -0
  21. package/server/codex-auth.test.ts +254 -0
  22. package/server/codex-auth.ts +315 -0
  23. package/server/codex-models.ts +2 -43
  24. package/server/protocol/codex-upstream/ClientRequest.ts.txt +62 -17
  25. package/server/protocol/codex-upstream/README.md +1 -1
  26. package/server/protocol/codex-upstream/ServerNotification.ts.txt +52 -4
  27. package/server/protocol/codex-upstream/ServerRequest.ts.txt +4 -1
  28. package/server/protocol/codex-upstream/v2/DynamicToolCallParams.ts.txt +1 -1
  29. package/server/routes/codex-auth-routes.test.ts +115 -0
  30. package/server/routes/codex-auth-routes.ts +49 -0
  31. package/server/routes.ts +2 -0
  32. package/dist/assets/CronManager-Dbz9rad2.js +0 -1
  33. package/dist/assets/MagicUIView-wrboravS.js +0 -1
  34. package/dist/assets/SettingsPage-BIvJyPOd.js +0 -1
@@ -1,41 +1,89 @@
1
1
  // GENERATED CODE! DO NOT MODIFY BY HAND!
2
2
 
3
3
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
4
- import type { AuthStatusChangeNotification } from "./AuthStatusChangeNotification";
4
+ import type { FuzzyFileSearchSessionCompletedNotification } from "./FuzzyFileSearchSessionCompletedNotification";
5
5
  import type { FuzzyFileSearchSessionUpdatedNotification } from "./FuzzyFileSearchSessionUpdatedNotification";
6
- import type { LoginChatGptCompleteNotification } from "./LoginChatGptCompleteNotification";
7
- import type { SessionConfiguredNotification } from "./SessionConfiguredNotification";
8
6
  import type { AccountLoginCompletedNotification } from "./v2/AccountLoginCompletedNotification";
9
7
  import type { AccountRateLimitsUpdatedNotification } from "./v2/AccountRateLimitsUpdatedNotification";
10
8
  import type { AccountUpdatedNotification } from "./v2/AccountUpdatedNotification";
11
9
  import type { AgentMessageDeltaNotification } from "./v2/AgentMessageDeltaNotification";
12
10
  import type { AppListUpdatedNotification } from "./v2/AppListUpdatedNotification";
11
+ import type { AuthRecoveryNotification } from "./v2/AuthRecoveryNotification";
12
+ import type { CommandExecOutputDeltaNotification } from "./v2/CommandExecOutputDeltaNotification";
13
13
  import type { CommandExecutionOutputDeltaNotification } from "./v2/CommandExecutionOutputDeltaNotification";
14
14
  import type { ConfigWarningNotification } from "./v2/ConfigWarningNotification";
15
15
  import type { ContextCompactedNotification } from "./v2/ContextCompactedNotification";
16
16
  import type { DeprecationNoticeNotification } from "./v2/DeprecationNoticeNotification";
17
+ import type { EnvironmentConnectionNotification } from "./v2/EnvironmentConnectionNotification";
17
18
  import type { ErrorNotification } from "./v2/ErrorNotification";
19
+ import type { ExternalAgentConfigImportCompletedNotification } from "./v2/ExternalAgentConfigImportCompletedNotification";
20
+ import type { ExternalAgentConfigImportProgressNotification } from "./v2/ExternalAgentConfigImportProgressNotification";
18
21
  import type { FileChangeOutputDeltaNotification } from "./v2/FileChangeOutputDeltaNotification";
22
+ import type { FileChangePatchUpdatedNotification } from "./v2/FileChangePatchUpdatedNotification";
23
+ import type { FsChangedNotification } from "./v2/FsChangedNotification";
24
+ import type { GuardianWarningNotification } from "./v2/GuardianWarningNotification";
25
+ import type { HookCompletedNotification } from "./v2/HookCompletedNotification";
26
+ import type { HookStartedNotification } from "./v2/HookStartedNotification";
19
27
  import type { ItemCompletedNotification } from "./v2/ItemCompletedNotification";
28
+ import type { ItemGuardianApprovalReviewCompletedNotification } from "./v2/ItemGuardianApprovalReviewCompletedNotification";
29
+ import type { ItemGuardianApprovalReviewStartedNotification } from "./v2/ItemGuardianApprovalReviewStartedNotification";
20
30
  import type { ItemStartedNotification } from "./v2/ItemStartedNotification";
31
+ import type { McpServerEventStreamNotification } from "./v2/McpServerEventStreamNotification";
21
32
  import type { McpServerOauthLoginCompletedNotification } from "./v2/McpServerOauthLoginCompletedNotification";
33
+ import type { McpServerStatusUpdatedNotification } from "./v2/McpServerStatusUpdatedNotification";
22
34
  import type { McpToolCallProgressNotification } from "./v2/McpToolCallProgressNotification";
35
+ import type { ModelReroutedNotification } from "./v2/ModelReroutedNotification";
36
+ import type { ModelSafetyBufferingUpdatedNotification } from "./v2/ModelSafetyBufferingUpdatedNotification";
37
+ import type { ModelVerificationNotification } from "./v2/ModelVerificationNotification";
23
38
  import type { PlanDeltaNotification } from "./v2/PlanDeltaNotification";
39
+ import type { ProcessExitedNotification } from "./v2/ProcessExitedNotification";
40
+ import type { ProcessOutputDeltaNotification } from "./v2/ProcessOutputDeltaNotification";
41
+ import type { ProjectChangedNotification } from "./v2/ProjectChangedNotification";
42
+ import type { RawResponseCompletedNotification } from "./v2/RawResponseCompletedNotification";
24
43
  import type { RawResponseItemCompletedNotification } from "./v2/RawResponseItemCompletedNotification";
25
44
  import type { ReasoningSummaryPartAddedNotification } from "./v2/ReasoningSummaryPartAddedNotification";
26
45
  import type { ReasoningSummaryTextDeltaNotification } from "./v2/ReasoningSummaryTextDeltaNotification";
27
46
  import type { ReasoningTextDeltaNotification } from "./v2/ReasoningTextDeltaNotification";
47
+ import type { RemoteControlStatusChangedNotification } from "./v2/RemoteControlStatusChangedNotification";
48
+ import type { ServerRequestResolvedNotification } from "./v2/ServerRequestResolvedNotification";
49
+ import type { SkillsChangedNotification } from "./v2/SkillsChangedNotification";
50
+ import type { StrictReviewRequiredNotification } from "./v2/StrictReviewRequiredNotification";
28
51
  import type { TerminalInteractionNotification } from "./v2/TerminalInteractionNotification";
52
+ import type { ThreadArchivedNotification } from "./v2/ThreadArchivedNotification";
53
+ import type { ThreadClosedNotification } from "./v2/ThreadClosedNotification";
54
+ import type { ThreadDeletedNotification } from "./v2/ThreadDeletedNotification";
55
+ import type { ThreadGoalClearedNotification } from "./v2/ThreadGoalClearedNotification";
56
+ import type { ThreadGoalUpdatedNotification } from "./v2/ThreadGoalUpdatedNotification";
29
57
  import type { ThreadNameUpdatedNotification } from "./v2/ThreadNameUpdatedNotification";
58
+ import type { ThreadProjectUpdatedNotification } from "./v2/ThreadProjectUpdatedNotification";
59
+ import type { ThreadQueueChangedNotification } from "./v2/ThreadQueueChangedNotification";
60
+ import type { ThreadRealtimeClosedNotification } from "./v2/ThreadRealtimeClosedNotification";
61
+ import type { ThreadRealtimeErrorNotification } from "./v2/ThreadRealtimeErrorNotification";
62
+ import type { ThreadRealtimeItemAddedNotification } from "./v2/ThreadRealtimeItemAddedNotification";
63
+ import type { ThreadRealtimeItemCompletedNotification } from "./v2/ThreadRealtimeItemCompletedNotification";
64
+ import type { ThreadRealtimeItemStartedNotification } from "./v2/ThreadRealtimeItemStartedNotification";
65
+ import type { ThreadRealtimeItemTranscriptDeltaNotification } from "./v2/ThreadRealtimeItemTranscriptDeltaNotification";
66
+ import type { ThreadRealtimeOutputAudioDeltaNotification } from "./v2/ThreadRealtimeOutputAudioDeltaNotification";
67
+ import type { ThreadRealtimeSdpNotification } from "./v2/ThreadRealtimeSdpNotification";
68
+ import type { ThreadRealtimeStartedNotification } from "./v2/ThreadRealtimeStartedNotification";
69
+ import type { ThreadRealtimeTranscriptDeltaNotification } from "./v2/ThreadRealtimeTranscriptDeltaNotification";
70
+ import type { ThreadRealtimeTranscriptDoneNotification } from "./v2/ThreadRealtimeTranscriptDoneNotification";
71
+ import type { ThreadRevertedNotification } from "./v2/ThreadRevertedNotification";
72
+ import type { ThreadSettingsUpdatedNotification } from "./v2/ThreadSettingsUpdatedNotification";
30
73
  import type { ThreadStartedNotification } from "./v2/ThreadStartedNotification";
74
+ import type { ThreadStatusChangedNotification } from "./v2/ThreadStatusChangedNotification";
31
75
  import type { ThreadTokenUsageUpdatedNotification } from "./v2/ThreadTokenUsageUpdatedNotification";
76
+ import type { ThreadUnarchivedNotification } from "./v2/ThreadUnarchivedNotification";
32
77
  import type { TurnCompletedNotification } from "./v2/TurnCompletedNotification";
33
78
  import type { TurnDiffUpdatedNotification } from "./v2/TurnDiffUpdatedNotification";
79
+ import type { TurnModerationMetadataNotification } from "./v2/TurnModerationMetadataNotification";
34
80
  import type { TurnPlanUpdatedNotification } from "./v2/TurnPlanUpdatedNotification";
35
81
  import type { TurnStartedNotification } from "./v2/TurnStartedNotification";
82
+ import type { WarningNotification } from "./v2/WarningNotification";
83
+ import type { WindowsSandboxSetupCompletedNotification } from "./v2/WindowsSandboxSetupCompletedNotification";
36
84
  import type { WindowsWorldWritableWarningNotification } from "./v2/WindowsWorldWritableWarningNotification";
37
85
 
38
86
  /**
39
87
  * Notification sent from the server to the client.
40
88
  */
41
- export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification } | { "method": "authStatusChange", "params": AuthStatusChangeNotification } | { "method": "loginChatGptComplete", "params": LoginChatGptCompleteNotification } | { "method": "sessionConfigured", "params": SessionConfiguredNotification };
89
+ export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/deleted", "params": ThreadDeletedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "thread/reverted", "params": ThreadRevertedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/goal/updated", "params": ThreadGoalUpdatedNotification } | { "method": "thread/goal/cleared", "params": ThreadGoalClearedNotification } | { "method": "thread/queue/changed", "params": ThreadQueueChangedNotification } | { "method": "project/changed", "params": ProjectChangedNotification } | { "method": "thread/project/updated", "params": ThreadProjectUpdatedNotification } | { "method": "thread/environment/connected", "params": EnvironmentConnectionNotification } | { "method": "thread/environment/disconnected", "params": EnvironmentConnectionNotification } | { "method": "thread/settings/updated", "params": ThreadSettingsUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "autoApprovalReview/strictReviewRequired", "params": StrictReviewRequiredNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "rawResponse/completed", "params": RawResponseCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "process/outputDelta", "params": ProcessOutputDeltaNotification } | { "method": "process/exited", "params": ProcessExitedNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/fileChange/patchUpdated", "params": FileChangePatchUpdatedNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "mcpServer/startupStatus/updated", "params": McpServerStatusUpdatedNotification } | { "method": "mcpServer/event/stream/notification", "params": McpServerEventStreamNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "remoteControl/status/changed", "params": RemoteControlStatusChangedNotification } | { "method": "externalAgentConfig/import/progress", "params": ExternalAgentConfigImportProgressNotification } | { "method": "externalAgentConfig/import/completed", "params": ExternalAgentConfigImportCompletedNotification } | { "method": "fs/changed", "params": FsChangedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "model/verification", "params": ModelVerificationNotification } | { "method": "modelProvider/authRecoveryStarted", "params": AuthRecoveryNotification } | { "method": "modelProvider/authRecoveryCompleted", "params": AuthRecoveryNotification } | { "method": "turn/moderationMetadata", "params": TurnModerationMetadataNotification } | { "method": "model/safetyBuffering/updated", "params": ModelSafetyBufferingUpdatedNotification } | { "method": "warning", "params": WarningNotification } | { "method": "guardianWarning", "params": GuardianWarningNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/item/started", "params": ThreadRealtimeItemStartedNotification } | { "method": "thread/realtime/item/transcript/delta", "params": ThreadRealtimeItemTranscriptDeltaNotification } | { "method": "thread/realtime/item/completed", "params": ThreadRealtimeItemCompletedNotification } | { "method": "thread/realtime/transcript/delta", "params": ThreadRealtimeTranscriptDeltaNotification } | { "method": "thread/realtime/transcript/done", "params": ThreadRealtimeTranscriptDoneNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/sdp", "params": ThreadRealtimeSdpNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification };
@@ -4,13 +4,16 @@
4
4
  import type { ApplyPatchApprovalParams } from "./ApplyPatchApprovalParams";
5
5
  import type { ExecCommandApprovalParams } from "./ExecCommandApprovalParams";
6
6
  import type { RequestId } from "./RequestId";
7
+ import type { AttestationGenerateParams } from "./v2/AttestationGenerateParams";
7
8
  import type { ChatgptAuthTokensRefreshParams } from "./v2/ChatgptAuthTokensRefreshParams";
8
9
  import type { CommandExecutionRequestApprovalParams } from "./v2/CommandExecutionRequestApprovalParams";
9
10
  import type { DynamicToolCallParams } from "./v2/DynamicToolCallParams";
10
11
  import type { FileChangeRequestApprovalParams } from "./v2/FileChangeRequestApprovalParams";
12
+ import type { McpServerElicitationRequestParams } from "./v2/McpServerElicitationRequestParams";
13
+ import type { PermissionsRequestApprovalParams } from "./v2/PermissionsRequestApprovalParams";
11
14
  import type { ToolRequestUserInputParams } from "./v2/ToolRequestUserInputParams";
12
15
 
13
16
  /**
14
17
  * Request initiated from the server and sent to the client.
15
18
  */
16
- export type ServerRequest = { "method": "item/commandExecution/requestApproval", id: RequestId, params: CommandExecutionRequestApprovalParams, } | { "method": "item/fileChange/requestApproval", id: RequestId, params: FileChangeRequestApprovalParams, } | { "method": "item/tool/requestUserInput", id: RequestId, params: ToolRequestUserInputParams, } | { "method": "item/tool/call", id: RequestId, params: DynamicToolCallParams, } | { "method": "account/chatgptAuthTokens/refresh", id: RequestId, params: ChatgptAuthTokensRefreshParams, } | { "method": "applyPatchApproval", id: RequestId, params: ApplyPatchApprovalParams, } | { "method": "execCommandApproval", id: RequestId, params: ExecCommandApprovalParams, };
19
+ export type ServerRequest ={ "method": "item/commandExecution/requestApproval", id: RequestId, params: CommandExecutionRequestApprovalParams, } | { "method": "item/fileChange/requestApproval", id: RequestId, params: FileChangeRequestApprovalParams, } | { "method": "item/tool/requestUserInput", id: RequestId, params: ToolRequestUserInputParams, } | { "method": "mcpServer/elicitation/request", id: RequestId, params: McpServerElicitationRequestParams, } | { "method": "item/permissions/requestApproval", id: RequestId, params: PermissionsRequestApprovalParams, } | { "method": "item/tool/call", id: RequestId, params: DynamicToolCallParams, } | { "method": "account/chatgptAuthTokens/refresh", id: RequestId, params: ChatgptAuthTokensRefreshParams, } | { "method": "attestation/generate", id: RequestId, params: AttestationGenerateParams, } | { "method": "applyPatchApproval", id: RequestId, params: ApplyPatchApprovalParams, } | { "method": "execCommandApproval", id: RequestId, params: ExecCommandApprovalParams, };
@@ -3,4 +3,4 @@
3
3
  // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
4
4
  import type { JsonValue } from "../serde_json/JsonValue";
5
5
 
6
- export type DynamicToolCallParams = { threadId: string, turnId: string, callId: string, tool: string, arguments: JsonValue, };
6
+ export type DynamicToolCallParams = { threadId: string, turnId: string, callId: string, namespace: string | null, tool: string, arguments: JsonValue, };
@@ -0,0 +1,115 @@
1
+ import { vi, describe, it, expect, beforeEach } from "vitest";
2
+
3
+ vi.mock("../codex-auth.js", () => ({
4
+ getAccountStatus: vi.fn(),
5
+ getLoginStatus: vi.fn(),
6
+ startDeviceLogin: vi.fn(),
7
+ cancelLogin: vi.fn(),
8
+ logout: vi.fn(),
9
+ }));
10
+
11
+ import { Hono } from "hono";
12
+ import {
13
+ getAccountStatus, getLoginStatus, startDeviceLogin, cancelLogin, logout,
14
+ } from "../codex-auth.js";
15
+ import { registerCodexAuthRoutes } from "./codex-auth-routes.js";
16
+
17
+ const mockAccount = vi.mocked(getAccountStatus);
18
+ const mockLoginStatus = vi.mocked(getLoginStatus);
19
+ const mockStart = vi.mocked(startDeviceLogin);
20
+ const mockCancel = vi.mocked(cancelLogin);
21
+ const mockLogout = vi.mocked(logout);
22
+
23
+ function createApp() {
24
+ const api = new Hono();
25
+ registerCodexAuthRoutes(api);
26
+ return api;
27
+ }
28
+
29
+ beforeEach(() => {
30
+ vi.clearAllMocks();
31
+ });
32
+
33
+ describe("GET /codex/auth/account", () => {
34
+ it("returns the current account status", async () => {
35
+ const status = {
36
+ cliAvailable: true, authenticated: true, method: "chatgpt" as const,
37
+ email: "user@example.com", planType: "pro",
38
+ };
39
+ mockAccount.mockResolvedValue(status);
40
+
41
+ const res = await createApp().request("/codex/auth/account");
42
+
43
+ expect(res.status).toBe(200);
44
+ expect(await res.json()).toEqual(status);
45
+ });
46
+ });
47
+
48
+ describe("GET /codex/auth/login", () => {
49
+ it("returns the pending login status for the client to poll", async () => {
50
+ const status = {
51
+ state: "pending" as const,
52
+ userCode: "ABCD-1234",
53
+ verificationUrl: "https://auth.openai.com/codex/device",
54
+ };
55
+ mockLoginStatus.mockReturnValue(status);
56
+
57
+ const res = await createApp().request("/codex/auth/login");
58
+
59
+ expect(await res.json()).toEqual(status);
60
+ });
61
+ });
62
+
63
+ describe("POST /codex/auth/login", () => {
64
+ it("starts a device login and returns the user code", async () => {
65
+ mockStart.mockResolvedValue({
66
+ state: "pending", userCode: "ABCD-1234",
67
+ verificationUrl: "https://auth.openai.com/codex/device",
68
+ });
69
+
70
+ const res = await createApp().request("/codex/auth/login", { method: "POST" });
71
+
72
+ expect(res.status).toBe(200);
73
+ expect(await res.json()).toMatchObject({ state: "pending", userCode: "ABCD-1234" });
74
+ });
75
+
76
+ it("returns 200 with an error field when starting fails, so the client keeps the detail", async () => {
77
+ // The frontend post() helper throws away the body on non-2xx, so structured
78
+ // failures are deliberately reported as 200 (same convention as tailscale).
79
+ mockStart.mockRejectedValue(new Error("Codex CLI not found on PATH"));
80
+
81
+ const res = await createApp().request("/codex/auth/login", { method: "POST" });
82
+
83
+ expect(res.status).toBe(200);
84
+ expect(await res.json()).toEqual({ state: "error", error: "Codex CLI not found on PATH" });
85
+ });
86
+ });
87
+
88
+ describe("POST /codex/auth/login/cancel", () => {
89
+ it("cancels the in-flight login", async () => {
90
+ mockCancel.mockResolvedValue({ state: "canceled" });
91
+
92
+ const res = await createApp().request("/codex/auth/login/cancel", { method: "POST" });
93
+
94
+ expect(await res.json()).toEqual({ state: "canceled" });
95
+ expect(mockCancel).toHaveBeenCalled();
96
+ });
97
+ });
98
+
99
+ describe("POST /codex/auth/logout", () => {
100
+ it("signs the account out", async () => {
101
+ mockLogout.mockResolvedValue({ ok: true });
102
+
103
+ const res = await createApp().request("/codex/auth/logout", { method: "POST" });
104
+
105
+ expect(await res.json()).toEqual({ ok: true });
106
+ });
107
+
108
+ it("passes through a logout failure reason", async () => {
109
+ mockLogout.mockResolvedValue({ ok: false, error: "boom" });
110
+
111
+ const res = await createApp().request("/codex/auth/logout", { method: "POST" });
112
+
113
+ expect(await res.json()).toEqual({ ok: false, error: "boom" });
114
+ });
115
+ });
@@ -0,0 +1,49 @@
1
+ import type { Hono } from "hono";
2
+ import {
3
+ cancelLogin,
4
+ getAccountStatus,
5
+ getLoginStatus,
6
+ logout,
7
+ startDeviceLogin,
8
+ } from "../codex-auth.js";
9
+
10
+ /**
11
+ * Codex ChatGPT-subscription auth, driven from Settings instead of an SSH
12
+ * session. The login is a device-code flow: POST /start returns a user code and
13
+ * a verification URL, the client polls GET /login until it resolves.
14
+ *
15
+ * Following the tailscale-routes convention, failures that carry useful
16
+ * structure are returned as 200 with an `error` field rather than a non-2xx
17
+ * status, so the frontend `post()` helper doesn't throw the detail away.
18
+ */
19
+ export function registerCodexAuthRoutes(api: Hono): void {
20
+ // Current account (spawns a short-lived app-server to ask Codex directly).
21
+ api.get("/codex/auth/account", async (c) => {
22
+ return c.json(await getAccountStatus());
23
+ });
24
+
25
+ // Poll target for an in-flight (or just-finished) login.
26
+ api.get("/codex/auth/login", (c) => {
27
+ return c.json(getLoginStatus());
28
+ });
29
+
30
+ // Begin a device-code login. Idempotent while one is in flight.
31
+ api.post("/codex/auth/login", async (c) => {
32
+ try {
33
+ return c.json(await startDeviceLogin());
34
+ } catch (e) {
35
+ return c.json({
36
+ state: "error" as const,
37
+ error: e instanceof Error ? e.message : String(e),
38
+ });
39
+ }
40
+ });
41
+
42
+ api.post("/codex/auth/login/cancel", async (c) => {
43
+ return c.json(await cancelLogin());
44
+ });
45
+
46
+ api.post("/codex/auth/logout", async (c) => {
47
+ return c.json(await logout());
48
+ });
49
+ }
package/server/routes.ts CHANGED
@@ -36,6 +36,7 @@ import { registerLinearRoutes, fetchLinearTeamStates } from "./routes/linear-rou
36
36
  import { registerLinearConnectionRoutes } from "./routes/linear-connection-routes.js";
37
37
  import { getConnection, resolveApiKey } from "./linear-connections.js";
38
38
  import { registerLinearOAuthConnectionRoutes } from "./routes/linear-oauth-connection-routes.js";
39
+ import { registerCodexAuthRoutes } from "./routes/codex-auth-routes.js";
39
40
  import { getSettings } from "./settings-manager.js";
40
41
  import { discoverClaudeSessions } from "./claude-session-discovery.js";
41
42
  import { getClaudeSessionHistoryPage } from "./claude-session-history.js";
@@ -1276,6 +1277,7 @@ export function createRoutes(
1276
1277
 
1277
1278
  registerPromptRoutes(api);
1278
1279
  registerSettingsRoutes(api);
1280
+ registerCodexAuthRoutes(api);
1279
1281
  registerDashboardRoutes(api, {
1280
1282
  listCompanionSessions: () => launcher.listSessions(),
1281
1283
  });
@@ -1 +0,0 @@
1
- import{r as a,a as j,j as e,t as z,H as _,I as B,J as K,K as U,F as Y}from"./index-C0oFg9YU.js";function W(s,p,c=!0){a.useEffect(()=>{if(!c)return;function d(o){s.some(m=>m.current&&m.current.contains(o.target))||p()}return document.addEventListener("pointerdown",d),()=>document.removeEventListener("pointerdown",d)},[s,p,c])}function J(s){const p=s-Date.now();if(p<=0)return"now";const c=Math.floor(p/6e4);if(c<60)return`in ${c}m`;const d=Math.floor(c/60);return d<24?`in ${d}h`:`in ${Math.floor(d/24)}d`}function F(s,p){if(!p)return"One-time";const c=s.trim().split(/\s+/);if(c.length!==5)return s;const[d,o,g,m,x]=c;if(s==="* * * * *")return"Every minute";if(o==="*"&&g==="*"&&m==="*"&&x==="*"&&d.startsWith("*/")){const l=parseInt(d.slice(2),10);return l===1?"Every minute":`Every ${l} minutes`}if(d==="0"&&g==="*"&&m==="*"&&x==="*"){if(o==="*")return"Every hour";if(o.startsWith("*/")){const l=parseInt(o.slice(2),10);return l===1?"Every hour":`Every ${l} hours`}}if(g==="*"&&m==="*"&&d!=="*"&&o!=="*"&&!o.includes("/")&&!o.includes(",")){const l=parseInt(o,10),y=parseInt(d,10);if(!isNaN(l)&&!isNaN(y)){const u=l>=12?"PM":"AM",w=l===0?12:l>12?l-12:l,r=y.toString().padStart(2,"0"),v=`${w}:${r} ${u}`;if(x==="*")return`Every day at ${v}`;if(x==="1-5")return`Weekdays at ${v}`;if(x==="0,6")return`Weekends at ${v}`}}return s}const $={name:"",prompt:"",recurring:!0,schedule:"0 8 * * *",oneTimeDate:"",backendType:"claude",model:B("claude"),cwd:""},q=[{label:"Every hour",value:"0 * * * *"},{label:"Every day at 8am",value:"0 8 * * *"},{label:"Every 2 hours",value:"0 */2 * * *"},{label:"Weekdays at 9am",value:"0 9 * * 1-5"}];function X({onClose:s,embedded:p=!1}){const[c,d]=a.useState([]),[o,g]=a.useState(!0),[m,x]=a.useState(""),[l,y]=a.useState(null),[u,w]=a.useState($),[r,v]=a.useState($),[h,M]=a.useState(!1),[f,S]=a.useState(!1),[k,E]=a.useState(new Set),n=a.useCallback(()=>{j.listCronJobs().then(d).catch(()=>{}).finally(()=>g(!1))},[]);a.useEffect(()=>{n();const t=setInterval(n,1e4);return()=>clearInterval(t)},[n]);async function C(){const t=r.name.trim(),i=r.prompt.trim();if(!t||!i)return;M(!0),x("");let N=r.schedule;!r.recurring&&r.oneTimeDate&&(N=new Date(r.oneTimeDate).toISOString());try{await j.createCronJob({name:t,prompt:i,schedule:N,recurring:r.recurring,backendType:r.backendType,model:r.model.trim()||void 0,cwd:r.cwd.trim()||void 0}),v($),S(!1),n()}catch(b){x(b instanceof Error?b.message:String(b))}finally{M(!1)}}function R(t){y(t.id),w({name:t.name,prompt:t.prompt,recurring:t.recurring,schedule:t.schedule,oneTimeDate:"",backendType:t.backendType,model:t.model,cwd:t.cwd}),x("")}function D(){y(null),x("")}async function L(){if(!l)return;const t=u.name.trim(),i=u.prompt.trim();if(!t||!i)return;let N=u.schedule;!u.recurring&&u.oneTimeDate&&(N=new Date(u.oneTimeDate).toISOString());try{await j.updateCronJob(l,{name:t,prompt:i,schedule:N,recurring:u.recurring,backendType:u.backendType,model:u.model.trim()||void 0,cwd:u.cwd.trim()||void 0}),y(null),x(""),n()}catch(b){x(b instanceof Error?b.message:String(b))}}async function A(t){try{await j.deleteCronJob(t),l===t&&y(null),n()}catch(i){x(i instanceof Error?i.message:String(i))}}async function I(t){try{await j.toggleCronJob(t),n()}catch(i){x(i instanceof Error?i.message:String(i))}}async function P(t){E(i=>new Set(i).add(t));try{await j.runCronJob(t),n()}catch(i){x(i instanceof Error?i.message:String(i))}finally{E(i=>{const N=new Set(i);return N.delete(t),N})}}if(p)return e.jsx("div",{className:"h-full bg-cc-bg text-cc-fg font-sans-ui antialiased overflow-y-auto",children:e.jsxs("div",{className:"max-w-2xl mx-auto px-4 sm:px-6 py-6 sm:py-10 pb-safe",children:[e.jsx("div",{className:"flex items-start justify-between gap-3 mb-2",children:e.jsxs("div",{className:"min-w-0",children:[e.jsx("h1",{className:"text-lg font-semibold text-cc-fg",children:"Scheduled Tasks"}),e.jsx("p",{className:"mt-0.5 text-[13px] text-cc-muted leading-relaxed",children:"Run autonomous Claude Code or Codex sessions on a schedule."})]})}),e.jsxs("div",{className:"flex items-center gap-2 mt-4 mb-5",children:[e.jsx("div",{className:"flex-1"}),e.jsxs("button",{onClick:()=>S(!f),className:`flex items-center gap-1.5 px-3.5 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer shrink-0 ${f?"bg-cc-active text-cc-fg":"bg-cc-primary hover:bg-cc-primary-hover text-white"}`,children:[e.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"w-4 h-4",children:f?e.jsx("path",{d:"M18 6 6 18M6 6l12 12"}):e.jsx("path",{d:"M12 5v14M5 12h14"})}),e.jsx("span",{className:"hidden sm:inline",children:f?"Cancel":"New Task"})]})]}),f&&e.jsxs("div",{className:"mb-6 rounded-xl bg-cc-card p-4 sm:p-5 space-y-3",style:{animation:"fadeSlideIn 150ms ease-out"},children:[e.jsx(T,{form:r,onChange:v}),e.jsx("p",{className:"text-[10px] text-cc-muted",children:"Scheduled tasks run with full autonomy (bypassPermissions)"}),m&&f&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-error/10 text-xs text-cc-error",children:m}),e.jsx("div",{className:"flex items-center justify-end pt-1",children:e.jsx("button",{onClick:C,disabled:!r.name.trim()||!r.prompt.trim()||h,className:`px-4 py-2.5 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${r.name.trim()&&r.prompt.trim()&&!h?"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer":"bg-cc-hover text-cc-muted cursor-not-allowed"}`,children:h?"Creating...":"Create"})})]}),e.jsxs("div",{className:"flex items-center gap-2 mb-3 text-[12px] text-cc-muted",children:[e.jsxs("span",{children:[c.length," task",c.length!==1?"s":""]}),c.filter(t=>t.enabled).length>0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-cc-border",children:"·"}),e.jsxs("span",{children:[c.filter(t=>t.enabled).length," active"]})]})]}),o?e.jsx("div",{className:"py-12 text-center text-sm text-cc-muted",children:"Loading scheduled tasks..."}):c.length===0?e.jsx("div",{className:"py-12 text-center text-sm text-cc-muted",children:"No scheduled tasks yet."}):e.jsx("div",{className:"space-y-1",children:c.map(t=>l===t.id?e.jsxs("div",{className:"rounded-xl bg-cc-card p-4 space-y-3",style:{animation:"fadeSlideIn 150ms ease-out"},children:[e.jsx(T,{form:u,onChange:w}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx("button",{onClick:D,className:"px-3 py-2.5 min-h-[44px] text-sm rounded-lg text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer",children:"Cancel"}),e.jsx("button",{onClick:()=>void L(),className:"px-4 py-2.5 min-h-[44px] text-sm rounded-lg font-medium bg-cc-primary hover:bg-cc-primary-hover text-white transition-colors cursor-pointer",children:"Save"})]})]},t.id):e.jsx(G,{job:t,isRunning:k.has(t.id),onStartEdit:()=>R(t),onDelete:()=>void A(t.id),onToggle:()=>void I(t.id),onRunNow:()=>void P(t.id)},t.id))}),m&&!f&&e.jsx("div",{className:"mt-4 px-3 py-2 rounded-lg bg-cc-error/10 text-xs text-cc-error",children:m})]})});const O=m&&e.jsx("div",{className:"px-3 py-2 rounded-lg bg-cc-error/10 text-xs text-cc-error",children:m}),H=o?e.jsx("div",{className:"text-sm text-cc-muted text-center py-6",children:"Loading scheduled tasks..."}):c.length===0?e.jsx("div",{className:"text-sm text-cc-muted text-center py-6",children:"No scheduled tasks yet."}):e.jsx("div",{className:"space-y-3",children:c.map(t=>e.jsxs("div",{className:"rounded-xl bg-cc-card overflow-hidden",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-2.5",children:[e.jsx("span",{className:"text-sm font-medium text-cc-fg flex-1 truncate",children:t.name}),e.jsx("span",{className:`text-[9px] font-medium px-1.5 rounded-full leading-[16px] shrink-0 ${t.backendType==="codex"?"text-blue-500 bg-blue-500/10":"text-[#5BA8A0] bg-[#5BA8A0]/10"}`,children:t.backendType==="codex"?"Codex":"Claude"}),t.consecutiveFailures>0&&e.jsxs("span",{className:"text-[9px] font-medium px-1.5 rounded-full leading-[16px] shrink-0 text-cc-error bg-cc-error/10",children:[t.consecutiveFailures," fail",t.consecutiveFailures!==1?"s":""]}),e.jsx("button",{onClick:()=>I(t.id),className:`relative w-10 h-6 rounded-full transition-colors cursor-pointer shrink-0 ${t.enabled?"bg-cc-primary":"bg-cc-border"}`,title:t.enabled?"Disable":"Enable",children:e.jsx("span",{className:`absolute top-[3px] w-[18px] h-[18px] rounded-full bg-white transition-transform ${t.enabled?"left-[19px]":"left-[3px]"}`})}),l===t.id?e.jsx("button",{onClick:D,className:"text-xs px-2 py-1.5 min-h-[44px] text-cc-muted hover:text-cc-fg cursor-pointer",children:"Cancel"}):e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>P(t.id),disabled:k.has(t.id),className:`text-xs px-2 py-1.5 min-h-[44px] cursor-pointer ${k.has(t.id)?"text-cc-muted cursor-not-allowed":"text-cc-primary hover:text-cc-primary-hover"}`,children:k.has(t.id)?"Running...":"Run Now"}),e.jsx("button",{onClick:()=>R(t),className:"text-xs px-2 py-1.5 min-h-[44px] text-cc-muted hover:text-cc-fg cursor-pointer",children:"Edit"}),e.jsx("button",{onClick:()=>A(t.id),className:"text-xs px-2 py-1.5 min-h-[44px] text-cc-muted hover:text-cc-error cursor-pointer",children:"Delete"})]})]}),l===t.id&&e.jsxs("div",{className:"px-3 py-3 space-y-2.5",children:[e.jsx(T,{form:u,onChange:w}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:L,className:"px-4 py-2.5 min-h-[44px] text-sm font-medium bg-cc-primary hover:bg-cc-primary-hover text-white rounded-lg transition-colors cursor-pointer",children:"Save"}),e.jsx("button",{onClick:D,className:"px-3 py-2.5 min-h-[44px] text-sm font-medium text-cc-muted hover:text-cc-fg rounded-lg transition-colors cursor-pointer",children:"Cancel"})]})]}),l!==t.id&&e.jsxs("div",{className:"px-3 py-2.5 space-y-1.5",children:[e.jsx("div",{className:"text-xs text-cc-muted truncate",title:t.prompt,children:t.prompt}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-cc-muted",children:[e.jsx("span",{children:F(t.schedule,t.recurring)}),t.nextRunAt!=null&&t.enabled&&e.jsxs("span",{children:["Next: ",J(t.nextRunAt)]}),t.lastRunAt!=null&&e.jsxs("span",{className:"flex items-center gap-1",children:["Last: ",z(t.lastRunAt),t.consecutiveFailures===0?e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-3 h-3 text-cc-success",children:e.jsx("path",{d:"M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2.5-2.5a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z"})}):e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-3 h-3 text-cc-error",children:e.jsx("path",{d:"M4.646 4.646a.5.5 0 01.708 0L8 7.293l2.646-2.647a.5.5 0 01.708.708L8.707 8l2.647 2.646a.5.5 0 01-.708.708L8 8.707l-2.646 2.647a.5.5 0 01-.708-.708L7.293 8 4.646 5.354a.5.5 0 010-.708z"})})]}),t.totalRuns>0&&e.jsxs("span",{children:[t.totalRuns," run",t.totalRuns!==1?"s":""]}),t.cwd&&e.jsx("span",{className:"font-mono-code truncate max-w-[200px]",title:t.cwd,children:t.cwd})]})]})]},t.id))}),V=e.jsxs("div",{className:"rounded-xl bg-cc-card overflow-hidden",children:[e.jsxs("button",{onClick:()=>S(!f),className:"w-full flex items-center gap-2 px-3 py-2.5 cursor-pointer hover:bg-cc-hover transition-colors",children:[e.jsx("svg",{viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"2",className:`w-3 h-3 text-cc-muted transition-transform ${f?"rotate-90":""}`,children:e.jsx("path",{d:"M6 4l4 4-4 4",strokeLinecap:"round",strokeLinejoin:"round"})}),e.jsx("span",{className:"text-sm font-medium text-cc-fg",children:"New Scheduled Task"})]}),f&&e.jsxs("div",{className:"px-3 py-3 space-y-2.5",children:[e.jsx(T,{form:r,onChange:v}),e.jsx("div",{className:"text-[10px] text-cc-muted",children:"Scheduled tasks run with full autonomy (bypassPermissions)"}),e.jsx("button",{onClick:C,disabled:!r.name.trim()||!r.prompt.trim()||h,className:`px-4 py-2.5 min-h-[44px] text-sm font-medium rounded-lg transition-colors ${r.name.trim()&&r.prompt.trim()&&!h?"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer":"bg-cc-hover text-cc-muted cursor-not-allowed"}`,children:h?"Creating...":"Create"})]})]}),Z=e.jsxs("div",{className:"w-full max-w-2xl max-h-[90dvh] sm:max-h-[80dvh] mx-0 sm:mx-4 flex flex-col bg-cc-bg rounded-t-[14px] sm:rounded-[14px] shadow-2xl overflow-hidden",onClick:t=>t.stopPropagation(),children:[e.jsxs("div",{className:"flex items-center justify-between px-4 sm:px-5 py-3 sm:py-4",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg",children:"Scheduled Tasks"}),e.jsx("p",{className:"text-xs text-cc-muted mt-0.5",children:"Run autonomous Claude Code or Codex sessions on a schedule"})]}),s&&e.jsx("button",{onClick:s,className:"w-8 h-8 flex items-center justify-center rounded-md text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer",children:e.jsx("svg",{viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"2",className:"w-3.5 h-3.5",children:e.jsx("path",{d:"M4 4l8 8M12 4l-8 8",strokeLinecap:"round"})})})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto px-3 sm:px-5 py-3 sm:py-4 pb-safe space-y-4",children:[O,H,V]})]});return _.createPortal(e.jsx("div",{className:"fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/50",onClick:s,children:Z}),document.body)}function G({job:s,isRunning:p,onStartEdit:c,onDelete:d,onToggle:o,onRunNow:g}){return e.jsxs("div",{className:"group flex items-start gap-3 px-3 py-3 min-h-[44px] rounded-lg hover:bg-cc-hover/60 transition-colors",children:[e.jsx("div",{className:"shrink-0 mt-0.5 w-7 h-7 rounded-md bg-cc-primary/10 flex items-center justify-center",children:e.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",className:"w-3.5 h-3.5 text-cc-primary",children:[e.jsx("circle",{cx:"12",cy:"12",r:"10"}),e.jsx("path",{d:"M12 6v6l4 2"})]})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-medium text-cc-fg truncate",children:s.name}),e.jsx("span",{className:`text-[9px] font-medium px-1.5 rounded-full leading-[16px] shrink-0 ${s.backendType==="codex"?"text-blue-500 bg-blue-500/10":"text-[#5BA8A0] bg-[#5BA8A0]/10"}`,children:s.backendType==="codex"?"Codex":"Claude"}),s.consecutiveFailures>0&&e.jsxs("span",{className:"text-[9px] font-medium px-1.5 rounded-full leading-[16px] shrink-0 text-cc-error bg-cc-error/10",children:[s.consecutiveFailures," fail",s.consecutiveFailures!==1?"s":""]}),!s.enabled&&e.jsx("span",{className:"text-[9px] font-medium px-1.5 rounded-full leading-[16px] shrink-0 text-cc-muted bg-cc-hover",children:"Paused"})]}),e.jsx("p",{className:"mt-0.5 text-xs text-cc-muted line-clamp-1 leading-relaxed",children:s.prompt}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-2 gap-y-0.5 mt-1 text-[11px] text-cc-muted",children:[e.jsx("span",{children:F(s.schedule,s.recurring)}),s.nextRunAt!=null&&s.enabled&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-cc-border",children:"·"}),e.jsxs("span",{children:["Next ",J(s.nextRunAt)]})]}),s.lastRunAt!=null&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-cc-border",children:"·"}),e.jsxs("span",{className:"flex items-center gap-0.5",children:["Last ",z(s.lastRunAt),s.consecutiveFailures===0?e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-2.5 h-2.5 text-cc-success",children:e.jsx("path",{d:"M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2.5-2.5a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z"})}):e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-2.5 h-2.5 text-cc-error",children:e.jsx("path",{d:"M4.646 4.646a.5.5 0 01.708 0L8 7.293l2.646-2.647a.5.5 0 01.708.708L8.707 8l2.647 2.646a.5.5 0 01-.708.708L8 8.707l-2.646 2.647a.5.5 0 01-.708-.708L7.293 8 4.646 5.354a.5.5 0 010-.708z"})})]})]}),s.totalRuns>0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-cc-border",children:"·"}),e.jsxs("span",{children:[s.totalRuns," run",s.totalRuns!==1?"s":""]})]})]})]}),e.jsxs("div",{className:"shrink-0 flex items-center gap-0.5 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity",children:[e.jsx("button",{onClick:o,className:`relative w-9 h-5 rounded-full transition-colors cursor-pointer shrink-0 ${s.enabled?"bg-cc-primary":"bg-cc-border"}`,title:s.enabled?"Disable":"Enable",children:e.jsx("span",{className:`absolute top-[2px] w-4 h-4 rounded-full bg-white transition-transform ${s.enabled?"left-[17px]":"left-[2px]"}`})}),e.jsx("button",{onClick:g,disabled:p,className:`p-2 min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0 sm:p-1.5 rounded-md transition-colors cursor-pointer ${p?"text-cc-muted cursor-not-allowed":"text-cc-primary hover:bg-cc-primary/10"}`,"aria-label":"Run now",title:p?"Running...":"Run now",children:e.jsx("svg",{viewBox:"0 0 24 24",fill:"currentColor",className:"w-3.5 h-3.5",children:e.jsx("path",{d:"M8 5v14l11-7z"})})}),e.jsx("button",{onClick:c,className:"p-2 min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0 sm:p-1.5 rounded-md text-cc-muted hover:text-cc-fg hover:bg-cc-active transition-colors cursor-pointer","aria-label":"Edit",children:e.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",className:"w-3.5 h-3.5",children:[e.jsx("path",{d:"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"}),e.jsx("path",{d:"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5Z"})]})}),e.jsx("button",{onClick:d,className:"p-2 min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0 sm:p-1.5 rounded-md text-cc-muted hover:text-cc-error hover:bg-cc-error/10 transition-colors cursor-pointer","aria-label":"Delete",children:e.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",className:"w-3.5 h-3.5",children:e.jsx("path",{d:"M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14Z"})})})]})]})}function T({form:s,onChange:p}){const c=n=>p({...s,...n}),[d,o]=a.useState(null),[g,m]=a.useState(!1),x=a.useRef(null),[l,y]=a.useState(!1),[u,w]=a.useState(!1),r=a.useRef(null),v=d||K(s.backendType),h=v.find(n=>n.value===s.model)||v[0];a.useEffect(()=>{o(null),s.backendType==="codex"&&j.getBackendModels(s.backendType).then(n=>{if(n.length>0){const C=U(n);o(C),C.some(R=>R.value===s.model)||c({model:C[0].value})}}).catch(()=>{})},[s.backendType]),a.useEffect(()=>{s.model||c({model:B(s.backendType)})},[]);const M=a.useMemo(()=>[x],[]),f=a.useCallback(()=>m(!1),[]);W(M,f,g);const S=a.useMemo(()=>[r],[]),k=a.useCallback(()=>w(!1),[]);W(S,k,u);const E=s.cwd?s.cwd.split("/").pop()||s.cwd:"Select folder";return e.jsxs("div",{className:"space-y-2.5",children:[e.jsx("input",{type:"text",value:s.name,onChange:n=>c({name:n.target.value}),placeholder:"Task name (e.g. Daily test suite)",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("textarea",{value:s.prompt,onChange:n=>c({prompt:n.target.value}),placeholder:"Prompt for the session (e.g. Run the test suite and fix any failures)",rows:4,className:"w-full px-3 py-2.5 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 resize-y transition-shadow",style:{minHeight:"100px"}}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("button",{onClick:()=>c({recurring:!0}),className:`px-2.5 py-2 min-h-[44px] text-xs font-medium rounded-lg transition-colors cursor-pointer ${s.recurring?"bg-cc-primary text-white":"bg-cc-hover text-cc-muted hover:text-cc-fg"}`,children:"Recurring"}),e.jsx("button",{onClick:()=>c({recurring:!1}),className:`px-2.5 py-2 min-h-[44px] text-xs font-medium rounded-lg transition-colors cursor-pointer ${s.recurring?"bg-cc-hover text-cc-muted hover:text-cc-fg":"bg-cc-primary text-white"}`,children:"One-time"})]}),s.recurring?e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("div",{className:"flex flex-wrap gap-1.5",children:q.map(n=>e.jsx("button",{onClick:()=>c({schedule:n.value}),className:`px-2.5 py-2 min-h-[44px] text-xs font-medium rounded-md transition-colors cursor-pointer ${s.schedule===n.value?"bg-cc-primary/20 text-cc-primary":"bg-cc-hover text-cc-muted hover:text-cc-fg"}`,children:n.label},n.value))}),e.jsx("input",{type:"text",value:s.schedule,onChange:n=>c({schedule:n.target.value}),placeholder:"Cron expression (e.g. 0 8 * * *)",className:"w-full px-3 py-2.5 min-h-[44px] text-sm font-mono-code 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("div",{className:"text-[10px] text-cc-muted",children:F(s.schedule,!0)})]}):e.jsx("input",{type:"datetime-local",value:s.oneTimeDate,onChange:n=>c({oneTimeDate:n.target.value}),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.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsxs("div",{className:"relative",ref:r,children:[e.jsxs("button",{onClick:()=>w(!u),className:"flex items-center gap-1.5 px-2.5 py-2 min-h-[44px] text-xs font-medium text-cc-fg rounded-lg hover:bg-cc-hover transition-colors cursor-pointer",children:[e.jsx("span",{children:s.backendType==="codex"?"Codex":"Claude Code"}),e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-3 h-3 opacity-50",children:e.jsx("path",{d:"M4 6l4 4 4-4"})})]}),u&&e.jsx("div",{className:"absolute left-0 bottom-full mb-1 w-40 bg-cc-card rounded-xl shadow-lg z-10 py-1",children:[{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex"}].map(n=>e.jsx("button",{onClick:()=>{c({backendType:n.value,model:B(n.value)}),w(!1)},className:`w-full px-3 py-2.5 min-h-[44px] text-xs text-left hover:bg-cc-hover transition-colors cursor-pointer ${n.value===s.backendType?"text-cc-primary font-medium":"text-cc-fg"}`,children:n.label},n.value))})]}),e.jsxs("div",{className:"relative",ref:x,children:[e.jsxs("button",{onClick:()=>m(!g),className:"flex items-center gap-1.5 px-2.5 py-2 min-h-[44px] text-xs text-cc-muted hover:text-cc-fg rounded-lg hover:bg-cc-hover transition-colors cursor-pointer",children:[e.jsx("span",{children:h==null?void 0:h.icon}),e.jsx("span",{children:h==null?void 0:h.label}),e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-3 h-3 opacity-50",children:e.jsx("path",{d:"M4 6l4 4 4-4"})})]}),g&&e.jsx("div",{className:"absolute left-0 bottom-full mb-1 w-52 bg-cc-card rounded-xl shadow-lg z-10 py-1",children:v.map(n=>e.jsxs("button",{onClick:()=>{c({model:n.value}),m(!1)},className:`w-full px-3 py-2.5 min-h-[44px] text-xs text-left hover:bg-cc-hover transition-colors cursor-pointer flex items-center gap-2 ${n.value===s.model?"text-cc-primary font-medium":"text-cc-fg"}`,children:[e.jsx("span",{children:n.icon}),n.label]},n.value))})]}),e.jsxs("button",{onClick:()=>y(!0),className:"flex items-center gap-1.5 px-2.5 py-2 min-h-[44px] text-xs text-cc-muted hover:text-cc-fg rounded-lg hover:bg-cc-hover transition-colors cursor-pointer",children:[e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-3.5 h-3.5 opacity-60",children:e.jsx("path",{d:"M1 3.5A1.5 1.5 0 012.5 2h3.379a1.5 1.5 0 011.06.44l.622.621a.5.5 0 00.353.146H13.5A1.5 1.5 0 0115 4.707V12.5a1.5 1.5 0 01-1.5 1.5h-11A1.5 1.5 0 011 12.5v-9z"})}),e.jsx("span",{className:"max-w-[200px] truncate font-mono-code",children:E}),e.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor",className:"w-3 h-3 opacity-50",children:e.jsx("path",{d:"M4 6l4 4 4-4"})})]}),l&&e.jsx(Y,{initialPath:s.cwd||"",onSelect:n=>c({cwd:n}),onClose:()=>y(!1)})]})]})}export{X as CronManager};
@@ -1 +0,0 @@
1
- import{u as l,r as s,c as k,j as r,D as M,M as R,P as _,C}from"./index-C0oFg9YU.js";import{d as P,t as D,M as E}from"./MagicUIDashboard-DpxmzOIx.js";const N=4e3;function A({sessionId:t}){const u=l(e=>e.pendingPermissions.get(t)),h=l(e=>e.removePermission),m=l(e=>e.connectionStatus.get(t)??"disconnected"),x=l(e=>e.cliConnected.get(t)??!1),i=s.useMemo(()=>u?Array.from(u.values()):[],[u]),[a,g]=s.useState(new Set),f=s.useRef(new Set),c=s.useRef(new Map);s.useEffect(()=>{for(const e of i){const n=e.request_id;f.current.has(n)||a.has(n)||c.current.has(n)||c.current.set(n,setTimeout(()=>{c.current.delete(n),f.current.has(n)||g(o=>new Set(o).add(n))},N))}for(const[e,n]of c.current)i.some(o=>o.request_id===e)||(clearTimeout(n),c.current.delete(e))},[i,a]),s.useEffect(()=>()=>{for(const e of c.current.values())clearTimeout(e);c.current.clear()},[]);const b=s.useCallback(e=>{f.current.add(e);const n=c.current.get(e);n&&(clearTimeout(n),c.current.delete(e))},[]),v=s.useCallback((e,n)=>{var d;const o=(d=l.getState().pendingPermissions.get(t))==null?void 0:d.get(e);o&&(k(t,P(o,n)),h(t,e))},[t,h]),w=s.useCallback(()=>{g(e=>{var o;const n=new Set(e);for(const d of((o=l.getState().pendingPermissions.get(t))==null?void 0:o.values())??[])n.add(d.request_id);return n})},[t]),j=s.useMemo(()=>i.filter(e=>!a.has(e.request_id)).map(D),[i,a]),p=s.useMemo(()=>i.filter(e=>a.has(e.request_id)),[i,a]),S=m==="connected"&&!x;return r.jsxs("div",{className:"flex flex-col h-full min-h-0",children:[(S||m==="disconnected")&&r.jsxs("div",{className:"px-4 py-1.5 bg-gradient-to-r from-cc-warning/8 to-cc-warning/4 border-b border-cc-warning/15 flex items-center justify-center gap-2",children:[r.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-cc-warning animate-[pulse-dot_1.5s_ease-in-out_infinite] shrink-0"}),r.jsx("span",{className:"text-xs text-cc-warning font-medium",children:m==="disconnected"?"Reconnecting to session…":"CLI disconnected — switch to Standard view to reconnect"})]}),r.jsx("div",{className:"h-36 shrink-0 border-b border-cc-border relative overflow-hidden","aria-label":"Raw session output",children:r.jsx(M,{value:"compact",children:r.jsx(R,{sessionId:t})})}),r.jsx("div",{className:"flex-1 min-h-0 relative bg-cc-bg",children:r.jsx(E,{sessionId:t,decisions:j,onDecisionAck:b,onDecisionResponse:v,onRuntimeError:w})}),p.length>0&&r.jsx("div",{className:"shrink-0 max-h-[50dvh] overflow-y-auto border-t border-cc-border bg-cc-card",children:p.map(e=>r.jsx(_,{permission:e,sessionId:t},e.request_id))}),r.jsx(C,{sessionId:t})]})}export{A as MagicUIView};
@@ -1 +0,0 @@
1
- import{r as s,u as o,g as Tt,a as n,j as e,n as It,b as Pt,s as Mt}from"./index-C0oFg9YU.js";const ge=[{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:"magic-ui",label:"Magic UI"},{id:"updates",label:"Updates"},{id:"telemetry",label:"Telemetry"},{id:"environments",label:"Environments"}];function Dt({embedded:fe=!1}){const[p,ve]=s.useState(""),[ye,je]=s.useState("claude-sonnet-4-6"),[d,we]=s.useState(!1),[C,ot]=s.useState(!0),[f,S]=s.useState(!1),[Ne,v]=s.useState(""),[ke,y]=s.useState(!1),it=o(t=>t.darkMode),rt=o(t=>t.toggleDarkMode),Ce=o(t=>t.diffBase),lt=o(t=>t.setDiffBase),dt=o(t=>t.density),ut=o(t=>t.toggleDensity),xt=o(t=>t.notificationSound),pt=o(t=>t.toggleNotificationSound),Se=o(t=>t.notificationDesktop),Ae=o(t=>t.setNotificationDesktop),i=o(t=>t.updateInfo),O=o(t=>t.setUpdateInfo),mt=o(t=>t.setUpdateOverlayActive),ht=typeof Notification<"u",[x,j]=s.useState("stable"),[A,L]=s.useState(!1),[U,V]=s.useState(!0),[E,K]=s.useState(!0),[T,$]=s.useState(!0),[I,F]=s.useState("stdio"),[Ue,H]=s.useState("loopback"),[B,Ee]=s.useState(!1),[Q,Te]=s.useState(!1),[Ie,w]=s.useState(""),[Pe,P]=s.useState(""),[Me,bt]=s.useState(Tt()),[M,W]=s.useState(!1),[_,G]=s.useState(!0),[q,Y]=s.useState(!1),[z,J]=s.useState(!1),[Re,X]=s.useState("claude-haiku-4-5"),[De,Z]=s.useState(3),[Oe,ee]=s.useState(30),[te,se]=s.useState(!1),[Le,ae]=s.useState("claude-haiku-4-5"),[m,gt]=s.useState(!0),[R,ne]=s.useState(""),[Ve,Ke]=s.useState("general"),[ft,$e]=s.useState(!1),[ce,Fe]=s.useState(!1),[N,h]=s.useState(null),[b,He]=s.useState(""),[oe,Be]=s.useState(!1),[g,Qe]=s.useState(""),[ie,We]=s.useState(!1),[re,_e]=s.useState(!1),[vt,le]=s.useState(!1),[Ge,qe]=s.useState(""),[yt,Ye]=s.useState(!1),[jt,ze]=s.useState(!1),[k,Je]=s.useState(null),[de,Xe]=s.useState(!1),[u,Ze]=s.useState(null),[D,wt]=s.useState(0),[ue,et]=s.useState(!1),[xe,tt]=s.useState(!1),[Nt,st]=s.useState(!1),at=s.useRef(null),pe=s.useRef({});s.useEffect(()=>{const t=at.current;if(!t)return;const a=new IntersectionObserver(c=>{var ct;let l=null;for(const be of c)be.isIntersecting&&(!l||be.boundingClientRect.top<l.boundingClientRect.top)&&(l=be);(ct=l==null?void 0:l.target)!=null&&ct.id&&Ke(l.target.id)},{root:t,rootMargin:"-10% 0px -70% 0px",threshold:0});for(const c of ge){const l=pe.current[c.id];l&&a.observe(l)}return()=>a.disconnect()},[C]);const nt=s.useCallback(t=>{Ke(t);const a=pe.current[t];a&&a.scrollIntoView({behavior:"smooth",block:"start"})},[]);s.useEffect(()=>{n.getSettings().then(t=>{we(t.anthropicApiKeyConfigured),Be(t.claudeCodeOAuthTokenConfigured),We(t.openaiApiKeyConfigured),je(t.anthropicModel||"claude-sonnet-4-6"),typeof t.aiValidationEnabled=="boolean"&&W(t.aiValidationEnabled),typeof t.aiValidationAutoApprove=="boolean"&&G(t.aiValidationAutoApprove),typeof t.aiValidationAutoDeny=="boolean"&&Y(t.aiValidationAutoDeny),typeof t.dashboardEnabled=="boolean"&&J(t.dashboardEnabled),typeof t.dashboardModel=="string"&&t.dashboardModel&&X(t.dashboardModel),typeof t.dashboardRunHour=="number"&&Z(t.dashboardRunHour),typeof t.dashboardMaxSessionsPerRun=="number"&&ee(t.dashboardMaxSessionsPerRun),typeof t.magicUiEnabled=="boolean"&&se(t.magicUiEnabled),typeof t.magicUiModel=="string"&&t.magicUiModel&&ae(t.magicUiModel),typeof t.claudeCliAvailable=="boolean"&&gt(t.claudeCliAvailable),(t.updateChannel==="stable"||t.updateChannel==="prerelease")&&j(t.updateChannel),typeof t.dockerAutoUpdate=="boolean"&&L(t.dockerAutoUpdate),typeof t.proactiveKeepaliveEnabled=="boolean"&&V(t.proactiveKeepaliveEnabled),typeof t.wedgeKillEnabled=="boolean"&&K(t.wedgeKillEnabled),typeof t.silenceProbeEnabled=="boolean"&&$(t.silenceProbeEnabled),(t.claudeTransport==="sdk"||t.claudeTransport==="stdio")&&F(t.claudeTransport),(t.cliBridgeMode==="loopback"||t.cliBridgeMode==="jsonHandoff")&&H(t.cliBridgeMode),typeof t.publicUrl=="string"&&(ne(t.publicUrl),o.getState().setPublicUrl(t.publicUrl))}).catch(t=>v(t instanceof Error?t.message:String(t))).finally(()=>ot(!1)),n.getAuthToken().then(t=>Je(t.token)).catch(()=>{})},[]);async function kt(t){t.preventDefault(),S(!0),v(""),y(!1);try{const a=p.trim(),c={anthropicModel:ye.trim()||"claude-sonnet-4-6"};a&&(c.anthropicApiKey=a);const l=await n.updateSettings(c);we(l.anthropicApiKeyConfigured),ve(""),y(!0),setTimeout(()=>y(!1),1800)}catch(a){v(a instanceof Error?a.message:String(a))}finally{S(!1)}}async function me(t){const a=t==="aiValidationEnabled"?M:t==="aiValidationAutoApprove"?_:q,c=!a;t==="aiValidationEnabled"?W(c):t==="aiValidationAutoApprove"?G(c):Y(c);try{await n.updateSettings({[t]:c})}catch{t==="aiValidationEnabled"?W(a):t==="aiValidationAutoApprove"?G(a):Y(a)}}async function Ct(){const t=z;J(!t);try{await n.updateSettings({dashboardEnabled:!t})}catch{J(t)}}async function St(){const t=te;se(!t);try{const a=await n.updateSettings({magicUiEnabled:!t});o.getState().setMagicUiAvailable(!!a.magicUiEnabled&&!!a.claudeCliAvailable)}catch{se(t)}}async function At(t,a){try{await n.updateSettings({magicUiModel:t})}catch{a()}}async function he(t,a){try{await n.updateSettings(t)}catch{a()}}async function Ut(){Ee(!0),w(""),P("");try{const t=await n.forceCheckForUpdate();O(t),t.updateAvailable&&t.latestVersion?w(`Update v${t.latestVersion} is available.`):w("You are up to date.")}catch(t){P(t instanceof Error?t.message:String(t))}finally{Ee(!1)}}async function Et(){Te(!0),w(""),P("");try{localStorage.setItem("companion_docker_prompt_pending","1");const t=await n.triggerUpdate();w(t.message),mt(!0)}catch(t){localStorage.removeItem("companion_docker_prompt_pending"),P(t instanceof Error?t.message:String(t)),Te(!1)}}const r=s.useCallback(t=>a=>{pe.current[t]=a},[]);return e.jsxs("div",{className:`${fe?"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."})]}),!fe&&e.jsx("button",{onClick:()=>{const t=o.getState().currentSessionId;t?It(t):Pt()},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:ge.map(t=>e.jsx("button",{type:"button",onClick:()=>nt(t.id),className:`shrink-0 px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${Ve===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:ge.map(t=>e.jsx("button",{type:"button",onClick:()=>nt(t.id),className:`text-left px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors cursor-pointer ${Ve===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:at,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:r("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:rt,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:it?"Dark":"Light"})]}),e.jsxs("button",{type:"button",onClick:ut,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:"Message density"}),e.jsx("span",{className:"text-xs text-cc-muted",children:dt==="compact"?"Compact":"Standard"})]}),e.jsx("p",{className:"text-xs text-cc-muted px-1",children:"Standard shows commands, diffs and tool output inline. Compact collapses each of them to a single line you can expand on demand, and hides empty thinking steps. This setting is stored in this browser only."}),e.jsxs("button",{type:"button",onClick:()=>lt(Ce==="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:Ce==="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:Ue,onChange:async t=>{const a=t.target.value==="jsonHandoff"?"jsonHandoff":"loopback",c=Ue;H(a);try{await n.updateSettings({cliBridgeMode:a})}catch{H(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":U,"aria-label":"Proactive keepalive relaunch",onClick:async()=>{const t=!U,a=U;V(t);try{await n.updateSettings({proactiveKeepaliveEnabled:t})}catch{V(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:U?"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;K(t);try{await n.updateSettings({wedgeKillEnabled:t})}catch{K(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("div",{className:"pt-3 border-t border-cc-border",children:[e.jsxs("button",{type:"button",role:"switch","aria-checked":T,"aria-label":"Probe silent CLI processes",onClick:async()=>{const t=!T,a=T;$(t);try{await n.updateSettings({silenceProbeEnabled:t})}catch{$(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:"Probe silent CLI processes"}),e.jsx("span",{className:"text-xs text-cc-muted",children:T?"On":"Off"})]}),e.jsx("p",{className:"mt-1 text-xs text-cc-muted px-1",children:"When on (default), a CLI that stops responding while its output stream stays open is sent a liveness probe after ~2 minutes of silence. If it does not answer within a further minute the session is relaunched and the in-flight turn replayed. Without this such a session hangs indefinitely showing “Still working…” with no error, because nothing ever closes the stream for companion to notice."})]}),e.jsxs("div",{className:"pt-3 border-t border-cc-border",children:[e.jsxs("button",{type:"button",role:"switch","aria-checked":I==="sdk","aria-label":"Use Agent SDK transport (experimental)",onClick:async()=>{const t=I==="sdk"?"stdio":"sdk",a=I;F(t);try{await n.updateSettings({claudeTransport:t})}catch{F(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:"Use Agent SDK transport (experimental)"}),e.jsx("span",{className:"text-xs text-cc-muted",children:I==="sdk"?"SDK":"stdio"})]}),e.jsxs("p",{className:"mt-1 text-xs text-cc-muted px-1",children:["Claude Code only — Codex sessions are unaffected. When on, new and reconnected Claude sessions run through Anthropic’s official Agent SDK instead of companion’s own stdio bridge: same ",e.jsx("code",{children:"claude"})," binary, same subscription login and usage windows, but the protocol layer is maintained upstream. Applies at launch time, so flip it and hit Reconnect on a session to migrate it (history is preserved via resume). Containerized sessions always use the stdio bridge."]})]})]})]}),e.jsxs("section",{id:"webhooks",ref:r("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:R,onChange:t=>ne(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:R?`Using: ${R}`:`Fallback: ${typeof window<"u"?window.location.origin:"http://localhost:3456"}`})]}),e.jsx("button",{type:"button",onClick:async()=>{S(!0),v("");try{const t=await n.updateSettings({publicUrl:R.trim()});ne(t.publicUrl),o.getState().setPublicUrl(t.publicUrl),y(!0),setTimeout(()=>y(!1),1800)}catch(t){v(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...":ke?"Saved!":"Save Public URL"})]})]}),e.jsxs("section",{id:"authentication",ref:r("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?de?k:"••••••••••••••••":e.jsx("span",{className:"text-cc-muted",children:"Loading..."})}),e.jsx("button",{type:"button",onClick:()=>Xe(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:de?"Hide token":"Show token",children:de?"Hide":"Show"}),e.jsx("button",{type:"button",onClick:()=>{k&&navigator.clipboard.writeText(k).then(()=>{st(!0),setTimeout(()=>st(!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:Nt?"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:()=>wt(a),className:`px-3 py-1.5 rounded-md text-xs font-medium transition-colors cursor-pointer ${a===D?"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[D].qrDataUrl,alt:`QR code for ${u[D].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[D].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()=>{et(!0);try{const t=await n.getAuthQr();Ze(t.qrCodes)}catch{}finally{et(!1)}},disabled:ue,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${ue?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:ue?"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.")){tt(!0);try{const t=await n.regenerateAuthToken();Je(t.token),Xe(!0),Ze(null)}catch{}finally{tt(!1)}}},disabled:xe,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${xe?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-error/10 hover:bg-cc-error/20 text-cc-error cursor-pointer"}`,children:xe?"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:r("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:pt,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:xt?"On":"Off"})]}),ht&&e.jsxs("button",{type:"button",onClick:async()=>{if(Se)Ae(!1);else{if(Notification.permission!=="granted"&&await Notification.requestPermission()!=="granted")return;Ae(!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:Se?"On":"Off"})]})]})]}),e.jsxs("section",{id:"providers",ref:r("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:oe&&!yt&&!b?"••••••••••••••••":b,onChange:t=>He(t.target.value),onFocus:()=>Ye(!0),onBlur:()=>Ye(!1),placeholder:oe?"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:oe?"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:ie&&!jt&&!g?"••••••••••••••••":g,onChange:t=>Qe(t.target.value),onFocus:()=>ze(!0),onBlur:()=>ze(!1),placeholder:ie?"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:ie?"OpenAI key configured":"OpenAI key not configured"})]}),Ge&&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:Ge}),vt&&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:re||!b.trim()&&!g.trim(),onClick:async()=>{_e(!0),qe(""),le(!1);try{const t={};b.trim()&&(t.claudeCodeOAuthToken=b.trim()),g.trim()&&(t.openaiApiKey=g.trim());const a=await n.updateSettings(t);Be(a.claudeCodeOAuthTokenConfigured),We(a.openaiApiKeyConfigured),He(""),Qe(""),le(!0),setTimeout(()=>le(!1),1800)}catch(t){qe(t instanceof Error?t.message:String(t))}finally{_e(!1)}},className:`px-4 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${re||!b.trim()&&!g.trim()?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:re?"Saving...":"Save Provider Settings"})]})]}),e.jsxs("section",{id:"anthropic",ref:r("anthropic"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Anthropic"}),e.jsxs("form",{onSubmit:kt,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&&!ft&&!p?"••••••••••••••••":p,onChange:t=>{ve(t.target.value),h(null)},onFocus:()=>$e(!0),onBlur:()=>$e(!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:ye,onChange:t=>je(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"})]}),Ne&&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:Ne}),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:"Settings saved."}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-cc-muted",children:C?"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:ce||!p.trim(),onClick:async()=>{Fe(!0),h(null);try{const t=await n.verifyAnthropicKey(p.trim());h(t),setTimeout(()=>h(null),5e3)}catch(t){h({valid:!1,error:t instanceof Error?t.message:String(t)}),setTimeout(()=>h(null),5e3)}finally{Fe(!1)}},className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${ce||!p.trim()?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:ce?"Verifying...":"Verify"}),e.jsx("button",{type:"submit",disabled:f||C,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${f||C?"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:r("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:()=>me("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 ${M&&d?"text-cc-success":"text-cc-muted"}`,children:M&&d?"On":"Off"})]}),!d&&e.jsx("p",{className:"text-[11px] text-cc-warning",children:"Configure an Anthropic API key above to enable AI validation."}),M&&d&&e.jsxs(e.Fragment,{children:[e.jsxs("button",{type:"button",onClick:()=>me("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 ${_?"text-cc-success":"text-cc-muted"}`,children:_?"On":"Off"})]}),e.jsxs("button",{type:"button",onClick:()=>me("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 ${q?"text-cc-success":"text-cc-muted"}`,children:q?"On":"Off"})]})]})]})]}),e.jsxs("section",{id:"dashboard",ref:r("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:Ct,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 ${z?"text-cc-success":"text-cc-muted"}`,children:z?"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:Re,onChange:t=>{const a=Re;X(t.target.value),he({dashboardModel:t.target.value},()=>X(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:De,onChange:t=>{const a=De,c=Number(t.target.value);Z(c),he({dashboardRunHour:c},()=>Z(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:Oe,onChange:t=>{const a=Oe,c=Number(t.target.value);ee(c),he({dashboardMaxSessionsPerRun:c},()=>ee(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:"magic-ui",ref:r("magic-ui"),children:[e.jsx("h2",{className:"text-sm font-semibold text-cc-fg mb-4",children:"Magic UI"}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("p",{className:"text-xs text-cc-muted leading-relaxed",children:["An experimental session view: a cheap watcher model follows the session and paints a live, full-width dashboard — condensed progress, charts, open points, and decisions — instead of the classic chat column. Turning this on only makes the view"," ",e.jsx("em",{children:"available"}),"; each user still enables it per session from the top bar, and the watcher only runs for sessions that opted in. Uses the Claude Code CLI login — no separate API key."]}),!m&&e.jsx("p",{className:"text-xs text-cc-warning",children:"Requires the Claude Code CLI login — no Claude CLI was found on this server, so Magic UI stays unavailable."}),e.jsxs("button",{type:"button",onClick:St,disabled:!m,className:`w-full flex items-center justify-between px-3 py-3 min-h-[44px] rounded-lg bg-cc-hover text-cc-fg transition-colors ${m?"hover:bg-cc-active cursor-pointer":"opacity-50 cursor-not-allowed"}`,children:[e.jsx("span",{className:"text-sm",children:"Magic UI available to users"}),e.jsx("span",{className:`text-xs font-medium ${te&&m?"text-cc-success":"text-cc-muted"}`,children:te&&m?"On":"Off"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1.5",htmlFor:"magic-ui-model",children:"Watcher model"}),e.jsxs("select",{id:"magic-ui-model",value:Le,disabled:!m,onChange:t=>{const a=Le;ae(t.target.value),At(t.target.value,()=>ae(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 disabled:opacity-50",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:"The watcher runs many small turns per session — Haiku keeps it fast and cheap."})]})]})]}),e.jsxs("section",{id:"updates",ref:r("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:[i?e.jsxs("p",{className:"text-xs text-cc-muted",children:["Current version: v",i.currentVersion,i.latestVersion?` • Latest: v${i.latestVersion}`:"",i.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"){j("stable");try{await n.updateSettings({updateChannel:"stable"})}catch{j("prerelease");return}try{const t=await n.forceCheckForUpdate();O(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"){j("prerelease");try{await n.updateSettings({updateChannel:"prerelease"})}catch{j("stable");return}try{const t=await n.forceCheckForUpdate();O(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":A,onClick:async()=>{const t=!A;L(t);try{await n.updateSettings({dockerAutoUpdate:t})}catch{L(!t)}},className:`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${A?"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 ${A?"translate-x-5":"translate-x-0"}`})})]}),Pe&&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:Pe}),Ie&&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:Ie}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:Ut,disabled:B,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${B?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-hover hover:bg-cc-active text-cc-fg cursor-pointer"}`,children:B?"Checking...":"Check for updates"}),i!=null&&i.isServiceMode?e.jsx("button",{type:"button",onClick:Et,disabled:Q||i.updateInProgress||!i.updateAvailable,className:`px-3 py-2 min-h-[44px] rounded-lg text-sm font-medium transition-colors ${Q||i.updateInProgress||!i.updateAvailable?"bg-cc-hover text-cc-muted cursor-not-allowed":"bg-cc-primary hover:bg-cc-primary-hover text-white cursor-pointer"}`,children:Q||i.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:r("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=!Me;Mt(t),bt(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:Me?"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:r("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{Dt as SettingsPage};