claudedesk 4.3.1 → 4.4.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 (124) hide show
  1. package/.github/workflows/ci.yml +44 -2
  2. package/CLAUDE.md +36 -3
  3. package/PHASE_1_IMPLEMENTATION.md +313 -0
  4. package/PHASE_2_PARTIAL_IMPLEMENTATION.md +286 -0
  5. package/dist/main/cli-manager.js +67 -2
  6. package/dist/main/command-registry.js +196 -0
  7. package/dist/main/git-manager.js +841 -0
  8. package/dist/main/index.js +25 -1
  9. package/dist/main/ipc-handlers.js +347 -3
  10. package/dist/main/layout-presets-manager.js +233 -0
  11. package/dist/main/model-history-manager.js +187 -0
  12. package/dist/main/session-manager.js +83 -26
  13. package/dist/main/session-persistence.js +1 -0
  14. package/dist/main/session-pool.js +40 -9
  15. package/dist/main/settings-persistence.js +67 -12
  16. package/dist/renderer/assets/index-BNeYLqV4.css +32 -0
  17. package/dist/renderer/assets/index-D5O5Ljoo.js +17189 -0
  18. package/dist/renderer/index.html +2 -2
  19. package/dist/shared/ipc-contract.js +79 -0
  20. package/dist/shared/model-detector.js +83 -0
  21. package/dist/shared/types/command-types.js +5 -0
  22. package/dist/shared/types/git-types.js +2 -0
  23. package/dist/types/layout-presets.js +11 -0
  24. package/docs/git-integration-implementation-tasks.md +974 -0
  25. package/docs/git-integration-product-spec.md +916 -0
  26. package/docs/git-integration-ui-spec.md +1464 -0
  27. package/docs/repo-index.md +83 -8
  28. package/e2e/app-launch.spec.ts +31 -0
  29. package/e2e/fixtures/electron.ts +34 -0
  30. package/e2e/keyboard-shortcuts.spec.ts +50 -0
  31. package/e2e/session.spec.ts +34 -0
  32. package/e2e/split-view.spec.ts +21 -0
  33. package/package.json +16 -3
  34. package/playwright.config.ts +15 -0
  35. package/src/main/cli-manager.ts +74 -3
  36. package/src/main/command-registry.ts +221 -0
  37. package/src/main/git-manager.test.ts +374 -0
  38. package/src/main/git-manager.ts +909 -0
  39. package/src/main/index.ts +31 -1
  40. package/src/main/ipc-emitter.test.ts +60 -0
  41. package/src/main/ipc-handlers.ts +295 -3
  42. package/src/main/ipc-registry.test.ts +75 -0
  43. package/src/main/layout-presets-manager.ts +268 -0
  44. package/src/main/model-history-manager.ts +196 -0
  45. package/src/main/session-manager.ts +102 -30
  46. package/src/main/session-persistence.test.ts +215 -0
  47. package/src/main/session-persistence.ts +1 -0
  48. package/src/main/session-pool.ts +31 -9
  49. package/src/main/settings-persistence.ts +74 -12
  50. package/src/renderer/App.tsx +215 -43
  51. package/src/renderer/components/CustomLayoutBuilder.tsx +143 -0
  52. package/src/renderer/components/GitPanel.test.tsx +181 -0
  53. package/src/renderer/components/GitPanel.tsx +1407 -0
  54. package/src/renderer/components/LayoutPicker.tsx +182 -0
  55. package/src/renderer/components/LayoutPreviewCard.tsx +175 -0
  56. package/src/renderer/components/ModelHistoryPanel.tsx +435 -0
  57. package/src/renderer/components/PaneHeader.test.tsx +96 -0
  58. package/src/renderer/components/PaneHeader.tsx +28 -0
  59. package/src/renderer/components/SplitLayout.test.tsx +153 -0
  60. package/src/renderer/components/SplitLayout.tsx +36 -1
  61. package/src/renderer/components/Terminal.tsx +10 -10
  62. package/src/renderer/components/WelcomeWizard.tsx +143 -0
  63. package/src/renderer/components/WizardStepper.tsx +135 -0
  64. package/src/renderer/components/ui/ClaudeReadinessProgress.tsx +168 -0
  65. package/src/renderer/components/ui/CommitDialog.test.tsx +134 -0
  66. package/src/renderer/components/ui/CommitDialog.tsx +464 -0
  67. package/src/renderer/components/ui/EmptyState.test.tsx +87 -0
  68. package/src/renderer/components/ui/EmptyState.tsx +115 -86
  69. package/src/renderer/components/ui/FeatureShowcase.tsx +187 -0
  70. package/src/renderer/components/ui/FuelGaugeBar.tsx +59 -0
  71. package/src/renderer/components/ui/FuelStatusIndicator.tsx +358 -0
  72. package/src/renderer/components/ui/FuelTooltip.tsx +267 -0
  73. package/src/renderer/components/ui/HelpButton.tsx +43 -0
  74. package/src/renderer/components/ui/ModelBadge.tsx +72 -0
  75. package/src/renderer/components/ui/ModelSwitcher.tsx +180 -0
  76. package/src/renderer/components/ui/PanelFooter.tsx +90 -0
  77. package/src/renderer/components/ui/PanelHeader.tsx +87 -0
  78. package/src/renderer/components/ui/PanelHelpOverlay.tsx +274 -0
  79. package/src/renderer/components/ui/QuickActionCard.tsx +103 -0
  80. package/src/renderer/components/ui/RecentSessionsList.tsx +154 -0
  81. package/src/renderer/components/ui/SessionStatusIndicator.tsx +104 -0
  82. package/src/renderer/components/ui/SettingsDialog.tsx +94 -0
  83. package/src/renderer/components/ui/ShortcutsPanel.tsx +433 -0
  84. package/src/renderer/components/ui/StatusPopover.tsx +344 -0
  85. package/src/renderer/components/ui/TabBar.test.tsx +124 -0
  86. package/src/renderer/components/ui/TabBar.tsx +152 -168
  87. package/src/renderer/components/ui/ToolbarDropdown.tsx +227 -0
  88. package/src/renderer/components/ui/ToolsDropdown.tsx +119 -0
  89. package/src/renderer/components/ui/TooltipCoach.tsx +217 -0
  90. package/src/renderer/components/ui/WelcomeHero.tsx +85 -0
  91. package/src/renderer/components/ui/index.ts +5 -0
  92. package/src/renderer/components/wizard/Step1_Welcome.tsx +166 -0
  93. package/src/renderer/components/wizard/Step2_LayoutPicker.tsx +246 -0
  94. package/src/renderer/components/wizard/Step3_Features.tsx +278 -0
  95. package/src/renderer/components/wizard/Step4_Ready.tsx +279 -0
  96. package/src/renderer/hooks/useGit.test.ts +140 -0
  97. package/src/renderer/hooks/useGit.ts +395 -0
  98. package/src/renderer/hooks/useLayoutPicker.ts +77 -0
  99. package/src/renderer/hooks/useModelHistory.ts +69 -0
  100. package/src/renderer/hooks/useSessionManager.test.ts +146 -0
  101. package/src/renderer/hooks/useSessionManager.ts +5 -0
  102. package/src/renderer/hooks/useSplitView.test.ts +168 -0
  103. package/src/renderer/hooks/useSplitView.ts +126 -128
  104. package/src/renderer/styles/globals.css +505 -0
  105. package/src/renderer/utils/fuzzy-search.test.ts +121 -0
  106. package/src/renderer/utils/layout-tree.test.ts +310 -0
  107. package/src/renderer/utils/layout-tree.ts +170 -0
  108. package/src/renderer/utils/variable-resolver.test.ts +102 -0
  109. package/src/shared/ipc-contract.ts +157 -0
  110. package/src/shared/ipc-types.ts +52 -1
  111. package/src/shared/message-parser.test.ts +79 -0
  112. package/src/shared/model-detector.test.ts +90 -0
  113. package/src/shared/model-detector.ts +97 -0
  114. package/src/shared/types/command-types.ts +26 -0
  115. package/src/shared/types/git-types.ts +126 -0
  116. package/src/types/layout-presets.ts +22 -0
  117. package/test/helpers/electron-api-mock.ts +52 -0
  118. package/test/setup-main.ts +61 -0
  119. package/test/setup-renderer.ts +8 -0
  120. package/tsconfig.json +1 -0
  121. package/tsconfig.main.json +2 -1
  122. package/vitest.workspace.ts +37 -0
  123. package/dist/renderer/assets/index-CR22a7j2.css +0 -32
  124. package/dist/renderer/assets/index-Dp-eceNq.js +0 -13915
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:;" />
7
7
  <title>ClaudeDesk</title>
8
- <script type="module" crossorigin src="./assets/index-Dp-eceNq.js"></script>
9
- <link rel="stylesheet" crossorigin href="./assets/index-CR22a7j2.css">
8
+ <script type="module" crossorigin src="./assets/index-D5O5Ljoo.js"></script>
9
+ <link rel="stylesheet" crossorigin href="./assets/index-BNeYLqV4.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -24,6 +24,11 @@ exports.channels = {
24
24
  sendSessionInput: 'session:input',
25
25
  resizeSession: 'session:resize',
26
26
  sessionReady: 'session:ready',
27
+ // Model switching
28
+ switchModel: 'model:switch',
29
+ // Model History
30
+ getModelHistory: 'model:getHistory',
31
+ clearModelHistory: 'model:clearHistory',
27
32
  // Window controls
28
33
  minimizeWindow: 'window:minimize',
29
34
  maximizeWindow: 'window:maximize',
@@ -35,6 +40,7 @@ exports.channels = {
35
40
  onSessionUpdated: 'session:updated',
36
41
  onSessionOutput: 'session:output',
37
42
  onSessionExited: 'session:exited',
43
+ onModelChanged: 'model:changed',
38
44
  // Dialogs
39
45
  browseDirectory: 'dialog:browseDirectory',
40
46
  showSaveDialog: 'dialog:showSaveDialog',
@@ -97,6 +103,8 @@ exports.channels = {
97
103
  unlinkSessionFromTeam: 'teams:unlinkSession',
98
104
  closeTeam: 'teams:close',
99
105
  updateAutoLayoutTeams: 'settings:updateAutoLayout',
106
+ updateUIMode: 'settings:updateUIMode',
107
+ updateDefaultModel: 'settings:updateDefaultModel',
100
108
  // Agent Teams events
101
109
  onTeamDetected: 'teams:detected',
102
110
  onTeammateAdded: 'teams:teammateAdded',
@@ -108,8 +116,42 @@ exports.channels = {
108
116
  getAtlasStatus: 'atlas:getStatus',
109
117
  getAtlasSettings: 'atlas:getSettings',
110
118
  updateAtlasSettings: 'atlas:updateSettings',
119
+ // Command Registry
120
+ searchCommands: 'commands:search',
121
+ getAllCommands: 'commands:getAll',
122
+ executeCommand: 'commands:execute',
111
123
  // Repository Atlas events
112
124
  onAtlasScanProgress: 'atlas:scanProgress',
125
+ // Layout Presets
126
+ getLayoutPresets: 'layout:getPresets',
127
+ applyLayoutPreset: 'layout:apply',
128
+ applyCustomLayout: 'layout:applyCustom',
129
+ getCurrentLayout: 'layout:getCurrent',
130
+ // Git Integration
131
+ getGitStatus: 'git:status',
132
+ getGitBranches: 'git:branches',
133
+ gitStageFiles: 'git:stage',
134
+ gitUnstageFiles: 'git:unstage',
135
+ gitStageAll: 'git:stageAll',
136
+ gitUnstageAll: 'git:unstageAll',
137
+ gitCommit: 'git:commit',
138
+ gitGenerateMessage: 'git:generateMessage',
139
+ gitPush: 'git:push',
140
+ gitPull: 'git:pull',
141
+ gitFetch: 'git:fetch',
142
+ gitSwitchBranch: 'git:switchBranch',
143
+ gitCreateBranch: 'git:createBranch',
144
+ gitLog: 'git:log',
145
+ gitDiff: 'git:diff',
146
+ gitCommitDiff: 'git:commitDiff',
147
+ gitDiscardFile: 'git:discardFile',
148
+ gitDiscardAll: 'git:discardAll',
149
+ gitInit: 'git:init',
150
+ gitStartWatching: 'git:startWatching',
151
+ gitStopWatching: 'git:stopWatching',
152
+ // Git events
153
+ onGitStatusChanged: 'git:statusChanged',
154
+ onGitRemoteProgress: 'git:remoteProgress',
113
155
  // App info
114
156
  getVersionInfo: 'app:getVersionInfo',
115
157
  };
@@ -125,6 +167,9 @@ exports.contractKinds = {
125
167
  sendSessionInput: 'send',
126
168
  resizeSession: 'send',
127
169
  sessionReady: 'send',
170
+ switchModel: 'invoke',
171
+ getModelHistory: 'invoke',
172
+ clearModelHistory: 'invoke',
128
173
  minimizeWindow: 'send',
129
174
  maximizeWindow: 'send',
130
175
  closeWindow: 'send',
@@ -134,6 +179,7 @@ exports.contractKinds = {
134
179
  onSessionUpdated: 'event',
135
180
  onSessionOutput: 'event',
136
181
  onSessionExited: 'event',
182
+ onModelChanged: 'event',
137
183
  browseDirectory: 'invoke',
138
184
  showSaveDialog: 'invoke',
139
185
  writeFile: 'invoke',
@@ -157,6 +203,9 @@ exports.contractKinds = {
157
203
  addTemplate: 'invoke',
158
204
  updateTemplate: 'invoke',
159
205
  deleteTemplate: 'invoke',
206
+ searchCommands: 'invoke',
207
+ getAllCommands: 'invoke',
208
+ executeCommand: 'invoke',
160
209
  getFileInfo: 'invoke',
161
210
  readFileContent: 'invoke',
162
211
  listHistory: 'invoke',
@@ -185,6 +234,8 @@ exports.contractKinds = {
185
234
  unlinkSessionFromTeam: 'invoke',
186
235
  closeTeam: 'invoke',
187
236
  updateAutoLayoutTeams: 'invoke',
237
+ updateUIMode: 'invoke',
238
+ updateDefaultModel: 'invoke',
188
239
  onTeamDetected: 'event',
189
240
  onTeammateAdded: 'event',
190
241
  onTasksUpdated: 'event',
@@ -195,5 +246,33 @@ exports.contractKinds = {
195
246
  getAtlasSettings: 'invoke',
196
247
  updateAtlasSettings: 'invoke',
197
248
  onAtlasScanProgress: 'event',
249
+ getLayoutPresets: 'invoke',
250
+ applyLayoutPreset: 'invoke',
251
+ applyCustomLayout: 'invoke',
252
+ getCurrentLayout: 'invoke',
253
+ // Git Integration
254
+ getGitStatus: 'invoke',
255
+ getGitBranches: 'invoke',
256
+ gitStageFiles: 'invoke',
257
+ gitUnstageFiles: 'invoke',
258
+ gitStageAll: 'invoke',
259
+ gitUnstageAll: 'invoke',
260
+ gitCommit: 'invoke',
261
+ gitGenerateMessage: 'invoke',
262
+ gitPush: 'invoke',
263
+ gitPull: 'invoke',
264
+ gitFetch: 'invoke',
265
+ gitSwitchBranch: 'invoke',
266
+ gitCreateBranch: 'invoke',
267
+ gitLog: 'invoke',
268
+ gitDiff: 'invoke',
269
+ gitCommitDiff: 'invoke',
270
+ gitDiscardFile: 'invoke',
271
+ gitDiscardAll: 'invoke',
272
+ gitInit: 'invoke',
273
+ gitStartWatching: 'invoke',
274
+ gitStopWatching: 'invoke',
275
+ onGitStatusChanged: 'event',
276
+ onGitRemoteProgress: 'event',
198
277
  getVersionInfo: 'invoke',
199
278
  };
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ /**
3
+ * Model Detector — Parse terminal output to detect active Claude model
4
+ *
5
+ * Detects model switches from Claude Code CLI output in two phases:
6
+ * 1. Initial detection: Parse welcome screen for starting model
7
+ * 2. Switch detection: Parse /model command confirmations
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.detectModelFromOutput = detectModelFromOutput;
11
+ // Patterns for detecting model switches via /model command
12
+ const SWITCH_PATTERNS = [
13
+ /Set model to (?:Default )?\(?(Opus|Sonnet|Haiku)/i, // "Set model to Default (Opus 4.6..."
14
+ /Set model to (\w+)/i, // "Set model to opus (claude-opus-4-6)"
15
+ /Kept model as (?:Default )?\(?(Opus|Sonnet|Haiku)/i, // "Kept model as Default (recommended)"
16
+ /Kept model as (\w+)/i, // "Kept model as haiku"
17
+ /Switched to (?:claude[- ])?(\w+)/i,
18
+ /Now using (?:model: )?(\w+)/i,
19
+ /Model changed to (\w+)/i,
20
+ /Using model (\w+)/i,
21
+ ];
22
+ // Patterns for detecting initial model from welcome screen
23
+ // IMPORTANT: Pattern 0 requires "·" immediately after version to exclude promo text
24
+ // like "Opus 4.6 is here · $50 free extra usage" (which has "is here" before "·")
25
+ const WELCOME_PATTERNS = [
26
+ /(Opus|Sonnet|Haiku)\s+\d+\.\d+\s*·/i, // "Haiku 4.5 · Claude Max" (v2.1+ format, requires ·)
27
+ /Claude (?:3\.5 |4\.\d+ )?(Sonnet|Opus|Haiku)/i,
28
+ /\((Opus|Sonnet|Haiku)\s+\d+\.\d+/i, // "(Opus 4.6 · Most capable..."
29
+ /Using model[: ]+(\w+)/i,
30
+ /Model[: ]+(\w+)/i,
31
+ /\((\w+)\s+\d+\.\d+\)/i, // e.g., "(Sonnet 4.5)"
32
+ ];
33
+ /**
34
+ * Strip ANSI escape sequences from terminal output.
35
+ * Handles CSI sequences (\x1b[...X), OSC sequences (\x1b]...\x07), and single-char escapes.
36
+ */
37
+ function stripAnsi(text) {
38
+ return text
39
+ .replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '') // CSI sequences (colors, cursor, etc.)
40
+ .replace(/\x1b\][^\x07]*\x07/g, '') // OSC sequences (title, etc.)
41
+ .replace(/\x1b[()][A-Z0-9]/g, '') // Character set selection
42
+ .replace(/\x1b[=>]/g, ''); // Keypad mode
43
+ }
44
+ /**
45
+ * Detect model from terminal output.
46
+ *
47
+ * @param text - Terminal output to parse (raw PTY output with ANSI codes is OK)
48
+ * @param isInitial - True for welcome screen detection, false for switch detection
49
+ * @returns Detection result with confidence level
50
+ */
51
+ function detectModelFromOutput(text, isInitial = false) {
52
+ const clean = stripAnsi(text);
53
+ const patterns = isInitial ? WELCOME_PATTERNS : SWITCH_PATTERNS;
54
+ for (const pattern of patterns) {
55
+ const match = clean.match(pattern);
56
+ if (match) {
57
+ const raw = match[1].toLowerCase();
58
+ const normalized = normalizeModelName(raw);
59
+ if (normalized) {
60
+ return { model: normalized, confidence: 'high' };
61
+ }
62
+ }
63
+ }
64
+ return { model: null, confidence: 'low' };
65
+ }
66
+ /**
67
+ * Normalize raw model name to canonical ClaudeModel type.
68
+ */
69
+ function normalizeModelName(raw) {
70
+ const map = {
71
+ 'sonnet': 'sonnet',
72
+ '3.5-sonnet': 'sonnet',
73
+ '4-sonnet': 'sonnet',
74
+ 'opus': 'opus',
75
+ '3-opus': 'opus',
76
+ '4-opus': 'opus',
77
+ 'haiku': 'haiku',
78
+ '3-haiku': 'haiku',
79
+ '4-haiku': 'haiku',
80
+ 'auto': 'auto',
81
+ };
82
+ return map[raw] || null;
83
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Command types for enhanced command palette
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PRESET_IDS = void 0;
4
+ // Preset IDs (constants for easy reference)
5
+ exports.PRESET_IDS = {
6
+ SINGLE: 'single',
7
+ TWO_COLUMN: 'two-column',
8
+ THREE_COLUMN: 'three-column',
9
+ QUAD_GRID: 'quad-grid',
10
+ CUSTOM: 'custom',
11
+ };