@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,394 @@
1
+ /**
2
+ * Provider scaffold template generator
3
+ * Generates provider.json + scripts/ directory structure (Antigravity pattern).
4
+ *
5
+ * New pattern:
6
+ * - Scripts WITHOUT params: self-invoking IIFE — (() => { ... })()
7
+ * - Scripts WITH params: function expression — (params) => { ... }
8
+ * Router invokes: `(${script})(${JSON.stringify(params)})`
9
+ * - Each function is a separate .js file in scripts/<version>/
10
+ * - scripts.js router loads + invokes individual files
11
+ */
12
+
13
+ export interface ScaffoldOptions {
14
+ cdpPorts?: [number, number];
15
+ cli?: string;
16
+ processName?: string;
17
+ installPath?: string;
18
+ binary?: string;
19
+ extensionId?: string;
20
+ version?: string;
21
+ }
22
+
23
+ export interface ScaffoldResult {
24
+ 'provider.json': string;
25
+ files?: Record<string, string>;
26
+ }
27
+
28
+ export function generateTemplate(type: string, name: string, category: string, opts: ScaffoldOptions = {}): string {
29
+ const result = generateFiles(type, name, category, opts);
30
+ return result['provider.json'];
31
+ }
32
+
33
+ /**
34
+ * Generate provider.json + per-function script files.
35
+ * Returns a map of relative paths -> file contents.
36
+ */
37
+ export function generateFiles(type: string, name: string, category: string, opts: ScaffoldOptions = {}): ScaffoldResult {
38
+ const { cdpPorts, cli, processName, installPath, binary, extensionId, version = '0.1' } = opts;
39
+
40
+ // ─── CLI / ACP: provider.json only ───
41
+ if (category === 'cli' || category === 'acp') {
42
+ const bin = binary || type;
43
+ const meta: Record<string, any> = {
44
+ type,
45
+ name,
46
+ category,
47
+ icon: '💻',
48
+ binary: bin,
49
+ spawn: {
50
+ command: bin,
51
+ args: [],
52
+ shell: true,
53
+ },
54
+ patterns: {
55
+ prompt: ['^[>$#] '],
56
+ generating: ['\\.{3}$', 'thinking'],
57
+ approval: ['\\(y\\/n\\)', 'approve', 'allow'],
58
+ ready: ['ready'],
59
+ },
60
+ };
61
+ return { 'provider.json': JSON.stringify(meta, null, 2) + '\n' };
62
+ }
63
+
64
+ // ─── IDE / Extension: provider.json + scripts/ directory ───
65
+ const isExtension = category === 'extension';
66
+ const scriptDir = `scripts/${version}`;
67
+
68
+ const meta: Record<string, any> = {
69
+ type,
70
+ name,
71
+ category,
72
+ displayName: name,
73
+ icon: isExtension ? '🧩' : '💻',
74
+ };
75
+ if (cli) meta.cli = cli;
76
+ if (cdpPorts) meta.cdpPorts = cdpPorts;
77
+ else if (!isExtension) meta.cdpPorts = [9222, 9223];
78
+ if (processName) meta.processNames = { darwin: processName };
79
+ if (installPath) meta.paths = { darwin: [installPath] };
80
+ if (isExtension) {
81
+ meta.extensionId = extensionId || `publisher.${type}`;
82
+ meta.extensionIdPattern = `${extensionId || type}`;
83
+ } else {
84
+ meta.inputMethod = 'cdp-type-and-send';
85
+ meta.inputSelector = '[contenteditable="true"][role="textbox"]';
86
+ meta.providerVersion = '1.0.0';
87
+ meta.compatibility = [
88
+ { ideVersion: `>=${version}.0`, scriptDir },
89
+ ];
90
+ meta.defaultScriptDir = scriptDir;
91
+ }
92
+
93
+ // ─── Individual script files ───
94
+ const files: Record<string, string> = {};
95
+
96
+ // Router (scripts.js)
97
+ files[`${scriptDir}/scripts.js`] = `/**
98
+ * ${name} CDP Scripts — Router
99
+ *
100
+ * Loads individual .js files and invokes with params.
101
+ * Pattern:
102
+ * - No-params scripts: loaded as-is (IIFE)
103
+ * - With-params scripts: \`(\${script})(\${JSON.stringify(params)})\`
104
+ */
105
+
106
+ 'use strict';
107
+
108
+ const fs = require('fs');
109
+ const path = require('path');
110
+
111
+ function load(name) {
112
+ try { return fs.readFileSync(path.join(__dirname, name), 'utf-8'); }
113
+ catch { return null; }
114
+ }
115
+
116
+ function withParams(name, params) {
117
+ const script = load(name);
118
+ if (!script) return null;
119
+ return \`(\${script})(\${JSON.stringify(params)})\`;
120
+ }
121
+
122
+ // ─── Core (no params — IIFE) ───
123
+
124
+ module.exports.readChat = () => load('read_chat.js');
125
+ module.exports.sendMessage = () => load('send_message.js');
126
+ module.exports.listSessions = () => load('list_sessions.js');
127
+ module.exports.newSession = () => load('new_session.js');
128
+ module.exports.focusEditor = () => load('focus_editor.js');
129
+ module.exports.openPanel = () => load('open_panel.js');
130
+ module.exports.listModels = () => load('list_models.js');
131
+ module.exports.listModes = () => load('list_modes.js');
132
+
133
+ // ─── With params (function expression) ───
134
+
135
+ module.exports.switchSession = (params) => {
136
+ const index = typeof params === 'number' ? params : params?.index ?? 0;
137
+ const title = typeof params === 'string' ? params : params?.title || null;
138
+ return withParams('switch_session.js', { index, title });
139
+ };
140
+
141
+ module.exports.resolveAction = (params) => {
142
+ const action = typeof params === 'string' ? params : params?.action || 'approve';
143
+ const buttonText = params?.button || params?.buttonText
144
+ || (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : action);
145
+ return withParams('resolve_action.js', { buttonText });
146
+ };
147
+
148
+ module.exports.setModel = (params) => {
149
+ const model = typeof params === 'string' ? params : params?.model;
150
+ return withParams('set_model.js', { model });
151
+ };
152
+
153
+ module.exports.setMode = (params) => {
154
+ const mode = typeof params === 'string' ? params : params?.mode;
155
+ return withParams('set_mode.js', { mode });
156
+ };
157
+ `;
158
+
159
+ // read_chat.js — most complex, stub with detailed TODO
160
+ files[`${scriptDir}/read_chat.js`] = `/**
161
+ * ${name} — read_chat
162
+ *
163
+ * Extract chat messages, status, and approval state from DOM.
164
+ *
165
+ * TODO: Identify via CDP/DevConsole:
166
+ * 1. Chat container selector
167
+ * 2. User message selector + class pattern
168
+ * 3. Assistant message selector + class pattern
169
+ * 4. Status detection (generating/idle/waiting_approval)
170
+ * 5. Approval dialog detection (buttons, modal)
171
+ * 6. Input field selector
172
+ *
173
+ * → { id, status, title, messages[], inputContent, activeModal }
174
+ */
175
+ (() => {
176
+ try {
177
+ const messages = [];
178
+ let status = 'idle';
179
+ let activeModal = null;
180
+
181
+ // TODO: Query chat container and extract messages
182
+ // Example:
183
+ // document.querySelectorAll('.chat-message').forEach(el => {
184
+ // const role = el.classList.contains('user') ? 'user' : 'assistant';
185
+ // messages.push({ role, content: el.innerText.trim(), index: messages.length });
186
+ // });
187
+
188
+ // TODO: Detect generating state
189
+ // TODO: Detect approval dialogs -> status = 'waiting_approval'
190
+
191
+ const inputEl = document.querySelector('[contenteditable="true"]');
192
+ const inputContent = inputEl?.innerText?.trim() || '';
193
+
194
+ return JSON.stringify({
195
+ id: 'active',
196
+ status,
197
+ title: document.title,
198
+ messages,
199
+ inputContent,
200
+ activeModal,
201
+ });
202
+ } catch(e) {
203
+ return JSON.stringify({ id: '', status: 'error', messages: [], error: e.message });
204
+ }
205
+ })()
206
+ `;
207
+
208
+ // send_message.js
209
+ files[`${scriptDir}/send_message.js`] = `/**
210
+ * ${name} — send_message
211
+ *
212
+ * For cdp-type-and-send IDEs: returns selector for daemon to type into.
213
+ * → { sent: false, needsTypeAndSend: true, selector }
214
+ */
215
+ (() => {
216
+ try {
217
+ const input = document.querySelector('${meta.inputSelector || '[contenteditable="true"]'}');
218
+ if (!input) return JSON.stringify({ sent: false, error: 'Input not found' });
219
+ return JSON.stringify({
220
+ sent: false,
221
+ needsTypeAndSend: true,
222
+ selector: '${meta.inputSelector || '[contenteditable="true"]'}',
223
+ });
224
+ } catch(e) {
225
+ return JSON.stringify({ sent: false, error: e.message });
226
+ }
227
+ })()
228
+ `;
229
+
230
+ // list_sessions.js
231
+ files[`${scriptDir}/list_sessions.js`] = `/**
232
+ * ${name} — list_sessions
233
+ *
234
+ * TODO: Query session/chat list from sidebar.
235
+ * → { sessions: [{ id, title, active, index }] }
236
+ */
237
+ (() => {
238
+ try {
239
+ const sessions = [];
240
+ // TODO: Find session list container and parse items
241
+ return JSON.stringify({ sessions });
242
+ } catch(e) {
243
+ return JSON.stringify({ sessions: [], error: e.message });
244
+ }
245
+ })()
246
+ `;
247
+
248
+ // switch_session.js
249
+ files[`${scriptDir}/switch_session.js`] = `/**
250
+ * ${name} — switch_session
251
+ *
252
+ * params.index: number, params.title: string|null
253
+ * TODO: Click on session in sidebar by title or index.
254
+ * → { switched: true/false }
255
+ */
256
+ (params) => {
257
+ try {
258
+ // TODO: Find session list and click target
259
+ return JSON.stringify({ switched: false, error: 'Not implemented' });
260
+ } catch(e) {
261
+ return JSON.stringify({ switched: false, error: e.message });
262
+ }
263
+ }
264
+ `;
265
+
266
+ // new_session.js
267
+ files[`${scriptDir}/new_session.js`] = `/**
268
+ * ${name} — new_session
269
+ *
270
+ * TODO: Click "New Chat" button.
271
+ * → { created: true/false }
272
+ */
273
+ (() => {
274
+ try {
275
+ const btn = document.querySelector('[aria-label*="New Chat"], [aria-label*="New Composer"]');
276
+ if (btn) { btn.click(); return JSON.stringify({ created: true }); }
277
+ return JSON.stringify({ created: false, error: 'New Chat button not found' });
278
+ } catch(e) {
279
+ return JSON.stringify({ created: false, error: e.message });
280
+ }
281
+ })()
282
+ `;
283
+
284
+ // focus_editor.js
285
+ files[`${scriptDir}/focus_editor.js`] = `/**
286
+ * ${name} — focus_editor
287
+ */
288
+ (() => {
289
+ try {
290
+ const input = document.querySelector('${meta.inputSelector || '[contenteditable="true"]'}');
291
+ if (input) { input.focus(); return 'focused'; }
292
+ return 'not_found';
293
+ } catch(e) { return 'error'; }
294
+ })()
295
+ `;
296
+
297
+ // open_panel.js
298
+ files[`${scriptDir}/open_panel.js`] = `/**
299
+ * ${name} — open_panel
300
+ *
301
+ * TODO: Open chat/AI panel if not visible.
302
+ */
303
+ (() => {
304
+ try {
305
+ // TODO: Check if panel visible, if not find toggle button
306
+ return 'not_found';
307
+ } catch(e) { return 'error'; }
308
+ })()
309
+ `;
310
+
311
+ // resolve_action.js
312
+ files[`${scriptDir}/resolve_action.js`] = `/**
313
+ * ${name} — resolve_action
314
+ *
315
+ * params.buttonText: string — button text to find and click.
316
+ * → { resolved: true/false, clicked? }
317
+ */
318
+ (params) => {
319
+ try {
320
+ const btns = [...document.querySelectorAll('button, [role="button"]')].filter(b => b.offsetWidth > 0);
321
+ const searchText = (params.buttonText || '').toLowerCase();
322
+ const target = btns.find(b => (b.textContent||'').trim().toLowerCase().includes(searchText));
323
+ if (target) {
324
+ target.click();
325
+ return JSON.stringify({ resolved: true, clicked: target.textContent.trim() });
326
+ }
327
+ return JSON.stringify({ resolved: false, available: btns.map(b => b.textContent.trim()).filter(Boolean).slice(0, 10) });
328
+ } catch(e) { return JSON.stringify({ resolved: false, error: e.message }); }
329
+ }
330
+ `;
331
+
332
+ // list_models.js
333
+ files[`${scriptDir}/list_models.js`] = `/**
334
+ * ${name} — list_models
335
+ *
336
+ * TODO: Open model dropdown and extract model list.
337
+ * → { models[], current }
338
+ */
339
+ (() => {
340
+ try {
341
+ return JSON.stringify({ models: [], current: '' });
342
+ } catch(e) { return JSON.stringify({ models: [], current: '', error: e.message }); }
343
+ })()
344
+ `;
345
+
346
+ // list_modes.js
347
+ files[`${scriptDir}/list_modes.js`] = `/**
348
+ * ${name} — list_modes
349
+ *
350
+ * TODO: Open mode dropdown and extract mode list.
351
+ * → { modes[], current }
352
+ */
353
+ (() => {
354
+ try {
355
+ return JSON.stringify({ modes: [], current: '' });
356
+ } catch(e) { return JSON.stringify({ modes: [], current: '', error: e.message }); }
357
+ })()
358
+ `;
359
+
360
+ // set_model.js
361
+ files[`${scriptDir}/set_model.js`] = `/**
362
+ * ${name} — set_model
363
+ *
364
+ * params.model: string
365
+ * TODO: Open model dropdown and select target model.
366
+ * → { success: true/false }
367
+ */
368
+ async (params) => {
369
+ try {
370
+ return JSON.stringify({ success: false, error: 'Not implemented' });
371
+ } catch(e) { return JSON.stringify({ success: false, error: e.message }); }
372
+ }
373
+ `;
374
+
375
+ // set_mode.js
376
+ files[`${scriptDir}/set_mode.js`] = `/**
377
+ * ${name} — set_mode
378
+ *
379
+ * params.mode: string
380
+ * TODO: Open mode dropdown and select target mode.
381
+ * → { success: true/false }
382
+ */
383
+ async (params) => {
384
+ try {
385
+ return JSON.stringify({ success: false, error: 'Not implemented' });
386
+ } catch(e) { return JSON.stringify({ success: false, error: e.message }); }
387
+ }
388
+ `;
389
+
390
+ return {
391
+ 'provider.json': JSON.stringify(meta, null, 2) + '\n',
392
+ files,
393
+ };
394
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * DaemonCore — Core daemon orchestrator interface
3
+ *
4
+ * Both daemon-standalone and daemon-cloud use this interface via daemon-core.
5
+ * Actual implementation extracted from launcher and placed in this package.
6
+ */
7
+
8
+ import type { DaemonStatus, CommandResult, DaemonEvent, IdeEntry, CliEntry, AcpEntry } from './types.js';
9
+
10
+ export interface DaemonCoreOptions {
11
+ /** Data directory for config, logs */
12
+ dataDir?: string;
13
+ /** Custom provider directories */
14
+ providerDirs?: string[];
15
+ /** Enable/disable specific detectors */
16
+ enableIdeDetection?: boolean;
17
+ enableCliDetection?: boolean;
18
+ enableAcpDetection?: boolean;
19
+ /** Status report interval (ms) */
20
+ statusInterval?: number;
21
+ }
22
+
23
+ export interface IDaemonCore {
24
+ /** Initialize and start the daemon core */
25
+ start(): Promise<void>;
26
+
27
+ /** Gracefully stop the daemon */
28
+ stop(): Promise<void>;
29
+
30
+ /** Get current daemon status snapshot */
31
+ getStatus(): DaemonStatus;
32
+
33
+ /** Subscribe to status changes. Returns unsubscribe function. */
34
+ onStatusChange(callback: (status: DaemonStatus) => void): () => void;
35
+
36
+ /** Subscribe to all daemon events. Returns unsubscribe function. */
37
+ onEvent(callback: (event: DaemonEvent) => void): () => void;
38
+
39
+ /** Execute a command (send_chat, new_session, etc.) */
40
+ executeCommand(type: string, payload: any, target?: string): Promise<CommandResult>;
41
+
42
+ /** Get currently detected/managed IDEs */
43
+ getManagedIdes(): IdeEntry[];
44
+
45
+ /** Get currently detected/managed CLIs */
46
+ getManagedClis(): CliEntry[];
47
+
48
+ /** Get currently detected/managed ACP agents */
49
+ getManagedAcps(): AcpEntry[];
50
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * CLI AI Agent Detector
3
+ *
4
+ * Dynamic CLI detection based on Provider.
5
+ * Reads spawn.command from cli/acp categories via ProviderLoader to check installation.
6
+ *
7
+ * Uses parallel execution for fast detection across many providers.
8
+ */
9
+
10
+ import { exec } from 'child_process';
11
+ import * as os from 'os';
12
+ import type { ProviderLoader } from '../providers/provider-loader.js';
13
+
14
+ export interface CLIInfo {
15
+ id: string;
16
+ displayName: string;
17
+ icon: string;
18
+ command: string;
19
+ installed: boolean;
20
+ version?: string;
21
+ path?: string;
22
+ category?: string;
23
+ }
24
+
25
+ /** Run a shell command with timeout, returning stdout or null on failure */
26
+ function execAsync(cmd: string, timeoutMs = 5000): Promise<string | null> {
27
+ return new Promise((resolve) => {
28
+ const child = exec(cmd, { encoding: 'utf-8', timeout: timeoutMs }, (err, stdout) => {
29
+ if (err || !stdout?.trim()) {
30
+ resolve(null);
31
+ } else {
32
+ resolve(stdout.trim());
33
+ }
34
+ });
35
+ // Safety: kill on timeout
36
+ child.on('error', () => resolve(null));
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Detect all CLI/ACP agents (parallel)
42
+ * @param providerLoader ProviderLoader instance (dynamic list creation)
43
+ */
44
+ export async function detectCLIs(providerLoader?: ProviderLoader): Promise<CLIInfo[]> {
45
+ const platform = os.platform();
46
+ const whichCmd = platform === 'win32' ? 'where' : 'which';
47
+
48
+ // Provider-based dynamic list creation, fallback is empty array
49
+ const cliList = providerLoader
50
+ ? providerLoader.getCliDetectionList()
51
+ : [];
52
+
53
+ // Run all `which` checks in parallel
54
+ const results = await Promise.all(
55
+ cliList.map(async (cli): Promise<CLIInfo> => {
56
+ try {
57
+ const pathResult = await execAsync(`${whichCmd} ${cli.command} 2>/dev/null`);
58
+ if (!pathResult) return { ...cli, installed: false };
59
+
60
+ const firstPath = pathResult.split('\n')[0];
61
+
62
+ // Get version (parallel with other checks)
63
+ let version: string | undefined;
64
+ try {
65
+ const versionResult = await execAsync(`${cli.command} --version 2>/dev/null`, 3000);
66
+ if (versionResult) {
67
+ // Extract version number (e.g. "gemini v1.2.3" → "1.2.3")
68
+ const match = versionResult.match(/(\d+\.\d+[\.\d]*)/);
69
+ version = match ? match[1] : versionResult.split('\n')[0].slice(0, 30);
70
+ }
71
+ } catch { }
72
+
73
+ return { ...cli, installed: true, version, path: firstPath };
74
+ } catch {
75
+ return { ...cli, installed: false };
76
+ }
77
+ })
78
+ );
79
+
80
+ return results;
81
+ }
82
+
83
+ /** Detect specific CLI */
84
+ export async function detectCLI(cliId: string, providerLoader?: ProviderLoader): Promise<CLIInfo | null> {
85
+ // Resolve alias
86
+ const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
87
+ const all = await detectCLIs(providerLoader);
88
+ return all.find((c) => c.id === resolvedId && c.installed) || null;
89
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * ADHDev — IDE Detector (canonical implementation)
3
+ *
4
+ * Detects installed IDEs on the user's local machine.
5
+ * Supports macOS, Windows, and Linux.
6
+ *
7
+ * Migrated from @adhdev/core — this is now the single source of truth.
8
+ */
9
+
10
+ import { execSync } from 'child_process';
11
+ import { existsSync } from 'fs';
12
+ import { platform, homedir } from 'os';
13
+
14
+ // ─── Types ──────────────────────────────────────
15
+
16
+ export interface IDEInfo {
17
+ id: string;
18
+ name: string;
19
+ displayName: string;
20
+ installed: boolean;
21
+ path: string | null;
22
+ cliCommand: string | null;
23
+ version: string | null;
24
+ icon: string;
25
+ extensionSupport: 'full' | 'partial' | 'none';
26
+ notes?: string;
27
+ }
28
+
29
+ export interface IDEDefinition {
30
+ id: string;
31
+ name: string;
32
+ displayName: string;
33
+ icon: string;
34
+ extensionSupport: 'full' | 'partial' | 'none';
35
+ cli: string;
36
+ paths: {
37
+ darwin?: string[];
38
+ win32?: string[];
39
+ linux?: string[];
40
+ [key: string]: string[] | undefined;
41
+ };
42
+ }
43
+
44
+ // No builtin IDE definitions — provider.js registered via registerToDetector() is the single source of truth
45
+ // To add new IDE: create providers/_builtin/ide/{name}/provider.js then define paths/cli
46
+ const BUILTIN_IDE_DEFINITIONS: IDEDefinition[] = [];
47
+
48
+ // ─── Runtime Registry ───────────────────────────
49
+ const registeredIDEs = new Map<string, IDEDefinition>();
50
+
51
+ export function registerIDEDefinition(def: IDEDefinition): void {
52
+ registeredIDEs.set(def.id, def);
53
+ }
54
+
55
+ function getMergedDefinitions(): IDEDefinition[] {
56
+ const merged = new Map<string, IDEDefinition>();
57
+ for (const def of BUILTIN_IDE_DEFINITIONS) {
58
+ merged.set(def.id, def);
59
+ }
60
+ for (const [id, def] of registeredIDEs) {
61
+ merged.set(id, def);
62
+ }
63
+ return [...merged.values()];
64
+ }
65
+
66
+ function findCliCommand(command: string): string | null {
67
+ try {
68
+ const result = execSync(
69
+ platform() === 'win32' ? `where ${command}` : `which ${command}`,
70
+ { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }
71
+ ).trim();
72
+ return result.split('\n')[0] || null;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ function getIdeVersion(cliCommand: string): string | null {
79
+ try {
80
+ const result = execSync(`"${cliCommand}" --version`, {
81
+ encoding: 'utf-8',
82
+ timeout: 10000,
83
+ stdio: ['pipe', 'pipe', 'pipe'],
84
+ }).trim();
85
+ return result.split('\n')[0] || null;
86
+ } catch {
87
+ return null;
88
+ }
89
+ }
90
+
91
+ function checkPathExists(paths: string[]): string | null {
92
+ for (const p of paths) {
93
+ if (p.includes('*')) {
94
+ const home = homedir();
95
+ const starIdx = p.indexOf('*');
96
+ const suffix = p.substring(starIdx + 1);
97
+ const homeNormalized = home.replace(/\//g, '\\\\');
98
+ const resolved = homeNormalized + suffix;
99
+ if (existsSync(resolved)) return resolved;
100
+ } else {
101
+ if (existsSync(p)) return p;
102
+ }
103
+ }
104
+ return null;
105
+ }
106
+
107
+ export async function detectIDEs(): Promise<IDEInfo[]> {
108
+ const os = platform() as 'darwin' | 'win32' | 'linux';
109
+ const results: IDEInfo[] = [];
110
+
111
+ for (const def of getMergedDefinitions()) {
112
+ const cliPath = findCliCommand(def.cli);
113
+ const appPath = checkPathExists(def.paths[os] || []);
114
+ const installed = !!(cliPath || appPath);
115
+
116
+ let resolvedCli = cliPath;
117
+
118
+ if (!resolvedCli && appPath && os === 'darwin') {
119
+ const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
120
+ if (existsSync(bundledCli)) resolvedCli = bundledCli;
121
+ }
122
+
123
+ if (!resolvedCli && appPath && os === 'win32') {
124
+ const { dirname } = await import('path');
125
+ const appDir = dirname(appPath);
126
+ const candidates = [
127
+ `${appDir}\\\\bin\\\\${def.cli}.cmd`,
128
+ `${appDir}\\\\bin\\\\${def.cli}`,
129
+ `${appDir}\\\\${def.cli}.cmd`,
130
+ `${appDir}\\\\${def.cli}.exe`,
131
+ `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`,
132
+ ];
133
+ for (const c of candidates) {
134
+ if (existsSync(c)) {
135
+ resolvedCli = c;
136
+ break;
137
+ }
138
+ }
139
+ }
140
+
141
+ const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
142
+
143
+ results.push({
144
+ id: def.id,
145
+ name: def.name,
146
+ displayName: def.displayName,
147
+ installed,
148
+ path: appPath || cliPath,
149
+ cliCommand: resolvedCli || null,
150
+ version,
151
+ icon: def.icon,
152
+ extensionSupport: def.extensionSupport,
153
+ });
154
+ }
155
+
156
+ return results;
157
+ }