@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,156 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ADHDev Provider Validator
4
+ *
5
+ * Usage:
6
+ * node validate.js # validate all providers
7
+ * node validate.js ide/my-ide/provider.js # validate a single file
8
+ */
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const REQUIRED_FIELDS = ['type', 'name', 'category'];
13
+ const VALID_CATEGORIES = ['ide', 'extension', 'cli', 'acp'];
14
+ const USED_PORTS = new Map();
15
+ const USED_TYPES = new Map();
16
+
17
+ let errors = 0;
18
+ let warnings = 0;
19
+ let validated = 0;
20
+
21
+ function validate(filePath) {
22
+ const rel = path.relative(process.cwd(), filePath);
23
+
24
+ // 1. Syntax check
25
+ try {
26
+ delete require.cache[require.resolve(filePath)];
27
+ } catch {}
28
+
29
+ let mod;
30
+ try {
31
+ mod = require(filePath);
32
+ } catch (e) {
33
+ console.error(`❌ ${rel}: syntax error — ${e.message}`);
34
+ errors++;
35
+ return;
36
+ }
37
+
38
+ // 2. Required fields
39
+ for (const field of REQUIRED_FIELDS) {
40
+ if (!mod[field]) {
41
+ console.error(`❌ ${rel}: missing required field '${field}'`);
42
+ errors++;
43
+ return;
44
+ }
45
+ }
46
+
47
+ // 3. Valid category
48
+ if (!VALID_CATEGORIES.includes(mod.category)) {
49
+ console.error(`❌ ${rel}: invalid category '${mod.category}' (must be: ${VALID_CATEGORIES.join(', ')})`);
50
+ errors++;
51
+ return;
52
+ }
53
+
54
+ // 4. Unique type
55
+ if (USED_TYPES.has(mod.type)) {
56
+ console.error(`❌ ${rel}: duplicate type '${mod.type}' (also in ${USED_TYPES.get(mod.type)})`);
57
+ errors++;
58
+ return;
59
+ }
60
+ USED_TYPES.set(mod.type, rel);
61
+
62
+ // 5. IDE-specific checks
63
+ if (mod.category === 'ide') {
64
+ if (!mod.cdpPorts || !Array.isArray(mod.cdpPorts) || mod.cdpPorts.length < 2) {
65
+ console.warn(`⚠ ${rel}: IDE missing cdpPorts [primary, fallback]`);
66
+ warnings++;
67
+ } else {
68
+ for (const port of mod.cdpPorts) {
69
+ if (USED_PORTS.has(port)) {
70
+ console.error(`❌ ${rel}: CDP port ${port} conflicts with ${USED_PORTS.get(port)}`);
71
+ errors++;
72
+ }
73
+ USED_PORTS.set(port, rel);
74
+ }
75
+ }
76
+
77
+ if (!mod.cli) {
78
+ console.warn(`⚠ ${rel}: IDE missing 'cli' field`);
79
+ warnings++;
80
+ }
81
+
82
+ if (!mod.paths) {
83
+ console.warn(`⚠ ${rel}: IDE missing 'paths' (install detection won't work)`);
84
+ warnings++;
85
+ }
86
+ }
87
+
88
+ // 6. ACP-specific checks
89
+ if (mod.category === 'acp') {
90
+ if (!mod.spawn || !mod.spawn.command) {
91
+ console.warn(`⚠ ${rel}: ACP missing spawn.command`);
92
+ warnings++;
93
+ }
94
+ }
95
+
96
+ // 7. Scripts check
97
+ if (mod.category === 'ide' || mod.category === 'extension') {
98
+ const hasRead = mod.scripts?.readChat || mod.scripts?.webviewReadChat;
99
+ const hasSend = mod.scripts?.sendMessage || mod.scripts?.webviewSendMessage;
100
+ if (!hasRead) {
101
+ console.warn(`⚠ ${rel}: no readChat/webviewReadChat script`);
102
+ warnings++;
103
+ }
104
+ if (!hasSend) {
105
+ console.warn(`⚠ ${rel}: no sendMessage/webviewSendMessage script`);
106
+ warnings++;
107
+ }
108
+ }
109
+
110
+ // 8. Webview IDE consistency
111
+ if (mod.category === 'ide' && mod.webviewMatchText) {
112
+ if (!mod.scripts?.webviewReadChat) {
113
+ console.warn(`⚠ ${rel}: has webviewMatchText but no webviewReadChat script`);
114
+ warnings++;
115
+ }
116
+ }
117
+
118
+ validated++;
119
+ console.log(`✅ ${rel}: ${mod.type} (${mod.category}) — ${mod.name}`);
120
+ }
121
+
122
+ function scanDir(dir) {
123
+ if (!fs.existsSync(dir)) return;
124
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
125
+ const full = path.join(dir, entry.name);
126
+ if (entry.isDirectory()) {
127
+ if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;
128
+ scanDir(full);
129
+ } else if (entry.name === 'provider.js') {
130
+ validate(full);
131
+ }
132
+ }
133
+ }
134
+
135
+ // ─── Main ───
136
+ const args = process.argv.slice(2);
137
+
138
+ if (args.length > 0) {
139
+ // Validate specific file(s)
140
+ for (const arg of args) {
141
+ const filePath = path.resolve(arg);
142
+ if (!fs.existsSync(filePath)) {
143
+ console.error(`❌ File not found: ${arg}`);
144
+ errors++;
145
+ continue;
146
+ }
147
+ validate(filePath);
148
+ }
149
+ } else {
150
+ // Validate all
151
+ console.log('🔍 Validating all providers...\n');
152
+ scanDir(process.cwd());
153
+ }
154
+
155
+ console.log(`\n━━━ Result: ${validated} passed, ${errors} errors, ${warnings} warnings ━━━`);
156
+ process.exit(errors > 0 ? 1 : 0);
@@ -0,0 +1,6 @@
1
+ export { DaemonAgentStreamManager } from './manager.js';
2
+ export type { ManagedAgent } from './manager.js';
3
+ export { ProviderStreamAdapter } from './provider-adapter.js';
4
+ export * from './types.js';
5
+ export { AgentStreamPoller } from './poller.js';
6
+ export type { AgentStreamPollerDeps } from './poller.js';
@@ -0,0 +1,286 @@
1
+ /**
2
+ * DaemonAgentStreamManager — manage agent streams (ported for Daemon)
3
+ *
4
+ * Agent stream manager for extension data collection.
5
+ * All vscode dependencies removed — pure Node.js environment.
6
+ *
7
+ * Panel focus is delegated to Extension via IPC.
8
+ * CDP session management uses DaemonCdpManager directly.
9
+ */
10
+
11
+ import { DaemonCdpManager, AgentWebviewTarget } from '../cdp/manager.js';
12
+ import { ProviderLoader } from '../providers/provider-loader.js';
13
+ import { ProviderStreamAdapter } from './provider-adapter.js';
14
+ import { LOG } from '../logging/logger.js';
15
+ import type {
16
+ IAgentStreamAdapter,
17
+ AgentStreamState,
18
+ AgentChatListItem,
19
+ AgentEvaluateFn,
20
+ } from './types.js';
21
+
22
+ export interface ManagedAgent {
23
+ adapter: IAgentStreamAdapter;
24
+ sessionId: string;
25
+ target: AgentWebviewTarget;
26
+ lastState: AgentStreamState | null;
27
+ lastError: string | null;
28
+ lastHiddenCheckTime: number;
29
+ }
30
+
31
+ export class DaemonAgentStreamManager {
32
+ private allAdapters: IAgentStreamAdapter[] = [];
33
+ private managed = new Map<string, ManagedAgent>();
34
+ private enabled = true;
35
+ private logFn: (msg: string) => void;
36
+ private lastDiscoveryTime = 0;
37
+ private discoveryIntervalMs = 10_000;
38
+
39
+
40
+ private _activeAgentType: string | null = null;
41
+
42
+ constructor(logFn?: (msg: string) => void, providerLoader?: ProviderLoader) {
43
+ this.logFn = logFn || LOG.forComponent('AgentStream').asLogFn();
44
+
45
+ // Create adapter for all extension providers
46
+ // Per-IDE filtering is handled by each CDP manager via setExtensionProviders
47
+ if (providerLoader) {
48
+ const allExtProviders = providerLoader.getByCategory('extension');
49
+ for (const p of allExtProviders) {
50
+ const adapter = new ProviderStreamAdapter(p);
51
+ this.allAdapters.push(adapter);
52
+ this.logFn(`[AgentStream] Adapter created: ${p.type} (${p.name})`);
53
+ }
54
+ }
55
+ }
56
+
57
+ setEnabled(enabled: boolean) { this.enabled = enabled; }
58
+ get isEnabled() { return this.enabled; }
59
+ get activeAgentType(): string | null { return this._activeAgentType; }
60
+
61
+ /** Panel focus based on provider.js focusPanel or extensionId (currently no-op) */
62
+ async ensureAgentPanelOpen(agentType: string, targetIdeType?: string): Promise<void> {
63
+ // Extension was removed, so localServer-based panel focus no longer works
64
+ // Can be replaced with CDP-based focus (future implementation)
65
+ }
66
+
67
+ async switchActiveAgent(cdp: DaemonCdpManager, agentType: string | null): Promise<void> {
68
+ if (this._activeAgentType === agentType) return;
69
+
70
+ if (this._activeAgentType) {
71
+ const prev = this.managed.get(this._activeAgentType);
72
+ if (prev) {
73
+ try { await cdp.detachAgent(prev.sessionId); } catch { }
74
+ this.managed.delete(this._activeAgentType);
75
+ this.logFn(`[AgentStream] Deactivated: ${prev.adapter.agentName}`);
76
+ }
77
+ }
78
+
79
+ this._activeAgentType = agentType;
80
+ this.lastDiscoveryTime = 0;
81
+ this.logFn(`[AgentStream] Active agent: ${agentType || 'none'}`);
82
+ }
83
+
84
+ /** Agent webview discovery + session connection */
85
+ async syncAgentSessions(cdp: DaemonCdpManager): Promise<void> {
86
+ if (!this.enabled || !this._activeAgentType) return;
87
+
88
+ const now = Date.now();
89
+ if (this.managed.has(this._activeAgentType) && (now - this.lastDiscoveryTime) < this.discoveryIntervalMs) {
90
+ return;
91
+ }
92
+ this.lastDiscoveryTime = now;
93
+
94
+ try {
95
+ const targets = await cdp.discoverAgentWebviews();
96
+ const activeTarget = targets.find(t => t.agentType === this._activeAgentType);
97
+
98
+ if (activeTarget && !this.managed.has(this._activeAgentType)) {
99
+ const adapter = this.allAdapters.find(a => a.agentType === this._activeAgentType);
100
+ if (adapter) {
101
+ const sessionId = await cdp.attachToAgent(activeTarget);
102
+ if (sessionId) {
103
+ this.managed.set(this._activeAgentType, {
104
+ adapter,
105
+ sessionId,
106
+ target: activeTarget,
107
+ lastState: null,
108
+ lastError: null,
109
+ lastHiddenCheckTime: 0,
110
+ });
111
+ this.logFn(`[AgentStream] Connected: ${adapter.agentName}`);
112
+ }
113
+ }
114
+ }
115
+
116
+ // Cleanup inactive agents
117
+ for (const [type, agent] of this.managed) {
118
+ if (type !== this._activeAgentType) {
119
+ await cdp.detachAgent(agent.sessionId);
120
+ this.managed.delete(type);
121
+ }
122
+ }
123
+
124
+ this.discoveryIntervalMs = this.managed.has(this._activeAgentType) ? 30_000 : 10_000;
125
+ } catch (e) {
126
+ this.logFn(`[AgentStream] sync error: ${(e as Error).message}`);
127
+ }
128
+ }
129
+
130
+ /** Collect active agent status */
131
+ async collectAgentStreams(cdp: DaemonCdpManager): Promise<AgentStreamState[]> {
132
+ if (!this.enabled) return [];
133
+
134
+ const results: AgentStreamState[] = [];
135
+
136
+ if (this._activeAgentType && this.managed.has(this._activeAgentType)) {
137
+ const agent = this.managed.get(this._activeAgentType)!;
138
+ const type = this._activeAgentType;
139
+
140
+ const isHidden = agent.lastState?.status === 'panel_hidden';
141
+ const hiddenCacheFresh = isHidden && (Date.now() - agent.lastHiddenCheckTime < 30000);
142
+
143
+ if (hiddenCacheFresh) {
144
+ results.push(agent.lastState!);
145
+ } else {
146
+ try {
147
+ const evaluate: AgentEvaluateFn = (expr, timeout) =>
148
+ cdp.evaluateInSession(agent.sessionId, expr, timeout);
149
+ const state = await agent.adapter.readChat(evaluate);
150
+ agent.lastState = state;
151
+ agent.lastError = null;
152
+ if (state.status === 'panel_hidden') {
153
+ agent.lastHiddenCheckTime = Date.now();
154
+ }
155
+ results.push(state);
156
+ } catch (e) {
157
+ const errorMsg = (e as Error)?.message || String(e);
158
+ this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
159
+ agent.lastError = errorMsg;
160
+ results.push({
161
+ agentType: type,
162
+ agentName: agent.adapter.agentName,
163
+ extensionId: agent.adapter.extensionId,
164
+ status: 'disconnected',
165
+ messages: agent.lastState?.messages || [],
166
+ inputContent: '',
167
+ });
168
+ if (errorMsg.includes('timeout') || errorMsg.includes('not connected') || errorMsg.includes('Session')) {
169
+ try { await cdp.detachAgent(agent.sessionId); } catch { }
170
+ this.managed.delete(type);
171
+ this.lastDiscoveryTime = 0;
172
+ }
173
+ }
174
+ }
175
+ }
176
+
177
+ return results;
178
+ }
179
+
180
+ async sendToAgent(cdp: DaemonCdpManager, agentType: string, text: string, targetIdeType?: string): Promise<boolean> {
181
+ await this.ensureAgentPanelOpen(agentType, targetIdeType);
182
+ const agent = this.managed.get(agentType);
183
+ if (!agent) return false;
184
+ try {
185
+ const evaluate: AgentEvaluateFn = (expr, timeout) =>
186
+ cdp.evaluateInSession(agent.sessionId, expr, timeout);
187
+ await agent.adapter.sendMessage(evaluate, text);
188
+ return true;
189
+ } catch (e) {
190
+ this.logFn(`[AgentStream] sendToAgent(${agentType}) error: ${(e as Error).message}`);
191
+ return false;
192
+ }
193
+ }
194
+
195
+ async resolveAgentAction(cdp: DaemonCdpManager, agentType: string, action: 'approve' | 'reject', targetIdeType?: string): Promise<boolean> {
196
+ await this.ensureAgentPanelOpen(agentType, targetIdeType);
197
+ const agent = this.managed.get(agentType);
198
+ if (!agent) return false;
199
+ try {
200
+ const evaluate: AgentEvaluateFn = (expr, timeout) =>
201
+ cdp.evaluateInSession(agent.sessionId, expr, timeout);
202
+ return await agent.adapter.resolveAction(evaluate, action);
203
+ } catch (e) {
204
+ this.logFn(`[AgentStream] resolveAction(${agentType}) error: ${(e as Error).message}`);
205
+ return false;
206
+ }
207
+ }
208
+
209
+ async newAgentSession(cdp: DaemonCdpManager, agentType: string, targetIdeType?: string): Promise<boolean> {
210
+ await this.ensureAgentPanelOpen(agentType, targetIdeType);
211
+ const agent = this.managed.get(agentType);
212
+ if (!agent) return false;
213
+ try {
214
+ const evaluate: AgentEvaluateFn = (expr, timeout) =>
215
+ cdp.evaluateInSession(agent.sessionId, expr, timeout);
216
+ await agent.adapter.newSession(evaluate);
217
+ return true;
218
+ } catch (e) {
219
+ this.logFn(`[AgentStream] newSession(${agentType}) error: ${(e as Error).message}`);
220
+ return false;
221
+ }
222
+ }
223
+
224
+ async listAgentChats(cdp: DaemonCdpManager, agentType: string): Promise<AgentChatListItem[]> {
225
+ let agent = this.managed.get(agentType);
226
+ // on-demand: try activate+sync if not in managed list
227
+ if (!agent) {
228
+ this.logFn(`[AgentStream] listChats: ${agentType} not managed, trying on-demand activation`);
229
+ await this.switchActiveAgent(cdp, agentType);
230
+ await this.syncAgentSessions(cdp);
231
+ agent = this.managed.get(agentType);
232
+ }
233
+ if (!agent || typeof agent.adapter.listChats !== 'function') return [];
234
+ try {
235
+ const evaluate: AgentEvaluateFn = (expr, timeout) =>
236
+ cdp.evaluateInSession(agent!.sessionId, expr, timeout);
237
+ return await agent.adapter.listChats(evaluate);
238
+ } catch (e) {
239
+ this.logFn(`[AgentStream] listChats(${agentType}) error: ${(e as Error).message}`);
240
+ return [];
241
+ }
242
+ }
243
+
244
+ async switchAgentSession(cdp: DaemonCdpManager, agentType: string, sessionId: string): Promise<boolean> {
245
+ let agent = this.managed.get(agentType);
246
+ if (!agent) {
247
+ this.logFn(`[AgentStream] switchSession: ${agentType} not managed, trying on-demand activation`);
248
+ await this.switchActiveAgent(cdp, agentType);
249
+ await this.syncAgentSessions(cdp);
250
+ agent = this.managed.get(agentType);
251
+ }
252
+ if (!agent || typeof agent.adapter.switchSession !== 'function') return false;
253
+ try {
254
+ const evaluate: AgentEvaluateFn = (expr, timeout) =>
255
+ cdp.evaluateInSession(agent!.sessionId, expr, timeout);
256
+ return await agent.adapter.switchSession(evaluate, sessionId);
257
+ } catch (e) {
258
+ this.logFn(`[AgentStream] switchSession(${agentType}) error: ${(e as Error).message}`);
259
+ return false;
260
+ }
261
+ }
262
+
263
+ async focusAgentEditor(cdp: DaemonCdpManager, agentType: string): Promise<boolean> {
264
+ const agent = this.managed.get(agentType);
265
+ if (!agent || typeof agent.adapter.focusEditor !== 'function') return false;
266
+ try {
267
+ const evaluate: AgentEvaluateFn = (expr, timeout) =>
268
+ cdp.evaluateInSession(agent.sessionId, expr, timeout);
269
+ await agent.adapter.focusEditor(evaluate);
270
+ return true;
271
+ } catch (e) {
272
+ this.logFn(`[AgentStream] focusEditor(${agentType}) error: ${(e as Error).message}`);
273
+ return false;
274
+ }
275
+ }
276
+
277
+ getConnectedAgents(): string[] { return Array.from(this.managed.keys()); }
278
+ getManagedAgent(agentType: string): ManagedAgent | undefined { return this.managed.get(agentType); }
279
+
280
+ async dispose(cdp: DaemonCdpManager): Promise<void> {
281
+ for (const [, agent] of this.managed) {
282
+ try { await cdp.detachAgent(agent.sessionId); } catch { }
283
+ }
284
+ this.managed.clear();
285
+ }
286
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * AgentStreamPoller — Periodic agent stream polling + extension dynamic management
3
+ *
4
+ * Extracted from cloud daemon's startAgentStreamPolling() logic.
5
+ * Used by both daemon-cloud and daemon-standalone.
6
+ *
7
+ * Responsibilities:
8
+ * 1. Refresh extension providers in CDP managers (config changes take effect immediately)
9
+ * 2. Dynamically add/remove IDE instance extensions based on enabled state
10
+ * 3. Sync agent sessions + collect agent streams
11
+ * 4. Auto-discover agents in connected IDEs
12
+ */
13
+
14
+ import type { DaemonCdpManager } from '../cdp/manager.js';
15
+ import type { DaemonAgentStreamManager } from './manager.js';
16
+ import type { ProviderLoader } from '../providers/provider-loader.js';
17
+ import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
18
+ import { registerExtensionProviders } from '../cdp/setup.js';
19
+ import { LOG } from '../logging/logger.js';
20
+ import type { AgentStreamState } from './types.js';
21
+
22
+ // ─── Types ───
23
+
24
+ export interface AgentStreamPollerDeps {
25
+ agentStreamManager: DaemonAgentStreamManager;
26
+ providerLoader: ProviderLoader;
27
+ instanceManager: ProviderInstanceManager;
28
+ cdpManagers: Map<string, DaemonCdpManager>;
29
+ /** Callback when agent streams are updated */
30
+ onStreamsUpdated?: (ideType: string, streams: AgentStreamState[]) => void;
31
+ }
32
+
33
+ export class AgentStreamPoller {
34
+ private deps: AgentStreamPollerDeps;
35
+ private _activeIdeType: string | null = null;
36
+ private timer: NodeJS.Timeout | null = null;
37
+
38
+ constructor(deps: AgentStreamPollerDeps) {
39
+ this.deps = deps;
40
+ }
41
+
42
+ /** Currently active IDE type for agent streaming */
43
+ get activeIde(): string | null {
44
+ return this._activeIdeType;
45
+ }
46
+
47
+ /** Reset active IDE tracking (e.g., when IDE is stopped) */
48
+ resetActiveIde(ideType: string): void {
49
+ if (this._activeIdeType === ideType) {
50
+ this._activeIdeType = null;
51
+ }
52
+ }
53
+
54
+ /** Start polling (idempotent — ignored if already started) */
55
+ start(intervalMs = 5000): void {
56
+ if (this.timer) return; // Already running
57
+
58
+ this.timer = setInterval(async () => {
59
+ await this.tick();
60
+ }, intervalMs);
61
+ }
62
+
63
+ /** Stop polling */
64
+ stop(): void {
65
+ if (this.timer) {
66
+ clearInterval(this.timer);
67
+ this.timer = null;
68
+ }
69
+ }
70
+
71
+ /** Single poll tick — can also be called manually */
72
+ private async tick(): Promise<void> {
73
+ const {
74
+ agentStreamManager,
75
+ providerLoader,
76
+ instanceManager,
77
+ cdpManagers,
78
+ } = this.deps;
79
+
80
+ if (!agentStreamManager || cdpManagers.size === 0) return;
81
+
82
+ // ─── Phase 1: Refresh extension providers + IDE instance extensions ───
83
+ for (const [ideType, cdp] of cdpManagers) {
84
+ // 1a. Refresh CDP manager's extension providers from config
85
+ registerExtensionProviders(providerLoader, cdp, ideType);
86
+
87
+ // 1b. Dynamically add/remove IDE instance extensions
88
+ const ideInstance = instanceManager.getInstance(`ide:${ideType}`) as any;
89
+ if (ideInstance?.getExtensionTypes && ideInstance?.addExtension && ideInstance?.removeExtension) {
90
+ const currentExtTypes = new Set(ideInstance.getExtensionTypes() as string[]);
91
+ const enabledExtTypes = new Set(
92
+ providerLoader.getEnabledByCategory('extension', ideType).map((p: any) => p.type)
93
+ );
94
+
95
+ // Remove disabled extensions
96
+ for (const extType of currentExtTypes) {
97
+ if (!enabledExtTypes.has(extType)) {
98
+ ideInstance.removeExtension(extType);
99
+ LOG.info('AgentStream', `Extension removed: ${extType} (disabled for ${ideType})`);
100
+ }
101
+ }
102
+
103
+ // Add newly enabled extensions
104
+ for (const extType of enabledExtTypes) {
105
+ if (!currentExtTypes.has(extType)) {
106
+ const extProvider = providerLoader.getMeta(extType);
107
+ if (extProvider) {
108
+ const extSettings = providerLoader.getSettings(extType);
109
+ ideInstance.addExtension(extProvider, extSettings);
110
+ LOG.info('AgentStream', `Extension added: ${extType} (enabled for ${ideType})`);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ // ─── Phase 2: Agent session sync + collect ───
118
+
119
+ // If agent already connected to a specific IDE, only operate on that CDP
120
+ if (this._activeIdeType) {
121
+ const cdp = cdpManagers.get(this._activeIdeType);
122
+ if (cdp?.isConnected) {
123
+ try {
124
+ await agentStreamManager.syncAgentSessions(cdp);
125
+ const streams = await agentStreamManager.collectAgentStreams(cdp);
126
+ this.deps.onStreamsUpdated?.(this._activeIdeType, streams);
127
+ } catch { }
128
+ return;
129
+ }
130
+ // CDP lost — reset
131
+ this._activeIdeType = null;
132
+ }
133
+
134
+ // ─── Phase 3: Auto-discover agents ───
135
+ if (!agentStreamManager.activeAgentType) {
136
+ for (const [ideType, cdp] of cdpManagers) {
137
+ if (!cdp.isConnected) continue;
138
+ try {
139
+ const discovered = await cdp.discoverAgentWebviews();
140
+ if (discovered.length > 0) {
141
+ this._activeIdeType = ideType;
142
+ await agentStreamManager.switchActiveAgent(cdp, discovered[0].agentType);
143
+ LOG.info('AgentStream', `Auto-activated: ${discovered[0].agentType} (${ideType})`);
144
+ // sync+collect immediately
145
+ await agentStreamManager.syncAgentSessions(cdp);
146
+ const streams = await agentStreamManager.collectAgentStreams(cdp);
147
+ this.deps.onStreamsUpdated?.(ideType, streams);
148
+ return;
149
+ }
150
+ } catch { }
151
+ }
152
+ }
153
+ }
154
+ }