@adhdev/daemon-core 0.5.3

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 (217) hide show
  1. package/dist/index.d.ts +2662 -0
  2. package/dist/index.js +11341 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +48 -0
  5. package/providers/_builtin/.github/workflows/generate-registry.yml +57 -0
  6. package/providers/_builtin/COMPATIBILITY.md +217 -0
  7. package/providers/_builtin/CONTRIBUTING.md +200 -0
  8. package/providers/_builtin/README.md +119 -0
  9. package/providers/_builtin/_helpers/index.js +188 -0
  10. package/providers/_builtin/acp/agentpool/provider.json +54 -0
  11. package/providers/_builtin/acp/amp/provider.json +52 -0
  12. package/providers/_builtin/acp/auggie/provider.json +57 -0
  13. package/providers/_builtin/acp/autodev/provider.json +54 -0
  14. package/providers/_builtin/acp/autohand/provider.json +52 -0
  15. package/providers/_builtin/acp/blackbox-ai/provider.json +54 -0
  16. package/providers/_builtin/acp/claude-agent/provider.json +57 -0
  17. package/providers/_builtin/acp/cline-acp/provider.json +54 -0
  18. package/providers/_builtin/acp/codebuddy/provider.json +54 -0
  19. package/providers/_builtin/acp/codex-cli/provider.json +57 -0
  20. package/providers/_builtin/acp/corust-agent/provider.json +52 -0
  21. package/providers/_builtin/acp/crow-cli/provider.json +54 -0
  22. package/providers/_builtin/acp/cursor-acp/provider.json +54 -0
  23. package/providers/_builtin/acp/deepagents/provider.json +52 -0
  24. package/providers/_builtin/acp/dimcode/provider.json +54 -0
  25. package/providers/_builtin/acp/docker-cagent/provider.json +57 -0
  26. package/providers/_builtin/acp/factory-droid/provider.json +60 -0
  27. package/providers/_builtin/acp/fast-agent/provider.json +52 -0
  28. package/providers/_builtin/acp/gemini-cli/provider.json +114 -0
  29. package/providers/_builtin/acp/github-copilot/provider.json +54 -0
  30. package/providers/_builtin/acp/goose/provider.json +57 -0
  31. package/providers/_builtin/acp/junie/provider.json +52 -0
  32. package/providers/_builtin/acp/kilo/provider.json +54 -0
  33. package/providers/_builtin/acp/kimi-cli/provider.json +57 -0
  34. package/providers/_builtin/acp/minion-code/provider.json +52 -0
  35. package/providers/_builtin/acp/mistral-vibe/provider.json +57 -0
  36. package/providers/_builtin/acp/nova/provider.json +54 -0
  37. package/providers/_builtin/acp/openclaw/provider.json +54 -0
  38. package/providers/_builtin/acp/opencode/provider.json +52 -0
  39. package/providers/_builtin/acp/openhands/provider.json +54 -0
  40. package/providers/_builtin/acp/pi-acp/provider.json +52 -0
  41. package/providers/_builtin/acp/qoder/provider.json +54 -0
  42. package/providers/_builtin/acp/qwen-code/provider.json +60 -0
  43. package/providers/_builtin/acp/stakpak/provider.json +54 -0
  44. package/providers/_builtin/acp/vtcode/provider.json +54 -0
  45. package/providers/_builtin/cli/claude-cli/provider.json +100 -0
  46. package/providers/_builtin/cli/codex-cli/provider.json +89 -0
  47. package/providers/_builtin/cli/gemini-cli/provider.json +93 -0
  48. package/providers/_builtin/docs/CDP_SELECTOR_GUIDE.md +370 -0
  49. package/providers/_builtin/docs/PROVIDER_GUIDE.md +916 -0
  50. package/providers/_builtin/extension/cline/provider.json +35 -0
  51. package/providers/_builtin/extension/cline/scripts/focus_editor.js +48 -0
  52. package/providers/_builtin/extension/cline/scripts/list_chats.js +100 -0
  53. package/providers/_builtin/extension/cline/scripts/list_models.js +43 -0
  54. package/providers/_builtin/extension/cline/scripts/list_modes.js +35 -0
  55. package/providers/_builtin/extension/cline/scripts/new_session.js +85 -0
  56. package/providers/_builtin/extension/cline/scripts/open_panel.js +25 -0
  57. package/providers/_builtin/extension/cline/scripts/read_chat.js +257 -0
  58. package/providers/_builtin/extension/cline/scripts/resolve_action.js +83 -0
  59. package/providers/_builtin/extension/cline/scripts/send_message.js +95 -0
  60. package/providers/_builtin/extension/cline/scripts/set_mode.js +36 -0
  61. package/providers/_builtin/extension/cline/scripts/set_model.js +36 -0
  62. package/providers/_builtin/extension/cline/scripts/switch_session.js +206 -0
  63. package/providers/_builtin/extension/cline/scripts.js +73 -0
  64. package/providers/_builtin/extension/roo-code/provider.json +35 -0
  65. package/providers/_builtin/extension/roo-code/scripts.js +659 -0
  66. package/providers/_builtin/ide/antigravity/provider.json +68 -0
  67. package/providers/_builtin/ide/antigravity/scripts/1.106/focus_editor.js +20 -0
  68. package/providers/_builtin/ide/antigravity/scripts/1.106/list_chats.js +137 -0
  69. package/providers/_builtin/ide/antigravity/scripts/1.106/list_models.js +38 -0
  70. package/providers/_builtin/ide/antigravity/scripts/1.106/list_modes.js +48 -0
  71. package/providers/_builtin/ide/antigravity/scripts/1.106/new_session.js +75 -0
  72. package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +262 -0
  73. package/providers/_builtin/ide/antigravity/scripts/1.106/resolve_action.js +68 -0
  74. package/providers/_builtin/ide/antigravity/scripts/1.106/scripts.js +57 -0
  75. package/providers/_builtin/ide/antigravity/scripts/1.106/send_message.js +56 -0
  76. package/providers/_builtin/ide/antigravity/scripts/1.106/set_mode.js +34 -0
  77. package/providers/_builtin/ide/antigravity/scripts/1.106/set_model.js +47 -0
  78. package/providers/_builtin/ide/antigravity/scripts/1.106/switch_session.js +114 -0
  79. package/providers/_builtin/ide/antigravity/scripts/1.107/focus_editor.js +20 -0
  80. package/providers/_builtin/ide/antigravity/scripts/1.107/list_chats.js +137 -0
  81. package/providers/_builtin/ide/antigravity/scripts/1.107/list_models.js +61 -0
  82. package/providers/_builtin/ide/antigravity/scripts/1.107/list_modes.js +72 -0
  83. package/providers/_builtin/ide/antigravity/scripts/1.107/new_session.js +75 -0
  84. package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +262 -0
  85. package/providers/_builtin/ide/antigravity/scripts/1.107/resolve_action.js +68 -0
  86. package/providers/_builtin/ide/antigravity/scripts/1.107/scripts.js +67 -0
  87. package/providers/_builtin/ide/antigravity/scripts/1.107/send_message.js +56 -0
  88. package/providers/_builtin/ide/antigravity/scripts/1.107/set_mode.js +67 -0
  89. package/providers/_builtin/ide/antigravity/scripts/1.107/set_model.js +72 -0
  90. package/providers/_builtin/ide/antigravity/scripts/1.107/switch_session.js +114 -0
  91. package/providers/_builtin/ide/cursor/provider.json +70 -0
  92. package/providers/_builtin/ide/cursor/scripts/0.49/dismiss_notification.js +30 -0
  93. package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +13 -0
  94. package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +78 -0
  95. package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +40 -0
  96. package/providers/_builtin/ide/cursor/scripts/0.49/list_notifications.js +23 -0
  97. package/providers/_builtin/ide/cursor/scripts/0.49/list_sessions.js +42 -0
  98. package/providers/_builtin/ide/cursor/scripts/0.49/new_session.js +20 -0
  99. package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +23 -0
  100. package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +75 -0
  101. package/providers/_builtin/ide/cursor/scripts/0.49/resolve_action.js +19 -0
  102. package/providers/_builtin/ide/cursor/scripts/0.49/scripts.js +78 -0
  103. package/providers/_builtin/ide/cursor/scripts/0.49/send_message.js +23 -0
  104. package/providers/_builtin/ide/cursor/scripts/0.49/set_mode.js +38 -0
  105. package/providers/_builtin/ide/cursor/scripts/0.49/set_model.js +81 -0
  106. package/providers/_builtin/ide/cursor/scripts/0.49/switch_session.js +28 -0
  107. package/providers/_builtin/ide/kiro/provider.json +67 -0
  108. package/providers/_builtin/ide/kiro/scripts/focus_editor.js +20 -0
  109. package/providers/_builtin/ide/kiro/scripts/open_panel.js +47 -0
  110. package/providers/_builtin/ide/kiro/scripts/resolve_action.js +54 -0
  111. package/providers/_builtin/ide/kiro/scripts/send_message.js +29 -0
  112. package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +39 -0
  113. package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +39 -0
  114. package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +21 -0
  115. package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +34 -0
  116. package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +68 -0
  117. package/providers/_builtin/ide/kiro/scripts/webview_send_message.js +72 -0
  118. package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +15 -0
  119. package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +15 -0
  120. package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +26 -0
  121. package/providers/_builtin/ide/kiro/scripts.js +62 -0
  122. package/providers/_builtin/ide/pearai/provider.json +67 -0
  123. package/providers/_builtin/ide/pearai/scripts/focus_editor.js +20 -0
  124. package/providers/_builtin/ide/pearai/scripts/list_sessions.js +38 -0
  125. package/providers/_builtin/ide/pearai/scripts/new_session.js +55 -0
  126. package/providers/_builtin/ide/pearai/scripts/open_panel.js +46 -0
  127. package/providers/_builtin/ide/pearai/scripts/resolve_action.js +54 -0
  128. package/providers/_builtin/ide/pearai/scripts/send_message.js +29 -0
  129. package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +43 -0
  130. package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +35 -0
  131. package/providers/_builtin/ide/pearai/scripts/webview_list_sessions.js +62 -0
  132. package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +49 -0
  133. package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +92 -0
  134. package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +59 -0
  135. package/providers/_builtin/ide/pearai/scripts/webview_send_message.js +72 -0
  136. package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +36 -0
  137. package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +36 -0
  138. package/providers/_builtin/ide/pearai/scripts/webview_switch_session.js +34 -0
  139. package/providers/_builtin/ide/pearai/scripts.js +74 -0
  140. package/providers/_builtin/ide/trae/provider.json +66 -0
  141. package/providers/_builtin/ide/trae/scripts/focus_editor.js +20 -0
  142. package/providers/_builtin/ide/trae/scripts/list_chats.js +24 -0
  143. package/providers/_builtin/ide/trae/scripts/list_models.js +39 -0
  144. package/providers/_builtin/ide/trae/scripts/list_modes.js +39 -0
  145. package/providers/_builtin/ide/trae/scripts/new_session.js +30 -0
  146. package/providers/_builtin/ide/trae/scripts/open_panel.js +44 -0
  147. package/providers/_builtin/ide/trae/scripts/read_chat.js +113 -0
  148. package/providers/_builtin/ide/trae/scripts/resolve_action.js +54 -0
  149. package/providers/_builtin/ide/trae/scripts/send_message.js +69 -0
  150. package/providers/_builtin/ide/trae/scripts/set_mode.js +15 -0
  151. package/providers/_builtin/ide/trae/scripts/set_model.js +15 -0
  152. package/providers/_builtin/ide/trae/scripts/switch_session.js +23 -0
  153. package/providers/_builtin/ide/trae/scripts.js +57 -0
  154. package/providers/_builtin/ide/vscode/provider.json +64 -0
  155. package/providers/_builtin/ide/vscode-insiders/provider.json +62 -0
  156. package/providers/_builtin/ide/vscodium/provider.json +63 -0
  157. package/providers/_builtin/ide/windsurf/provider.json +53 -0
  158. package/providers/_builtin/ide/windsurf/scripts/focus_editor.js +30 -0
  159. package/providers/_builtin/ide/windsurf/scripts/list_chats.js +117 -0
  160. package/providers/_builtin/ide/windsurf/scripts/list_models.js +39 -0
  161. package/providers/_builtin/ide/windsurf/scripts/list_modes.js +39 -0
  162. package/providers/_builtin/ide/windsurf/scripts/new_session.js +69 -0
  163. package/providers/_builtin/ide/windsurf/scripts/open_panel.js +58 -0
  164. package/providers/_builtin/ide/windsurf/scripts/read_chat.js +297 -0
  165. package/providers/_builtin/ide/windsurf/scripts/resolve_action.js +68 -0
  166. package/providers/_builtin/ide/windsurf/scripts/send_message.js +87 -0
  167. package/providers/_builtin/ide/windsurf/scripts/set_mode.js +15 -0
  168. package/providers/_builtin/ide/windsurf/scripts/set_model.js +15 -0
  169. package/providers/_builtin/ide/windsurf/scripts/switch_session.js +58 -0
  170. package/providers/_builtin/ide/windsurf/scripts.js +57 -0
  171. package/providers/_builtin/registry.json +266 -0
  172. package/providers/_builtin/validate.js +156 -0
  173. package/src/agent-stream/index.ts +6 -0
  174. package/src/agent-stream/manager.ts +286 -0
  175. package/src/agent-stream/poller.ts +154 -0
  176. package/src/agent-stream/provider-adapter.ts +138 -0
  177. package/src/agent-stream/types.ts +61 -0
  178. package/src/boot/daemon-lifecycle.ts +252 -0
  179. package/src/cdp/devtools.ts +335 -0
  180. package/src/cdp/initializer.ts +191 -0
  181. package/src/cdp/manager.ts +897 -0
  182. package/src/cdp/scanner.ts +185 -0
  183. package/src/cdp/setup.ts +150 -0
  184. package/src/cli-adapter-types.ts +25 -0
  185. package/src/cli-adapters/provider-cli-adapter.ts +448 -0
  186. package/src/commands/cdp-commands.ts +208 -0
  187. package/src/commands/chat-commands.ts +675 -0
  188. package/src/commands/cli-manager.ts +353 -0
  189. package/src/commands/handler.ts +328 -0
  190. package/src/commands/router.ts +258 -0
  191. package/src/commands/stream-commands.ts +325 -0
  192. package/src/config/chat-history.ts +211 -0
  193. package/src/config/config.ts +219 -0
  194. package/src/daemon/dev-server.ts +2378 -0
  195. package/src/daemon/scaffold-template.ts +394 -0
  196. package/src/daemon-core.ts +50 -0
  197. package/src/detection/cli-detector.ts +89 -0
  198. package/src/detection/ide-detector.ts +157 -0
  199. package/src/index.ts +103 -0
  200. package/src/installer.ts +263 -0
  201. package/src/ipc-protocol.ts +133 -0
  202. package/src/launch.ts +433 -0
  203. package/src/logging/command-log.ts +180 -0
  204. package/src/logging/logger.ts +316 -0
  205. package/src/providers/acp-provider-instance.ts +1140 -0
  206. package/src/providers/cli-provider-instance.ts +207 -0
  207. package/src/providers/contracts.ts +524 -0
  208. package/src/providers/extension-provider-instance.ts +156 -0
  209. package/src/providers/ide-provider-instance.ts +377 -0
  210. package/src/providers/index.ts +18 -0
  211. package/src/providers/provider-instance-manager.ts +182 -0
  212. package/src/providers/provider-instance.ts +112 -0
  213. package/src/providers/provider-loader.ts +1031 -0
  214. package/src/providers/status-monitor.ts +125 -0
  215. package/src/providers/version-archive.ts +266 -0
  216. package/src/status/reporter.ts +294 -0
  217. package/src/types.ts +206 -0
@@ -0,0 +1,916 @@
1
+ # ADHDev Provider Creation Guide
2
+
3
+ > Complete guide for adding new IDE, Extension, CLI, and ACP providers to ADHDev.
4
+ > **Just create `provider.json` + `scripts.js` — no TypeScript modifications needed.**
5
+
6
+ ---
7
+
8
+ ## 🏗️ Provider Architecture
9
+
10
+ ```
11
+ provider.js created (ide/cli/extension/acp)
12
+
13
+
14
+ ProviderLoader.loadAll() ← 3-tier priority loading
15
+
16
+ ├─ 1. _builtin/ (npm bundle — offline fallback)
17
+ ├─ 2. .upstream/ (GitHub auto-download — checked every 30min)
18
+ └─ 3. ~/.adhdev/providers/ (user custom — highest priority, never auto-updated)
19
+
20
+ ├─ registerToDetector() ← IDE: installation detection (paths, cli)
21
+ ├─ getCdpPortMap() ← IDE: CDP port auto-assignment
22
+ ├─ getCliDetectionList() ← CLI/ACP: installation detection (spawn.command)
23
+ ├─ resolveAlias() ← alias resolution ('claude' → 'claude-cli')
24
+ └─ fetchLatest() ← GitHub tarball auto-download
25
+ ```
26
+
27
+ ### Loading Priority (later overrides earlier)
28
+
29
+ | Priority | Directory | Auto-update | Purpose |
30
+ |----------|-----------|-------------|---------|
31
+ | 1 (lowest) | `packages/launcher/providers/_builtin/` | npm update only | Offline fallback |
32
+ | 2 | `~/.adhdev/providers/.upstream/` | ✅ On daemon start | Latest GitHub providers |
33
+ | 3 (highest) | `~/.adhdev/providers/` (excl. _upstream) | ❌ **Never** | User custom |
34
+
35
+ ### Auto-update Flow
36
+
37
+ ```
38
+ adhdev daemon start
39
+ ├─ loadAll() → builtin + .upstream + user custom loaded immediately
40
+ └─ background: fetchLatest()
41
+ ├─ HEAD request → ETag comparison
42
+ ├─ no change → skip (zero network cost)
43
+ └─ changed → download tarball → replace .upstream/ → reload()
44
+ ```
45
+
46
+ > [!IMPORTANT]
47
+ > **User custom protection**: provider.js files you create directly in `~/.adhdev/providers/`
48
+ > are never auto-updated under any circumstances. Only `.upstream/` is auto-replaced,
49
+ > and user custom always takes priority.
50
+
51
+ ---
52
+
53
+ ## 📁 Directory Structure
54
+
55
+ ```
56
+ providers/_builtin/ide/
57
+ ├── cursor/ ← reference implementation
58
+ │ ├── provider.json ← metadata (type, name, cdpPorts, etc.)
59
+ │ └── scripts.js ← CDP scripts (readChat, sendMessage, etc.)
60
+ ├── windsurf/ ← file-split script pattern
61
+ │ ├── provider.json
62
+ │ ├── scripts.js ← loads from scripts/ folder
63
+ │ └── scripts/
64
+ │ ├── read_chat.js
65
+ │ ├── send_message.js
66
+ │ └── ...
67
+ ├── antigravity/
68
+ │ ├── provider.json
69
+ │ └── scripts.js
70
+ ├── vscode/
71
+ │ └── provider.json ← infrastructure only (scripts not yet implemented)
72
+ └── [your-ide]/ ← new provider location
73
+ ├── provider.json ← required
74
+ └── scripts.js ← required for IDE/Extension, not needed for CLI/ACP
75
+ ```
76
+
77
+ ---
78
+
79
+ ## 1️⃣ provider.js Basic Structure
80
+
81
+ > [!IMPORTANT]
82
+ > `provider.json` contains static metadata. `scripts.js` exports CDP script functions.
83
+ > Type definitions: [contracts.ts](file:///Users/vilmire/Work/remote_vs/packages/daemon-core/src/providers/contracts.ts)
84
+
85
+ **provider.json:**
86
+ ```json
87
+ {
88
+ "type": "my-ide",
89
+ "name": "My IDE",
90
+ "category": "ide",
91
+ "displayName": "My IDE",
92
+ "icon": "🔧",
93
+ "cli": "my-ide",
94
+ "cdpPorts": [9357, 9358],
95
+ "processNames": { "darwin": "My IDE" },
96
+ "paths": { "darwin": ["/Applications/My IDE.app"] },
97
+ "inputMethod": "cdp-type-and-send",
98
+ "inputSelector": "[contenteditable=\"true\"][role=\"textbox\"]",
99
+ "versionCommand": "my-ide --version",
100
+ "testedVersions": ["1.0.0", "1.1.0"]
101
+ }
102
+ ```
103
+
104
+ **scripts.js:**
105
+ ```javascript
106
+ module.exports.readChat = function readChat(params) {
107
+ return `(() => {
108
+ // CDP JS code to extract chat messages
109
+ return JSON.stringify({ id: 'active', status: 'idle', messages: [], inputContent: '' });
110
+ })()`;
111
+ };
112
+
113
+ module.exports.sendMessage = function sendMessage(params) {
114
+ const text = typeof params === 'string' ? params : params?.text;
115
+ return `(() => {
116
+ return JSON.stringify({ sent: false, needsTypeAndSend: true, selector: '[contenteditable]' });
117
+ })()`;
118
+ };
119
+ // ... more scripts
120
+ ```
121
+
122
+ ### CDP Ports Already In Use
123
+
124
+ | Port | Provider |
125
+ |------|----------|
126
+ | 9333-9334 | Cursor |
127
+ | 9335-9336 | Antigravity |
128
+ | 9337-9338 | Windsurf |
129
+ | 9339-9340 | VS Code |
130
+ | 9341-9342 | VS Code Insiders |
131
+ | 9343-9344 | VSCodium |
132
+ | 9351-9352 | Kiro |
133
+ | 9353-9354 | Trae |
134
+ | 9355-9356 | PearAI |
135
+
136
+ > [!WARNING]
137
+ > When adding a new provider, **avoid overlapping with existing ports** — use 9357 and above.
138
+
139
+ ### aliases Field
140
+
141
+ Defining `aliases` enables usage in `adhdev launch <alias>` etc.
142
+ No need to add alias maps in TypeScript code — just declare in provider.js.
143
+
144
+ ```javascript
145
+ // CLI example
146
+ module.exports = {
147
+ type: 'claude-cli',
148
+ aliases: ['claude', 'claude-code'], // adhdev launch claude → resolves to claude-cli
149
+ // ...
150
+ };
151
+
152
+ // IDE example (optional)
153
+ module.exports = {
154
+ type: 'vscode',
155
+ aliases: ['code', 'vs'], // adhdev launch code → resolves to vscode
156
+ // ...
157
+ };
158
+ ```
159
+
160
+ ---
161
+
162
+ ## 2️⃣ Script Implementation — Two Patterns
163
+
164
+ ### Pattern A: Inline (Cursor style)
165
+
166
+ Write directly inside `provider.js` using template literals.
167
+
168
+ ```javascript
169
+ scripts: {
170
+ readChat(params) {
171
+ return `(() => {
172
+ try {
173
+ // ... CDP JS code ...
174
+ return JSON.stringify({ id, status, messages, inputContent, activeModal });
175
+ } catch(e) {
176
+ return JSON.stringify({ id: '', status: 'error', messages: [] });
177
+ }
178
+ })()`;
179
+ },
180
+ }
181
+ ```
182
+
183
+ **Pros:** Self-contained in one file, natural parameter substitution (`${JSON.stringify(text)}`)
184
+ **Cons:** Hard to manage when code grows long, no syntax highlighting
185
+
186
+ ### Pattern B: File Separation (Windsurf style)
187
+
188
+ Place individual `.js` files in `scripts/` folder and load with `loadScript()`.
189
+
190
+ ```javascript
191
+ const fs = require('fs');
192
+ const path = require('path');
193
+ const SCRIPTS_DIR = path.join(__dirname, 'scripts');
194
+
195
+ function loadScript(name) {
196
+ try { return fs.readFileSync(path.join(SCRIPTS_DIR, name), 'utf8'); }
197
+ catch { return null; }
198
+ }
199
+
200
+ // scripts object
201
+ scripts: {
202
+ readChat() { return loadScript('read_chat.js'); },
203
+ sendMessage(params) {
204
+ const text = typeof params === 'string' ? params : params?.text;
205
+ const s = loadScript('send_message.js');
206
+ return s ? s.replace(/\$\{\s*MESSAGE\s*\}/g, JSON.stringify(text)) : null;
207
+ },
208
+ }
209
+ ```
210
+
211
+ **Pros:** Syntax highlighting, easy to edit/test individually in DevConsole
212
+ **Cons:** Requires file management, needs `${MESSAGE}` placeholder for parameter substitution
213
+
214
+ > [!TIP]
215
+ > For scripts under 30 lines, use **inline**; for longer scripts, use **file separation**.
216
+
217
+ ---
218
+
219
+ ## 3️⃣ Script Output Contract
220
+
221
+ All scripts **must return a JSON string**.
222
+ See [contracts.ts](file:///Users/vilmire/Work/remote_vs/packages/launcher/src/providers/contracts.ts) for reference.
223
+
224
+ ### Core Scripts
225
+
226
+ #### readChat(params?) → `ReadChatResult`
227
+ ```typescript
228
+ {
229
+ id: string; // session ID
230
+ status: AgentStatus; // 'idle' | 'generating' | 'waiting_approval' | 'error'
231
+ messages: ChatMessage[]; // { role, content, index }
232
+ title?: string;
233
+ inputContent?: string; // current input field text
234
+ activeModal?: { // pending approval modal
235
+ message: string;
236
+ buttons: string[];
237
+ } | null;
238
+ }
239
+ ```
240
+
241
+ #### sendMessage(params) → `SendMessageResult`
242
+ ```typescript
243
+ {
244
+ sent: boolean;
245
+ error?: string;
246
+ needsTypeAndSend?: boolean; // true → daemon types via CDP Input API
247
+ selector?: string; // target selector when needsTypeAndSend
248
+ }
249
+ ```
250
+
251
+ #### listSessions(params?) → `ListSessionsResult`
252
+ ```typescript
253
+ { sessions: [{ id: string, title: string, active?: boolean, index?: number }] }
254
+ ```
255
+
256
+ #### switchSession(params) → `SwitchSessionResult`
257
+ ```typescript
258
+ { switched: boolean, error?: string, title?: string }
259
+ ```
260
+
261
+ #### newSession(params?) → `{ created: boolean, error?: string }`
262
+
263
+ ### UI Control Scripts
264
+
265
+ #### focusEditor(params?) → `string` (e.g., `'focused'`, `'not_found'`)
266
+ #### openPanel(params?) → `string` (e.g., `'visible'`, `'opened'`, `'not_found'`)
267
+
268
+ ### Modal/Approval Scripts
269
+
270
+ #### resolveAction(params) — Two return methods
271
+
272
+ ```typescript
273
+ // params: { action: 'approve'|'reject'|'custom', button?: string, buttonText?: string }
274
+ ```
275
+
276
+ **Method 1: Script-Click** — script calls `el.click()` directly (Cursor etc.)
277
+
278
+ ```js
279
+ // Cursor uses div.cursor-pointer elements, so direct click works
280
+ return JSON.stringify({ resolved: true, clicked: "Run⏎" });
281
+ return JSON.stringify({ resolved: false, available: ["Send", "Cancel"] });
282
+ ```
283
+
284
+ **Method 2: Coordinate-Click** — return coordinates → daemon performs CDP mouse click (Antigravity etc.)
285
+
286
+ ```js
287
+ // When el.click() doesn't propagate events properly, return coordinates
288
+ return JSON.stringify({ found: true, text: "Accept", x: 800, y: 450, w: 120, h: 32 });
289
+ return JSON.stringify({ found: false });
290
+ ```
291
+
292
+ > [!IMPORTANT]
293
+ > Daemon processing order: `resolved: true` → success / `found: true` + `x,y` → CDP click / neither → fail
294
+
295
+ #### Approval Detection (waiting_approval in readChat)
296
+
297
+ Each IDE has different approval UI, so each provider's readChat must detect appropriately:
298
+
299
+ | IDE | Detection method |
300
+ |-----|-----------------|
301
+ | Cursor | `.run-command-review-active` CSS class + `div.cursor-pointer` buttons (`Run⏎`, `SkipEsc`) |
302
+ | Antigravity | `<button>` text matching (`Allow This Conversation`, `Deny` etc.) |
303
+ | Windsurf | Fiber props or button text |
304
+
305
+ > [!TIP]
306
+ > In Cursor 2.6.19+, approval buttons are `<div class="cursor-pointer">` not `<button>`,
307
+ > and button text includes keyboard shortcuts (e.g., `"Run⏎"`, `"SkipEsc"`).
308
+
309
+ #### listNotifications(params?) → `Array<{ index, message, severity, buttons }>`
310
+ #### dismissNotification(params) → `{ dismissed: boolean, error?: string }`
311
+
312
+ ### Model / Mode Scripts
313
+
314
+ #### listModels(params?) → `{ models: string[], current: string }`
315
+ #### setModel(params) → `{ success: boolean, model?: string, error?: string }`
316
+ #### listModes(params?) → `{ modes: string[], current: string }`
317
+ #### setMode(params) → `{ success: boolean, mode?: string, error?: string }`
318
+
319
+ > [!NOTE]
320
+ > Webview-based IDEs (Kiro, PearAI) use `webviewListModels`, `webviewSetModel` etc. with webview prefix scripts.
321
+ > `handleExtensionScript` automatically prioritizes webview variants when they exist.
322
+
323
+
324
+ ---
325
+
326
+ ## 3½. Daemon Routing Logic — What provider.js Controls
327
+
328
+ > [!IMPORTANT]
329
+ > The daemon (daemon-commands.ts) **does not branch by IDE name.**
330
+ > All routing is determined by **properties and script return values** defined in provider.js.
331
+
332
+ ### Automatic Routing by IDE Type
333
+
334
+ ```
335
+ daemon receives command (readChat, sendMessage, etc.)
336
+
337
+ ├─ provider.category === 'cli' or 'acp'?
338
+ │ └─ CLI/ACP adapter (stdin/stdout JSON-RPC)
339
+
340
+ ├─ provider.category === 'extension'?
341
+ │ └─ AgentStream → webview iframe execution
342
+
343
+ └─ provider.category === 'ide'?
344
+
345
+ ├─ scripts.webviewReadChat exists? (★ webview IDE)
346
+ │ └─ evaluateInWebviewFrame() → JS runs inside webview iframe
347
+ │ └─ provider.webviewMatchText matches correct iframe
348
+
349
+ └─ scripts.readChat only? (★ mainframe IDE)
350
+ └─ cdp.evaluate() → JS runs in mainframe
351
+ └─ provider.inputMethod determines input method
352
+ ```
353
+
354
+ ### Mainframe IDE vs Webview IDE Differences
355
+
356
+ | Property | Mainframe (Cursor, Windsurf, Trae) | Webview (Kiro, PearAI) |
357
+ |----------|-------------------------------------|------------------------|
358
+ | `inputMethod` | `'cdp-type-and-send'` | none (handled in webview script) |
359
+ | `inputSelector` | `'[contenteditable="true"]...'` | none |
360
+ | `webviewMatchText` | none | `'Kiro'` etc. (iframe body match text) |
361
+ | Script names | `readChat`, `sendMessage` | `webviewReadChat`, `webviewSendMessage` |
362
+ | Execution context | IDE main frame DOM | webview iframe internal DOM |
363
+
364
+ ### Creating a Mainframe IDE
365
+
366
+ ```javascript
367
+ module.exports = {
368
+ type: 'my-ide',
369
+ category: 'ide',
370
+ inputMethod: 'cdp-type-and-send', // ← this determines mainframe mode
371
+ inputSelector: '[contenteditable="true"][role="textbox"]',
372
+ scripts: {
373
+ readChat() { return `(() => { ... })()`; },
374
+ sendMessage(text) {
375
+ // needsTypeAndSend: true → daemon types via CDP into inputSelector
376
+ return `(() => JSON.stringify({ sent: false, needsTypeAndSend: true }))()`;
377
+ },
378
+ },
379
+ };
380
+ ```
381
+
382
+ ### Creating a Webview IDE
383
+
384
+ ```javascript
385
+ module.exports = {
386
+ type: 'my-webview-ide',
387
+ category: 'ide',
388
+ webviewMatchText: 'MyWebviewApp', // ← matches if iframe body contains this text
389
+ // no inputMethod! handled directly inside webview
390
+ scripts: {
391
+ // webview prefix → auto-routed to evaluateInWebviewFrame()
392
+ webviewReadChat() { return `(() => { ... })()`; },
393
+ webviewSendMessage(text) { return `(() => { ... })()`; },
394
+ webviewListSessions() { return `(() => { ... })()`; },
395
+
396
+ // scripts to run in mainframe (open panel etc.)
397
+ openPanel() { return `(() => { ... })()`; },
398
+ focusEditor() { return `(() => { ... })()`; },
399
+ },
400
+ };
401
+ ```
402
+
403
+ ### Daemon Behavior Based on sendMessage Return Values
404
+
405
+ | Return value | Daemon action |
406
+ |-------------|---------------|
407
+ | `{ sent: true }` | Done (script sent directly) |
408
+ | `{ sent: false, needsTypeAndSend: true }` | CDP type + Enter into `inputSelector` |
409
+ | `{ sent: false, needsTypeAndSend: true, selector: '...' }` | Type into specified selector |
410
+ | `{ sent: false, needsTypeAndSend: true, clickCoords: {x,y} }` | Click coordinates then type |
411
+
412
+ ### Daemon Behavior Based on resolveAction Return Values
413
+
414
+ | Return value | Daemon action |
415
+ |-------------|---------------|
416
+ | `{ resolved: true }` | Done (script clicked directly) |
417
+ | `{ found: true, x, y, w, h }` | CDP mouse click (coordinate-based) |
418
+ | `{ resolved: false }` / `{ found: false }` | Failed |
419
+
420
+ > [!TIP]
421
+ > When adding a new IDE, **you don't need to read TS code.**
422
+ > Just set the correct properties in provider.js and the daemon automatically picks the right path.
423
+
424
+ ---
425
+
426
+ ## 4️⃣ Development Workflow (Using DevConsole)
427
+
428
+ ### Step 1: Launch IDE in CDP Mode
429
+
430
+ ```bash
431
+ # Example: Cursor
432
+ adhdev launch cursor --cdp
433
+
434
+ # Or re-launch existing IDE with CDP port
435
+ /Applications/MyIDE.app/Contents/MacOS/MyIDE --remote-debugging-port=9350
436
+ ```
437
+
438
+ ### Step 2: Open DevConsole
439
+
440
+ ```bash
441
+ adhdev daemon --dev
442
+ # Open http://127.0.0.1:19280 in browser
443
+ ```
444
+
445
+ ### Step 3: DOM Exploration and Script Writing
446
+
447
+ 1. **📸 Screenshot** button to capture current IDE screen
448
+ 2. **CSS selector** input field to explore elements (`Query` button)
449
+ 3. **🖥 Editor** tab to write CDP JS code → **▶ Run** for immediate testing
450
+ 4. Copy tested code to `provider.js`
451
+
452
+ ### Step 4: Using Script Edit Mode
453
+
454
+ 1. **📜 Scripts ▾** dropdown → click script name → enter edit mode
455
+ 2. Modify code → **▶ Run** to test directly and check Output
456
+ 3. When satisfied → **💾 Save Script** button to save to `provider.js`
457
+
458
+ ### Step 5: Scripts Requiring Parameters
459
+
460
+ - **⚙ params** button → enter JSON parameters → run
461
+ - Example: `sendMessage` with `{"text": "Hello"}`
462
+
463
+ ---
464
+
465
+ ## 5️⃣ Using _helpers (Optional)
466
+
467
+ [_helpers/index.js](file:///Users/vilmire/Work/remote_vs/packages/launcher/providers/_helpers/index.js) provides common utilities you can use.
468
+
469
+ | Helper | Purpose |
470
+ |--------|---------|
471
+ | `getWebviewDoc(selector)` | Access Extension webview iframe document |
472
+ | `getFiber(selectors)` | Extract React Fiber data |
473
+ | `typeAndSubmit(varName, selectorExpr)` | Text input + Enter send |
474
+ | `waitFor(selector, timeout)` | Wait for element appearance |
475
+ | `htmlToMdCode()` | HTML → Markdown converter function declaration |
476
+ | `isNoiseText(text)` | Noise text filtering |
477
+
478
+ ```javascript
479
+ const { htmlToMdCode, waitFor } = require('../../_helpers/index.js');
480
+
481
+ scripts: {
482
+ readChat() {
483
+ return `(async () => {
484
+ ${htmlToMdCode()}
485
+ ${waitFor('.chat-container')}
486
+ // ...
487
+ })()`;
488
+ },
489
+ }
490
+ ```
491
+
492
+ > [!NOTE]
493
+ > Using helpers is **completely optional**. Each `provider.js` can be fully independent.
494
+
495
+ ---
496
+
497
+ ## 6️⃣ DOM Exploration Tips
498
+
499
+ ### Common Patterns Across IDEs
500
+
501
+ Most VS Code-based IDEs share the following structure:
502
+
503
+ | Element | Selector pattern |
504
+ |---------|-----------------|
505
+ | Sidebar | `#workbench.parts.auxiliarybar` |
506
+ | Editor input | `[contenteditable="true"][role="textbox"]` |
507
+ | Notification toast | `.notifications-toasts .notification-toast` |
508
+ | Dialog | `.monaco-dialog-box, [role="dialog"]` |
509
+ | Action button | `a.action-label.codicon-*` |
510
+
511
+ ### Status Detection Strategy
512
+
513
+ ```
514
+ 1. data-* attribute check (most stable)
515
+ → Cursor: data-composer-status="streaming"
516
+
517
+ 2. Fiber props exploration (React-based UI)
518
+ → Windsurf: fiber.memoizedProps.isRunning
519
+
520
+ 3. Stop button presence (universal)
521
+ → button[aria-label*="stop"], text="Stop"
522
+
523
+ 4. Placeholder text (fallback)
524
+ → input placeholder contains "wait" / "generating"
525
+ ```
526
+
527
+ ---
528
+
529
+ ## 7️⃣ Verification Checklist
530
+
531
+ After completing a new provider, verify all items below:
532
+
533
+ - [ ] `readChat` — returns message list correctly in idle state
534
+ - [ ] `readChat` — correctly detects generating status
535
+ - [ ] `readChat` — detects waiting_approval status (including modal button list)
536
+ - [ ] `sendMessage` — `needsTypeAndSend: true` return triggers normal daemon typing
537
+ - [ ] `listSessions` — session list (including title, active status)
538
+ - [ ] `switchSession` — switching based on index/title
539
+ - [ ] `newSession` — new chat creation
540
+ - [ ] `focusEditor` — focuses input field
541
+ - [ ] `openPanel` — chat panel toggle
542
+ - [ ] `resolveAction` — approve/reject button click
543
+ - [ ] `listNotifications` — notification list output
544
+ - [ ] `dismissNotification` — dismiss notification
545
+ - [ ] All scripts pass ▶ Run tests in DevConsole
546
+ - [ ] `node -c provider.js` — no syntax errors
547
+
548
+ ---
549
+
550
+ ## 8️⃣ Reference Implementations
551
+
552
+ | Pattern | Provider | Features |
553
+ |---------|----------|----------|
554
+ | **Inline** | [cursor/provider.js] | Most complete, concise implementation |
555
+ | **File separation** | [windsurf/provider.js] | Fiber usage, HTML→Markdown conversion |
556
+ | **File separation** | [antigravity/provider.js] | CDP mouse click coordinate return pattern |
557
+ | **Webview** | [kiro/provider.js] | webviewMatchText + webview* script pattern |
558
+ | **Webview** | [pearai/provider.js] | webview iframe-based chat UI |
559
+ | **File separation** | [trae/provider.js] | webviewMatchText + mainframe script hybrid |
560
+ | **ACP** | [gemini-cli/provider.js] | ACP + env_var auth + agent auth |
561
+ | **ACP** | [goose/provider.js] | ACP + terminal auth |
562
+
563
+ > [!TIP]
564
+ > When writing a new provider, **copy Cursor's `provider.json` + `scripts.js`** and modify selectors — it's the fastest approach.
565
+ > For VS Code-based IDEs, the DOM structure is similar, so just change a few selectors.
566
+ > For webview-based IDEs, refer to **Kiro's provider.json**.
567
+ > For ACP agents, refer to **gemini-cli's provider.json**.
568
+
569
+ ---
570
+
571
+ ## 📊 Version Detection & Compatibility Tracking
572
+
573
+ ADHDev automatically detects installed versions of all providers and archives the history
574
+ for future compatibility tracking.
575
+
576
+ ### How It Works
577
+
578
+ ```
579
+ adhdev daemon --dev
580
+ └─ GET /api/providers/versions
581
+ ├─ IDE: cli --version → Info.plist fallback (macOS)
582
+ ├─ CLI: binary --version → -V → -v (auto-fallback)
583
+ ├─ ACP: binary --version → -V → -v (auto-fallback)
584
+ └─ Extensions: detected at runtime via CDP (future)
585
+ ```
586
+
587
+ ### Version Archive
588
+
589
+ Detected versions are archived to `~/.adhdev/version-history.json`:
590
+
591
+ ```json
592
+ {
593
+ "cursor": [
594
+ { "version": "2.5.0", "detectedAt": "2026-02-01T...", "os": "darwin" },
595
+ { "version": "2.6.19", "detectedAt": "2026-03-18T...", "os": "darwin" }
596
+ ],
597
+ "claude-cli": [
598
+ { "version": "2.1.76", "detectedAt": "2026-03-18T...", "os": "darwin" }
599
+ ]
600
+ }
601
+ ```
602
+
603
+ - **Deduplication**: Same version is not recorded twice consecutively
604
+ - **Entry limit**: Max 20 entries per provider (oldest trimmed)
605
+ - **OS tracking**: Records which OS the version was detected on
606
+
607
+ ### provider.json Version Fields
608
+
609
+ | Field | Type | Purpose |
610
+ |-------|------|---------|
611
+ | `versionCommand` | `string` | Custom version detection command (default: `"<binary> --version"`) |
612
+ | `testedVersions` | `string[]` | Versions tested by the provider maintainer |
613
+
614
+ ```json
615
+ {
616
+ "type": "cursor",
617
+ "versionCommand": "cursor --version",
618
+ "testedVersions": ["2.5.0", "2.6.19"]
619
+ }
620
+ ```
621
+
622
+ ### Use Cases
623
+
624
+ 1. **Compatibility alerts**: When a user's installed version doesn't match `testedVersions`,
625
+ the dashboard can warn that scripts may not work correctly.
626
+ 2. **Regression tracking**: When selectors break after an IDE update, the version history
627
+ shows exactly when the change occurred.
628
+ 3. **Per-version script overrides**: Use the existing `versions` field in provider config
629
+ to provide different scripts for different IDE versions:
630
+
631
+ ```json
632
+ {
633
+ "versions": {
634
+ ">=2.7.0": {
635
+ "scripts": {
636
+ "readChat": "... updated selectors for 2.7+ ..."
637
+ }
638
+ }
639
+ }
640
+ }
641
+ ```
642
+
643
+ ### DevServer API
644
+
645
+ ```bash
646
+ # Detect all provider versions (runs installation checks)
647
+ curl http://127.0.0.1:19280/api/providers/versions
648
+
649
+ # Response:
650
+ {
651
+ "total": 52,
652
+ "installed": 13,
653
+ "providers": [
654
+ {
655
+ "type": "cursor",
656
+ "name": "Cursor",
657
+ "category": "ide",
658
+ "installed": true,
659
+ "version": "2.6.19",
660
+ "path": "/Applications/Cursor.app",
661
+ "binary": "/Applications/Cursor.app/Contents/Resources/app/bin/cursor"
662
+ }
663
+ ],
664
+ "history": { ... }
665
+ }
666
+ ```
667
+
668
+ > [!TIP]
669
+ > Run version detection periodically (or on daemon start) to keep the archive up-to-date.
670
+ > When a provider update breaks selectors, check the archive to identify the version change.
671
+
672
+ ---
673
+
674
+ ## 9️⃣ ACP Provider Guide
675
+
676
+ > Guide for adding ACP (Agent Client Protocol) agents.
677
+ > ACP agents communicate via stdin/stdout JSON-RPC 2.0.
678
+
679
+ ### Directory Structure
680
+
681
+ ```
682
+ providers/_builtin/acp/
683
+ ├── gemini-cli/ ← env_var auth (reference)
684
+ │ └── provider.js
685
+ ├── goose/ ← terminal auth (reference)
686
+ │ └── provider.js
687
+ ├── [your-agent]/ ← new ACP provider
688
+ │ └── provider.js
689
+ ```
690
+
691
+ ### provider.js Basic Structure
692
+
693
+ ```javascript
694
+ module.exports = {
695
+ type: 'my-agent-acp', // unique identifier
696
+ name: 'My Agent (ACP)', // display name
697
+ category: 'acp', // must be 'acp'
698
+ aliases: ['my-agent'], // aliases (adhdev launch my-agent etc.)
699
+
700
+ displayName: 'My Agent',
701
+ icon: '🤖',
702
+ install: 'npm install -g my-agent', // install command (shown in error messages)
703
+
704
+ spawn: {
705
+ command: 'my-agent', // used for which install check + CLI detection
706
+ args: ['--acp'], // ACP mode activation argument
707
+ shell: false,
708
+ },
709
+
710
+ // ─── Authentication Config ───
711
+ auth: [
712
+ // 1. API key based (env_var)
713
+ {
714
+ type: 'env_var',
715
+ id: 'api-key',
716
+ name: 'API Key',
717
+ link: 'https://my-agent.dev/keys', // key issuance URL
718
+ vars: [
719
+ { name: 'MY_AGENT_API_KEY', label: 'API Key', secret: true },
720
+ { name: 'MY_AGENT_ORG', label: 'Organization', optional: true },
721
+ ],
722
+ },
723
+ // 2. Self auth (agent)
724
+ // { type: 'agent', id: 'oauth', name: 'OAuth', description: 'First run will open browser' },
725
+ // 3. Terminal command (terminal)
726
+ // { type: 'terminal', id: 'config', name: 'Configure', args: ['configure'] },
727
+ ],
728
+
729
+ settings: {
730
+ approvalAlert: {
731
+ type: 'boolean', default: true, public: true,
732
+ label: 'Approval Alerts',
733
+ },
734
+ longGeneratingAlert: {
735
+ type: 'boolean', default: true, public: true,
736
+ label: 'Long Generation Alert',
737
+ },
738
+ longGeneratingThresholdSec: {
739
+ type: 'number', default: 180, public: true,
740
+ label: 'Long Generation Threshold (sec)',
741
+ min: 30, max: 600,
742
+ },
743
+ },
744
+ };
745
+ ```
746
+
747
+ ### Authentication Types (auth[]) — Documentation Only
748
+
749
+ > **Note**: ADHDev does not store or inject API keys (v0.7.1+).
750
+ > The `auth[]` field is used for documentation purposes only; each tool handles authentication independently.
751
+ > On auth failure, stderr error messages are displayed directly on the dashboard.
752
+
753
+ | type | Purpose | Note |
754
+ |------|---------|------|
755
+ | `env_var` | API key-based auth | User sets environment variables manually |
756
+ | `agent` | Agent self OAuth/browser auth | Auto-handled on first run |
757
+ | `terminal` | Auth setup via CLI command | User runs manually |
758
+
759
+ ### Behavior Flow
760
+
761
+ ```
762
+ 1. Dashboard CLIs tab → select Launch
763
+ 2. daemon-cli.ts → which check → AcpProviderInstance created
764
+ 3. spawn(command, args) → JSON-RPC initialize → session/new
765
+ 4. Chat available on Dashboard
766
+ 5. On auth failure → stderr error messages displayed on dashboard
767
+ ```
768
+
769
+ ### Error Handling (Automatic)
770
+
771
+ - **Not installed**: `which` failure → "Not installed" error + install guide
772
+ - **Auth failure**: stderr detects `unauthorized`, `api_key missing` etc. → `errorReason: 'auth_failed'`
773
+ - **Quick exit**: exit within 3 seconds → `errorReason: 'crash'` + last 3 stderr lines
774
+ - **Handshake failure**: initialize timeout → `errorReason: 'init_failed'`
775
+
776
+ > [!TIP]
777
+ > Adding a new ACP agent only requires creating a single provider.js.
778
+ > Copying `providers/_builtin/acp/gemini-cli/provider.js` is the fastest approach.
779
+
780
+ ---
781
+
782
+ ## 🔟 ProviderLoader API
783
+
784
+ ```typescript
785
+ class ProviderLoader {
786
+ loadAll(): void // load _builtin + .upstream + ~/.adhdev/providers
787
+ resolve(type, context?): ResolvedProvider // apply OS/version overrides
788
+ get(type): ProviderModule | undefined
789
+ getAll(): ProviderModule[]
790
+ getByCategory(cat): ProviderModule[]
791
+
792
+ // ─── Helpers (used by other modules) ───
793
+ getCdpPortMap(): Record<string, number[]> // CDP ports per IDE
794
+ getMacAppIdentifiers(): Record<string, string> // IDE → macOS app name
795
+ getWinProcessNames(): Record<string, string[]> // IDE → Windows process names
796
+ getAvailableIdeTypes(): string[] // IDE category only
797
+ registerToDetector(): void // register IDE to core detector
798
+ resolveAlias(alias): string // alias → type resolution
799
+ fetchLatest(): Promise<void> // download GitHub tarball (.upstream/)
800
+
801
+ watch(): void // hot-reload
802
+ stopWatch(): void
803
+ }
804
+ ```
805
+
806
+ ---
807
+
808
+ ## 1️⃣1️⃣ End-to-End Flow When Adding a New IDE
809
+
810
+ ```
811
+ ① provider.js created
812
+ providers/_builtin/ide/zed/provider.js
813
+
814
+ ② ProviderLoader.loadAll()
815
+ → auto-discovered (recursive scan)
816
+
817
+ ③ registerToDetector()
818
+ → IDE definition registered to core detector (paths, processNames)
819
+
820
+ ④ daemon initCdp()
821
+ → getCdpPortMap() → CDP connection starts
822
+
823
+ ⑤ daemon statusReport
824
+ → auto-included in managedIdes (from cdpManagers.keys())
825
+ → included in availableProviders (delivered to frontend)
826
+
827
+ ⑥ Dashboard display
828
+ → DaemonContext auto-creates IDE tab from ':ide:' pattern
829
+ → formatIdeType('zed') → 'Zed' (fallback capitalize)
830
+
831
+ ⑦ User interaction — zero TS code changes
832
+ ```
833
+
834
+ > [!IMPORTANT]
835
+ > Adding just one `provider.json` + `scripts.js` enables **detection → CDP connection → dashboard display → command execution**
836
+ > to work automatically. No TypeScript code changes are required.
837
+
838
+ ---
839
+
840
+ ## ⚡ Scaffold — Quick Provider Creation
841
+
842
+ Use the scaffold API or DevConsole to generate a new provider skeleton:
843
+
844
+ ### Via DevConsole
845
+
846
+ 1. Open http://127.0.0.1:19280
847
+ 2. Click **+ New** in the toolbar
848
+ 3. Fill in Type ID, Display Name, Category
849
+ 4. Category-specific fields appear automatically:
850
+ - **IDE**: CDP Port, CLI Command, Process Name, Install Path
851
+ - **Extension**: Extension ID
852
+ - **CLI/ACP**: Binary / Command
853
+ 5. Click **Create** → generates `~/.adhdev/providers/{type}/provider.json` + `scripts.js`
854
+
855
+ ### Via API
856
+
857
+ ```bash
858
+ curl -X POST http://127.0.0.1:19280/api/scaffold \
859
+ -H 'Content-Type: application/json' \
860
+ -d '{
861
+ "type": "zed",
862
+ "name": "Zed",
863
+ "category": "ide",
864
+ "cdpPorts": [9450, 9451],
865
+ "cli": "zed",
866
+ "processName": "Zed",
867
+ "installPath": "/Applications/Zed.app"
868
+ }'
869
+ ```
870
+
871
+ ### Generated Files
872
+
873
+ | Category | Files Generated |
874
+ |----------|----------------|
875
+ | IDE | `provider.json` + `scripts.js` (with readChat, sendMessage, etc.) |
876
+ | Extension | `provider.json` + `scripts.js` |
877
+ | CLI | `provider.json` only |
878
+ | ACP | `provider.json` only |
879
+
880
+ > [!TIP]
881
+ > After scaffold, open the provider in DevConsole → use the Wizard to discover
882
+ > DOM selectors → implement the TODO stubs in scripts.js.
883
+
884
+ ---
885
+
886
+ ## 1️⃣2️⃣ Scope Limitations
887
+
888
+ 1. **Electron-based IDEs only** — requires `--remote-debugging-port`. Zed, IntelliJ and other non-Electron IDEs not supported.
889
+ 2. **Common launch logic** — all IDEs use identical Electron launch arguments. Per-provider custom launch not implemented.
890
+ 3. **CLI adapter TypeScript maintained** — PTY lifecycle (spawn, handleOutput) is TS runtime code. provider.js provides config/patterns only.
891
+ 4. **P2P-first** — all data (chat, commands, screenshots) transmitted directly via P2P. Server WS for signaling + lightweight meta only.
892
+
893
+ ---
894
+
895
+ ## 1️⃣3️⃣ Hardcoding Removal Status
896
+
897
+ ### ✅ Fully Removed
898
+
899
+ | Location | Before | After |
900
+ |----------|--------|-------|
901
+ | `launch.ts` getCdpPorts | Hardcoded port map | `providerLoader.getCdpPortMap()` |
902
+ | `launch.ts` getMacAppIdentifiers | Hardcoded app names | `providerLoader.getMacAppIdentifiers()` |
903
+ | `launch.ts` getWinProcessNames | Hardcoded process names | `providerLoader.getWinProcessNames()` |
904
+ | `launch.ts` getAvailableIdeIds | Hardcoded IDE list | `providerLoader.getAvailableIdeTypes()` |
905
+ | `Dashboard.tsx` CLI_IDES | Hardcoded | `isCliConv()` — id pattern `:cli:` |
906
+ | `MachineDetail.tsx` CLI_TYPES | Hardcoded | `isCliEntry()` — id pattern |
907
+ | `detector.ts` IDE_DEFINITIONS | Hardcoded | `registerIDEDefinition()` runtime registration |
908
+
909
+ ### ⚠️ Intentionally Kept (fallback)
910
+
911
+ | Location | Content | Reason |
912
+ |----------|---------|--------|
913
+ | `adhdev-daemon.ts` | `fallbackType = 'cursor'` | Default on detection failure |
914
+ | `adhdev-daemon.ts` | fallback port map | On ProviderLoader load failure |
915
+ | `Dashboard.tsx` | `IDE_TYPE_LABELS` | Display name override (fallback) |
916
+ | `detector.ts` | `BUILTIN_IDE_DEFINITIONS` | Default before runtime registration |