@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,316 @@
1
+ /**
2
+ * ADHDev Daemon — unified logger (v2)
3
+ *
4
+ * log level: DEBUG < INFO < WARN < ERROR
5
+ *
6
+ * Features:
7
+ * 1. daemonLog(category, msg, level) — explicit per-category logging
8
+ * 2. installGlobalInterceptor() — Auto-intercept console.log (once on daemon start)
9
+ * 3. Recent log ring buffer — for remote transmission via P2P/WS
10
+ * 4. File logging — ~/Library/Logs/adhdev/daemon.log (10MB rolling)
11
+ *
12
+ * use:
13
+ * import { daemonLog, LOG } from './daemon-logger';
14
+ * LOG.info('CDP', 'Connected to cursor on port 9333');
15
+ * LOG.debug('StatusReport', 'P2P heartbeat sent');
16
+ * LOG.warn('IdeInstance', 'onTick error: ...');
17
+ * LOG.error('Server', 'WebSocket disconnected');
18
+ */
19
+
20
+ import * as fs from 'fs';
21
+ import * as path from 'path';
22
+ import * as os from 'os';
23
+
24
+ // ─── Log Level ──────────────────────────────
25
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
26
+
27
+ const LEVEL_NUM: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 };
28
+ const LEVEL_LABEL: Record<LogLevel, string> = { debug: 'DBG', info: 'INF', warn: 'WRN', error: 'ERR' };
29
+
30
+ let currentLevel: LogLevel = 'info';
31
+
32
+ export function setLogLevel(level: LogLevel): void {
33
+ currentLevel = level;
34
+ daemonLog('Logger', `Log level set to: ${level}`, 'info');
35
+ }
36
+
37
+ export function getLogLevel(): LogLevel { return currentLevel; }
38
+ // ─── File logging (date-based rolling) ──────────────────────────────
39
+ const LOG_DIR = process.platform === 'darwin'
40
+ ? path.join(os.homedir(), 'Library', 'Logs', 'adhdev')
41
+ : path.join(os.homedir(), '.local', 'share', 'adhdev', 'logs');
42
+
43
+ const MAX_LOG_SIZE = 5 * 1024 * 1024; // 5MB per day
44
+ const MAX_LOG_DAYS = 7; // 7-day retention
45
+
46
+ try { fs.mkdirSync(LOG_DIR, { recursive: true }); } catch { }
47
+
48
+ function getDateStr(): string {
49
+ return new Date().toISOString().slice(0, 10); // YYYY-MM-DD
50
+ }
51
+
52
+ let currentDate = getDateStr();
53
+ let currentLogFile = path.join(LOG_DIR, `daemon-${currentDate}.log`);
54
+
55
+ /** date change detect + old file cleanup */
56
+ function checkDateRotation(): void {
57
+ const today = getDateStr();
58
+ if (today !== currentDate) {
59
+ currentDate = today;
60
+ currentLogFile = path.join(LOG_DIR, `daemon-${currentDate}.log`);
61
+ cleanOldLogs();
62
+ }
63
+ }
64
+
65
+ /** Auto-delete log files older than MAX_LOG_DAYS */
66
+ function cleanOldLogs(): void {
67
+ try {
68
+ const files = fs.readdirSync(LOG_DIR).filter(f => f.startsWith('daemon-') && f.endsWith('.log'));
69
+ const cutoff = new Date();
70
+ cutoff.setDate(cutoff.getDate() - MAX_LOG_DAYS);
71
+ const cutoffStr = cutoff.toISOString().slice(0, 10);
72
+ for (const file of files) {
73
+ const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
74
+ if (dateMatch && dateMatch[1] < cutoffStr) {
75
+ try { fs.unlinkSync(path.join(LOG_DIR, file)); } catch { }
76
+ }
77
+ }
78
+ } catch { }
79
+ }
80
+
81
+ /** Roll to .1 file when size limit reached within same date */
82
+ function rotateSizeIfNeeded(): void {
83
+ try {
84
+ const stat = fs.statSync(currentLogFile);
85
+ if (stat.size > MAX_LOG_SIZE) {
86
+ const backup = currentLogFile.replace('.log', '.1.log');
87
+ try { fs.unlinkSync(backup); } catch { }
88
+ fs.renameSync(currentLogFile, backup);
89
+ }
90
+ } catch { /* file doesn't exist yet */ }
91
+ }
92
+
93
+ // start when cleanup
94
+ cleanOldLogs();
95
+ // Migrate existing daemon.log, daemon.log.old (if present)
96
+ try {
97
+ const oldLog = path.join(LOG_DIR, 'daemon.log');
98
+ if (fs.existsSync(oldLog)) {
99
+ const stat = fs.statSync(oldLog);
100
+ const oldDate = stat.mtime.toISOString().slice(0, 10);
101
+ fs.renameSync(oldLog, path.join(LOG_DIR, `daemon-${oldDate}.log`));
102
+ }
103
+ const oldLogBackup = path.join(LOG_DIR, 'daemon.log.old');
104
+ if (fs.existsSync(oldLogBackup)) { fs.unlinkSync(oldLogBackup); }
105
+ } catch { }
106
+
107
+ let writeCount = 0;
108
+
109
+ function writeToFile(line: string): void {
110
+ try {
111
+ // Check date change + file size every 1000 writes
112
+ if (++writeCount % 1000 === 0) {
113
+ checkDateRotation();
114
+ rotateSizeIfNeeded();
115
+ }
116
+ fs.appendFileSync(currentLogFile, line + '\n');
117
+ } catch { }
118
+ }
119
+
120
+ // ─── Ring buffer (for remote transmission) ─────────────────
121
+ export interface LogEntry {
122
+ ts: number;
123
+ level: LogLevel;
124
+ category: string;
125
+ message: string;
126
+ }
127
+
128
+ const RING_BUFFER_SIZE = 200;
129
+ const ringBuffer: LogEntry[] = [];
130
+
131
+ /** Get recent N logs (for remote transmission) */
132
+ export function getRecentLogs(count = 50, minLevel: LogLevel = 'info'): LogEntry[] {
133
+ const minNum = LEVEL_NUM[minLevel];
134
+ const filtered = ringBuffer.filter(e => LEVEL_NUM[e.level] >= minNum);
135
+ return filtered.slice(-count);
136
+ }
137
+
138
+ /** Ring buffer current size */
139
+ export function getLogBufferSize(): number { return ringBuffer.length; }
140
+
141
+ // ─── Timestamp ─────────────────────────────
142
+ function ts(): string {
143
+ return new Date().toISOString().slice(11, 23); // HH:mm:ss.SSS
144
+ }
145
+
146
+ function fullTs(): string {
147
+ return new Date().toISOString();
148
+ }
149
+
150
+ // ─── Preserve original console ──────────────────────
151
+ const origConsoleLog = console.log.bind(console);
152
+ const origConsoleError = console.error.bind(console);
153
+ const origConsoleWarn = console.warn.bind(console);
154
+
155
+ // ─── Core logging function ─────────────────────────
156
+
157
+ /**
158
+ * Explicit per-category logging
159
+ * level filter apply, File logging, Ring buffer save
160
+ */
161
+ export function daemonLog(category: string, msg: string, level: LogLevel = 'info'): void {
162
+ // Level filter (console output)
163
+ const shouldOutput = LEVEL_NUM[level] >= LEVEL_NUM[currentLevel];
164
+
165
+ const label = LEVEL_LABEL[level];
166
+ const line = `[${ts()}] [${label}] [${category}] ${msg}`;
167
+
168
+ // Always record to file (including DEBUG)
169
+ writeToFile(line);
170
+
171
+ // Always save to ring buffer (for remote transmission)
172
+ ringBuffer.push({ ts: Date.now(), level, category, message: msg });
173
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
174
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
175
+ }
176
+
177
+ // Apply filter to console output
178
+ if (shouldOutput) {
179
+ origConsoleLog(line);
180
+ }
181
+ }
182
+
183
+ // ─── Convenience API ────────────────────────────────
184
+
185
+ /**
186
+ * Scoped logger instance for a specific component.
187
+ * Created via LOG.forComponent('CDP:cursor').
188
+ */
189
+ export interface ScopedLogger {
190
+ debug: (msg: string) => void;
191
+ info: (msg: string) => void;
192
+ warn: (msg: string) => void;
193
+ error: (msg: string) => void;
194
+ /** Returns a plain (msg: string) => void function at the given level.
195
+ * Useful as logFn callback for ProviderLoader, DaemonStatusReporter, etc. */
196
+ asLogFn: (level?: LogLevel) => (msg: string) => void;
197
+ }
198
+
199
+ /**
200
+ * LOG — unified logging API
201
+ *
202
+ * Usage:
203
+ * LOG.info('CDP', 'Connected to cursor on port 9333');
204
+ * LOG.debug('StatusReport', 'P2P heartbeat sent');
205
+ *
206
+ * Component-scoped logger:
207
+ * const log = LOG.forComponent('ACP:cursor');
208
+ * log.info('Session created');
209
+ * log.debug('Heartbeat');
210
+ *
211
+ * As callback for external components:
212
+ * new ProviderLoader({ logFn: LOG.forComponent('Provider').asLogFn() });
213
+ * new DaemonStatusReporter({ logFn: LOG.forComponent('Status').asLogFn() });
214
+ */
215
+ export const LOG = {
216
+ debug: (category: string, msg: string) => daemonLog(category, msg, 'debug'),
217
+ info: (category: string, msg: string) => daemonLog(category, msg, 'info'),
218
+ warn: (category: string, msg: string) => daemonLog(category, msg, 'warn'),
219
+ error: (category: string, msg: string) => daemonLog(category, msg, 'error'),
220
+
221
+ /**
222
+ * Create a scoped logger for a specific component.
223
+ * Category is baked in so callers only pass the message.
224
+ */
225
+ forComponent(category: string): ScopedLogger {
226
+ return {
227
+ debug: (msg: string) => daemonLog(category, msg, 'debug'),
228
+ info: (msg: string) => daemonLog(category, msg, 'info'),
229
+ warn: (msg: string) => daemonLog(category, msg, 'warn'),
230
+ error: (msg: string) => daemonLog(category, msg, 'error'),
231
+ asLogFn: (level: LogLevel = 'info') => (msg: string) => daemonLog(category, msg, level),
232
+ };
233
+ },
234
+ };
235
+
236
+ // ─── global interceptor ────────────────────────
237
+
238
+ let interceptorInstalled = false;
239
+
240
+ /**
241
+ * console.log/warn/error global interceptor install
242
+ * Prevent recording in places not using daemonLog.
243
+ * daemon start when 1time call.
244
+ */
245
+ export function installGlobalInterceptor(): void {
246
+ if (interceptorInstalled) return;
247
+ interceptorInstalled = true;
248
+
249
+ const stripAnsi = (str: string) => str.replace(/\x1B\[[0-9;]*m/g, '');
250
+
251
+ // Ignore lines already recorded via daemonLog (prevent duplicates)
252
+ const isDaemonLogLine = (msg: string) => /\[(DBG|INF|WRN|ERR)\]/.test(msg);
253
+
254
+ console.log = (...args: any[]) => {
255
+ origConsoleLog(...args);
256
+ try {
257
+ const msg = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');
258
+ const clean = stripAnsi(msg);
259
+ // Skip lines not yet recorded via daemonLog
260
+ if (isDaemonLogLine(clean)) return;
261
+ const line = clean.startsWith('[20') ? clean : `[${fullTs()}] ${clean}`;
262
+ writeToFile(line);
263
+ // Also save to ring buffer (auto-detect category)
264
+ const catMatch = clean.match(/\[([^\]]+)\]/);
265
+ ringBuffer.push({
266
+ ts: Date.now(),
267
+ level: 'info',
268
+ category: catMatch?.[1] || 'System',
269
+ message: clean,
270
+ });
271
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
272
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
273
+ }
274
+ } catch { }
275
+ };
276
+
277
+ console.error = (...args: any[]) => {
278
+ origConsoleError(...args);
279
+ try {
280
+ const msg = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');
281
+ const clean = stripAnsi(msg);
282
+ if (isDaemonLogLine(clean)) return;
283
+ const line = `[${fullTs()}] [ERROR] ${clean}`;
284
+ writeToFile(line);
285
+ ringBuffer.push({ ts: Date.now(), level: 'error', category: 'System', message: clean });
286
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
287
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
288
+ }
289
+ } catch { }
290
+ };
291
+
292
+ console.warn = (...args: any[]) => {
293
+ origConsoleWarn(...args);
294
+ try {
295
+ const msg = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');
296
+ const clean = stripAnsi(msg);
297
+ if (isDaemonLogLine(clean)) return;
298
+ const line = `[${fullTs()}] [WARN] ${clean}`;
299
+ writeToFile(line);
300
+ ringBuffer.push({ ts: Date.now(), level: 'warn', category: 'System', message: clean });
301
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
302
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
303
+ }
304
+ } catch { }
305
+ };
306
+
307
+ writeToFile(`\n=== ADHDev Daemon started at ${fullTs()} ===`);
308
+ writeToFile(`Log file: ${currentLogFile}`);
309
+ writeToFile(`Log level: ${currentLevel}`);
310
+ }
311
+
312
+ /** current log file path (dateper) */
313
+ export function getLogPath(): string { return currentLogFile; }
314
+ /** LOG_PATH — backward compat (current date file) */
315
+ export const LOG_PATH = path.join(LOG_DIR, `daemon-${getDateStr()}.log`);
316
+ export const LOG_DIR_PATH = LOG_DIR;