@adhdev/daemon-core 0.5.19 → 0.5.21
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.
- package/dist/index.d.ts +83 -11
- package/dist/index.js +204 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/providers/_builtin/extension/codex/provider.json +36 -0
- package/providers/_builtin/extension/codex/scripts/click_conversation_webview.js +24 -0
- package/providers/_builtin/extension/codex/scripts/explore_chat_webview.js +110 -0
- package/providers/_builtin/extension/codex/scripts/explore_controls_webview.js +75 -0
- package/providers/_builtin/extension/codex/scripts/explore_dom.js +88 -0
- package/providers/_builtin/extension/codex/scripts/explore_dropdown_webview.js +64 -0
- package/providers/_builtin/extension/codex/scripts/inspect_code_webview.js +55 -0
- package/providers/_builtin/extension/codex/scripts/list_models.js +62 -0
- package/providers/_builtin/extension/codex/scripts/message_structure_webview.js +79 -0
- package/providers/_builtin/extension/codex/scripts/new_session.js +26 -0
- package/providers/_builtin/extension/codex/scripts/read_chat.js +342 -0
- package/providers/_builtin/extension/codex/scripts/resolve_action.js +42 -0
- package/providers/_builtin/extension/codex/scripts/send_message.js +62 -0
- package/providers/_builtin/extension/codex/scripts/set_model.js +86 -0
- package/providers/_builtin/extension/codex/scripts.js +94 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +10 -6
- package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +10 -6
- package/providers/_builtin/registry.json +6 -1
- package/src/commands/handler.ts +44 -21
- package/src/commands/router.ts +18 -4
- package/src/daemon/dev-server.ts +15 -7
- package/src/index.ts +1 -0
- package/src/status/builders.ts +210 -0
- package/src/status/reporter.ts +29 -82
|
@@ -266,8 +266,14 @@
|
|
|
266
266
|
// 5. 모달/승인 감지 — Run⌥⏎/Reject 인라인 + Deny/Allow 브라우저 승인
|
|
267
267
|
let activeModal = null;
|
|
268
268
|
try {
|
|
269
|
+
// Strip Mac symbols and Windows shortcut labels (e.g. "RunAlt+⏎" → "Run")
|
|
270
|
+
const stripShortcut = (s) => s
|
|
271
|
+
.replace(/[⌥⏎⇧⌫⌘⌃↵]/g, '')
|
|
272
|
+
.replace(/\s*(Alt|Ctrl|Shift|Cmd|Enter|Return|Esc|Tab|Backspace)(\+\s*\w+)*/gi, '')
|
|
273
|
+
.trim();
|
|
269
274
|
const isApprovalLike = (el) => {
|
|
270
|
-
const
|
|
275
|
+
const raw = (el.textContent || '').trim();
|
|
276
|
+
const t = stripShortcut(raw).toLowerCase();
|
|
271
277
|
// 드롭다운 옵션 제외
|
|
272
278
|
if (t === 'ask every time') return false;
|
|
273
279
|
return /^(run|reject|skip|approve|allow|deny|cancel|accept|yes|no)\b/i.test(t)
|
|
@@ -293,11 +299,9 @@
|
|
|
293
299
|
const approvalBtns = panelBtns.filter(isApprovalLike);
|
|
294
300
|
if (approvalBtns.length > 0) {
|
|
295
301
|
const hasActionBtn = approvalBtns.some(b => {
|
|
296
|
-
const t = (b.textContent || '').trim().toLowerCase();
|
|
297
|
-
return
|
|
298
|
-
|| t === '
|
|
299
|
-
|| t === 'deny' || t === 'allow' || t === 'always allow' || t === 'always deny'
|
|
300
|
-
|| t === 'accept' || t === 'approve';
|
|
302
|
+
const t = stripShortcut((b.textContent || '').trim()).toLowerCase();
|
|
303
|
+
return /^(run|reject|skip|deny|allow|accept|approve|yes|no)\b/.test(t)
|
|
304
|
+
|| t === 'always allow' || t === 'always deny';
|
|
301
305
|
});
|
|
302
306
|
if (hasActionBtn) {
|
|
303
307
|
const btnTexts = [...new Set(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2026.03.
|
|
2
|
+
"version": "2026.03.22",
|
|
3
3
|
"providers": {
|
|
4
4
|
"agentpool-acp": {
|
|
5
5
|
"providerVersion": "0.0.0",
|
|
@@ -196,6 +196,11 @@
|
|
|
196
196
|
"category": "extension",
|
|
197
197
|
"name": "Cline"
|
|
198
198
|
},
|
|
199
|
+
"codex": {
|
|
200
|
+
"providerVersion": "0.0.0",
|
|
201
|
+
"category": "extension",
|
|
202
|
+
"name": "Codex"
|
|
203
|
+
},
|
|
199
204
|
"roo-code": {
|
|
200
205
|
"providerVersion": "0.0.0",
|
|
201
206
|
"category": "extension",
|
package/src/commands/handler.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Routes
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
2
|
+
* DaemonCommandHandler — unified command routing for CDP & CLI
|
|
3
|
+
*
|
|
4
|
+
* Routes incoming commands (from server WS, P2P, or local WS) to
|
|
5
|
+
* the correct CDP manager or CLI adapter.
|
|
6
|
+
*
|
|
7
|
+
* Key concepts:
|
|
8
|
+
* - extractIdeType(): determines target IDE from _targetInstance
|
|
9
|
+
* - getCdp(): returns the DaemonCdpManager for current command
|
|
10
|
+
* - getProvider(): returns the ProviderModule for current command
|
|
11
|
+
* - handle(): main entry point, sets context then dispatches
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
|
-
import { DaemonCdpManager } from '../cdp/manager.js';
|
|
14
|
+
import type { DaemonCdpManager } from '../cdp/manager.js';
|
|
13
15
|
import { CdpDomHandlers } from '../cdp/devtools.js';
|
|
16
|
+
import { findCdpManager } from '../status/builders.js';
|
|
14
17
|
import { ProviderLoader } from '../providers/provider-loader.js';
|
|
15
18
|
import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
|
|
16
19
|
import type { ProviderModule } from '../providers/contracts.js';
|
|
@@ -85,12 +88,16 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
85
88
|
get currentIdeType(): string | undefined { return this._currentIdeType; }
|
|
86
89
|
get currentProviderType(): string | undefined { return this._currentProviderType; }
|
|
87
90
|
|
|
88
|
-
/** Get CDP manager for a specific ideType.
|
|
91
|
+
/** Get CDP manager for a specific ideType or managerKey.
|
|
92
|
+
* Supports exact match, multi-window prefix match, and instanceIdMap UUID lookup.
|
|
89
93
|
* Returns null if no match — never falls back to another IDE. */
|
|
90
94
|
getCdp(ideType?: string): DaemonCdpManager | null {
|
|
91
95
|
const key = ideType || this._currentIdeType;
|
|
92
96
|
if (!key) return null;
|
|
93
|
-
|
|
97
|
+
// 1. Try instanceIdMap (UUID → managerKey)
|
|
98
|
+
const resolved = this._ctx.instanceIdMap?.get(key) || key;
|
|
99
|
+
// 2. Use findCdpManager (exact + prefix match)
|
|
100
|
+
const m = findCdpManager(this._ctx.cdpManagers, resolved.toLowerCase());
|
|
94
101
|
if (m?.isConnected) return m;
|
|
95
102
|
return null;
|
|
96
103
|
}
|
|
@@ -177,11 +184,22 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
177
184
|
return managed?.sessionId || null;
|
|
178
185
|
}
|
|
179
186
|
|
|
180
|
-
/** Extract ideType from _targetInstance */
|
|
187
|
+
/** Extract ideType from _targetInstance or explicit ideType */
|
|
181
188
|
private extractIdeType(args: any): string | undefined {
|
|
182
|
-
// Also accept explicit ideType from args (agentType for extensions)
|
|
183
|
-
if (args?.ideType
|
|
184
|
-
|
|
189
|
+
// Also accept explicit ideType from args (P2P input, agentType for extensions)
|
|
190
|
+
if (args?.ideType) {
|
|
191
|
+
// Exact match first
|
|
192
|
+
if (this._ctx.cdpManagers.has(args.ideType)) {
|
|
193
|
+
return args.ideType;
|
|
194
|
+
}
|
|
195
|
+
// Prefix match for multi-window (e.g. "cursor" matches "cursor_remote_vs")
|
|
196
|
+
const found = findCdpManager(this._ctx.cdpManagers, args.ideType);
|
|
197
|
+
if (found) {
|
|
198
|
+
// Return the actual key so getCdp() finds it
|
|
199
|
+
for (const [k, m] of this._ctx.cdpManagers.entries()) {
|
|
200
|
+
if (m === found) return k;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
185
203
|
}
|
|
186
204
|
|
|
187
205
|
if (args?._targetInstance) {
|
|
@@ -197,19 +215,24 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
197
215
|
return this._ctx.instanceIdMap.get(raw)!;
|
|
198
216
|
}
|
|
199
217
|
|
|
200
|
-
// Direct CDP manager key match (e.g. "cursor", "
|
|
218
|
+
// Direct CDP manager key match (e.g. "cursor", "cursor_remote_vs")
|
|
201
219
|
if (this._ctx.cdpManagers.has(raw)) {
|
|
202
220
|
return raw;
|
|
203
221
|
}
|
|
204
222
|
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
if (
|
|
208
|
-
for (const [
|
|
209
|
-
if (
|
|
223
|
+
// Prefix match for multi-window keys
|
|
224
|
+
const found = findCdpManager(this._ctx.cdpManagers, raw);
|
|
225
|
+
if (found) {
|
|
226
|
+
for (const [k, m] of this._ctx.cdpManagers.entries()) {
|
|
227
|
+
if (m === found) return k;
|
|
210
228
|
}
|
|
211
229
|
}
|
|
212
230
|
|
|
231
|
+
// Fallback removed: returning first-connected CDP was the root cause of
|
|
232
|
+
// input routing to wrong IDE (e.g. screenshot shows Cursor but input goes
|
|
233
|
+
// to Antigravity). If no match is found, return undefined so the caller
|
|
234
|
+
// gets an explicit error rather than silently routing to the wrong IDE.
|
|
235
|
+
|
|
213
236
|
// Legacy: strip trailing _N suffix (e.g. "cursor_1" → "cursor")
|
|
214
237
|
const lastUnderscore = raw.lastIndexOf('_');
|
|
215
238
|
if (lastUnderscore > 0) {
|
package/src/commands/router.ts
CHANGED
|
@@ -48,6 +48,8 @@ export interface CommandRouterDeps {
|
|
|
48
48
|
onPostChatCommand?: () => void;
|
|
49
49
|
/** Get a connected CDP manager (for agent stream reset check) */
|
|
50
50
|
getCdpLogFn?: (ideType: string) => (msg: string) => void;
|
|
51
|
+
/** Package name for upgrade detection ('adhdev' or '@adhdev/daemon-standalone') */
|
|
52
|
+
packageName?: string;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
export interface CommandRouterResult {
|
|
@@ -257,12 +259,17 @@ export class DaemonCommandRouter {
|
|
|
257
259
|
try {
|
|
258
260
|
const { execSync } = await import('child_process');
|
|
259
261
|
|
|
262
|
+
// Detect package: standalone uses @adhdev/daemon-standalone, cloud uses adhdev
|
|
263
|
+
const isStandalone = this.deps.packageName === '@adhdev/daemon-standalone'
|
|
264
|
+
|| process.argv[1]?.includes('daemon-standalone');
|
|
265
|
+
const pkgName = isStandalone ? '@adhdev/daemon-standalone' : 'adhdev';
|
|
266
|
+
|
|
260
267
|
// Check latest version
|
|
261
|
-
const latest = execSync(
|
|
262
|
-
LOG.info('Upgrade', `Latest
|
|
268
|
+
const latest = execSync(`npm view ${pkgName} version`, { encoding: 'utf-8', timeout: 10000 }).trim();
|
|
269
|
+
LOG.info('Upgrade', `Latest ${pkgName}: v${latest}`);
|
|
263
270
|
|
|
264
271
|
// Install latest
|
|
265
|
-
execSync(
|
|
272
|
+
execSync(`npm install -g ${pkgName}@latest`, {
|
|
266
273
|
encoding: 'utf-8',
|
|
267
274
|
timeout: 60000,
|
|
268
275
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -272,8 +279,15 @@ export class DaemonCommandRouter {
|
|
|
272
279
|
// Schedule restart after response is sent
|
|
273
280
|
setTimeout(() => {
|
|
274
281
|
LOG.info('Upgrade', 'Restarting daemon with new version...');
|
|
282
|
+
// Remove PID file so the new process doesn't see 'already running'
|
|
283
|
+
try {
|
|
284
|
+
const path = require('path');
|
|
285
|
+
const fs = require('fs');
|
|
286
|
+
const pidFile = path.join(process.env.HOME || process.env.USERPROFILE || '', '.adhdev', 'daemon.pid');
|
|
287
|
+
if (fs.existsSync(pidFile)) fs.unlinkSync(pidFile);
|
|
288
|
+
} catch { /* ignore */ }
|
|
275
289
|
const { spawn } = require('child_process');
|
|
276
|
-
const child = spawn(process.execPath,
|
|
290
|
+
const child = spawn(process.execPath, process.argv.slice(1), {
|
|
277
291
|
detached: true,
|
|
278
292
|
stdio: 'ignore',
|
|
279
293
|
env: { ...process.env },
|
package/src/daemon/dev-server.ts
CHANGED
|
@@ -367,7 +367,10 @@ export class DevServer {
|
|
|
367
367
|
return;
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
-
const cdp =
|
|
370
|
+
const cdp = this.getCdp(ideType);
|
|
371
|
+
if (!cdp && !ideType) {
|
|
372
|
+
LOG.warn('DevServer', 'CDP evaluate without ideType — picked first connected manager');
|
|
373
|
+
}
|
|
371
374
|
if (!cdp?.isConnected) {
|
|
372
375
|
this.json(res, 503, { error: 'No CDP connection available' });
|
|
373
376
|
return;
|
|
@@ -626,7 +629,7 @@ export class DevServer {
|
|
|
626
629
|
this.sendSSE({ type: 'watch_error', error: `Script '${this.watchScriptName}' not found` });
|
|
627
630
|
return;
|
|
628
631
|
}
|
|
629
|
-
const cdp = this.
|
|
632
|
+
const cdp = this.getCdp();
|
|
630
633
|
if (!cdp) {
|
|
631
634
|
this.sendSSE({ type: 'watch_error', error: 'No CDP connection' });
|
|
632
635
|
return;
|
|
@@ -2361,22 +2364,27 @@ export class DevServer {
|
|
|
2361
2364
|
}
|
|
2362
2365
|
}
|
|
2363
2366
|
|
|
2364
|
-
/** Get CDP manager — matching IDE when ideType specified, first connected one otherwise
|
|
2367
|
+
/** Get CDP manager — matching IDE when ideType specified, first connected one otherwise.
|
|
2368
|
+
* DevServer is a debugging tool so first-connected fallback is acceptable,
|
|
2369
|
+
* but callers should pass ideType when possible. */
|
|
2365
2370
|
private getCdp(ideType?: string): DaemonCdpManager | null {
|
|
2366
2371
|
if (ideType) {
|
|
2367
2372
|
const cdp = this.cdpManagers.get(ideType);
|
|
2368
2373
|
if (cdp?.isConnected) return cdp;
|
|
2374
|
+
// Prefix match for multi-window keys
|
|
2375
|
+
for (const [k, m] of this.cdpManagers.entries()) {
|
|
2376
|
+
if (k.startsWith(ideType + '_') && m.isConnected) return m;
|
|
2377
|
+
}
|
|
2378
|
+
LOG.warn('DevServer', `getCdp: no manager found for ideType '${ideType}', available: [${[...this.cdpManagers.keys()].join(', ')}]`);
|
|
2379
|
+
return null;
|
|
2369
2380
|
}
|
|
2381
|
+
// No ideType — return first connected (dev convenience)
|
|
2370
2382
|
for (const cdp of this.cdpManagers.values()) {
|
|
2371
2383
|
if (cdp.isConnected) return cdp;
|
|
2372
2384
|
}
|
|
2373
2385
|
return null;
|
|
2374
2386
|
}
|
|
2375
2387
|
|
|
2376
|
-
private getAnyCdp(): DaemonCdpManager | null {
|
|
2377
|
-
return this.getCdp();
|
|
2378
|
-
}
|
|
2379
|
-
|
|
2380
2388
|
private json(res: http.ServerResponse, status: number, data: any): void {
|
|
2381
2389
|
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
2382
2390
|
res.end(JSON.stringify(data, null, 2));
|
package/src/index.ts
CHANGED
|
@@ -75,6 +75,7 @@ export type { CommandRouterDeps, CommandRouterResult } from './commands/router.j
|
|
|
75
75
|
|
|
76
76
|
// ── Status ──
|
|
77
77
|
export { DaemonStatusReporter } from './status/reporter.js';
|
|
78
|
+
export { buildManagedIdes, buildManagedClis, buildManagedAcps, buildAllManagedEntries, findCdpManager, hasCdpManager, isCdpConnected } from './status/builders.js';
|
|
78
79
|
|
|
79
80
|
// ── Logger ──
|
|
80
81
|
export { LOG, installGlobalInterceptor, setLogLevel, getLogLevel, getRecentLogs } from './logging/logger.js';
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Builders — shared conversion functions for ProviderState → ManagedEntry
|
|
3
|
+
*
|
|
4
|
+
* Used by:
|
|
5
|
+
* - daemon-cloud (DaemonStatusReporter)
|
|
6
|
+
* - daemon-standalone (StandaloneServer.getStatus)
|
|
7
|
+
*
|
|
8
|
+
* Consolidates duplicated ProviderState→ManagedEntry mapping that was
|
|
9
|
+
* previously copy-pasted between cloud and standalone codebases.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { DaemonCdpManager } from '../cdp/manager.js';
|
|
13
|
+
import type { ManagedIdeEntry, ManagedCliEntry, ManagedAcpEntry } from '../shared-types.js';
|
|
14
|
+
import type {
|
|
15
|
+
IdeProviderState,
|
|
16
|
+
CliProviderState,
|
|
17
|
+
AcpProviderState,
|
|
18
|
+
ProviderState,
|
|
19
|
+
} from '../providers/provider-instance.js';
|
|
20
|
+
|
|
21
|
+
// ─── CDP Manager lookup helpers ──────────────────────
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Find a CDP manager by key, with prefix matching for multi-window support.
|
|
25
|
+
*
|
|
26
|
+
* Lookup order:
|
|
27
|
+
* 1. Exact match: cdpManagers.get(key)
|
|
28
|
+
* 2. Prefix match: key starts with `${ideType}_` (multi-window: "cursor_remote_vs")
|
|
29
|
+
* 3. null
|
|
30
|
+
*
|
|
31
|
+
* This replaces raw `cdpManagers.get(ideType)` calls that broke when
|
|
32
|
+
* multi-window keys like "cursor_remote_vs" were used.
|
|
33
|
+
*/
|
|
34
|
+
export function findCdpManager(
|
|
35
|
+
cdpManagers: Map<string, DaemonCdpManager>,
|
|
36
|
+
key: string,
|
|
37
|
+
): DaemonCdpManager | null {
|
|
38
|
+
// 1. Exact match (single-window: "cursor", or full managerKey: "cursor_remote_vs")
|
|
39
|
+
const exact = cdpManagers.get(key);
|
|
40
|
+
if (exact) return exact;
|
|
41
|
+
|
|
42
|
+
// 2. Prefix match (key = ideType like "cursor", managerKey = "cursor_remote_vs")
|
|
43
|
+
const prefix = key + '_';
|
|
44
|
+
for (const [k, m] of cdpManagers.entries()) {
|
|
45
|
+
if (k.startsWith(prefix) && m.isConnected) return m;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if any CDP manager matches the given key (exact or prefix).
|
|
53
|
+
*/
|
|
54
|
+
export function hasCdpManager(
|
|
55
|
+
cdpManagers: Map<string, DaemonCdpManager>,
|
|
56
|
+
key: string,
|
|
57
|
+
): boolean {
|
|
58
|
+
if (cdpManagers.has(key)) return true;
|
|
59
|
+
const prefix = key + '_';
|
|
60
|
+
for (const k of cdpManagers.keys()) {
|
|
61
|
+
if (k.startsWith(prefix)) return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if any CDP manager matching the key is connected.
|
|
68
|
+
*/
|
|
69
|
+
export function isCdpConnected(
|
|
70
|
+
cdpManagers: Map<string, DaemonCdpManager>,
|
|
71
|
+
key: string,
|
|
72
|
+
): boolean {
|
|
73
|
+
const m = findCdpManager(cdpManagers, key);
|
|
74
|
+
return m?.isConnected ?? false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ─── ProviderState → ManagedEntry builders ───────────
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Convert IdeProviderState[] → ManagedIdeEntry[]
|
|
81
|
+
*
|
|
82
|
+
* @param ideStates - from instanceManager.collectAllStates() filtered to ide
|
|
83
|
+
* @param cdpManagers - for cdpConnected lookup
|
|
84
|
+
* @param opts.detectedIdes - include CDPs that have no instance yet
|
|
85
|
+
*/
|
|
86
|
+
export function buildManagedIdes(
|
|
87
|
+
ideStates: IdeProviderState[],
|
|
88
|
+
cdpManagers: Map<string, DaemonCdpManager>,
|
|
89
|
+
opts?: { detectedIdes?: { id: string; installed: boolean }[] },
|
|
90
|
+
): ManagedIdeEntry[] {
|
|
91
|
+
const result: ManagedIdeEntry[] = [];
|
|
92
|
+
|
|
93
|
+
for (const state of ideStates) {
|
|
94
|
+
// Use cdpConnected from IdeProviderState if available (it checks internally),
|
|
95
|
+
// otherwise fall back to CDP manager lookup
|
|
96
|
+
const cdpConnected = state.cdpConnected ?? isCdpConnected(cdpManagers, state.type);
|
|
97
|
+
result.push({
|
|
98
|
+
ideType: state.type,
|
|
99
|
+
ideVersion: '',
|
|
100
|
+
instanceId: state.instanceId || state.type,
|
|
101
|
+
workspace: state.workspace || null,
|
|
102
|
+
terminals: 0,
|
|
103
|
+
aiAgents: [],
|
|
104
|
+
activeChat: state.activeChat,
|
|
105
|
+
chats: [],
|
|
106
|
+
agentStreams: state.extensions.map((ext) => ({
|
|
107
|
+
agentType: ext.type,
|
|
108
|
+
agentName: ext.name,
|
|
109
|
+
extensionId: ext.type,
|
|
110
|
+
status: ext.status || 'idle',
|
|
111
|
+
messages: ext.activeChat?.messages || [],
|
|
112
|
+
inputContent: ext.activeChat?.inputContent || '',
|
|
113
|
+
activeModal: ext.activeChat?.activeModal || null,
|
|
114
|
+
})),
|
|
115
|
+
cdpConnected,
|
|
116
|
+
currentModel: state.currentModel,
|
|
117
|
+
currentPlan: state.currentPlan,
|
|
118
|
+
currentAutoApprove: state.currentAutoApprove,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Include CDPs with no ProviderInstance yet (newly detected IDEs)
|
|
123
|
+
if (opts?.detectedIdes) {
|
|
124
|
+
const coveredTypes = new Set(ideStates.map((s) => s.type));
|
|
125
|
+
for (const ide of opts.detectedIdes) {
|
|
126
|
+
if (!ide.installed || coveredTypes.has(ide.id)) continue;
|
|
127
|
+
if (!isCdpConnected(cdpManagers, ide.id)) continue;
|
|
128
|
+
result.push({
|
|
129
|
+
ideType: ide.id,
|
|
130
|
+
ideVersion: '',
|
|
131
|
+
instanceId: ide.id,
|
|
132
|
+
workspace: null,
|
|
133
|
+
terminals: 0,
|
|
134
|
+
aiAgents: [],
|
|
135
|
+
activeChat: null,
|
|
136
|
+
chats: [],
|
|
137
|
+
agentStreams: [],
|
|
138
|
+
cdpConnected: true,
|
|
139
|
+
currentModel: undefined,
|
|
140
|
+
currentPlan: undefined,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Convert CliProviderState[] → ManagedCliEntry[]
|
|
150
|
+
*/
|
|
151
|
+
export function buildManagedClis(
|
|
152
|
+
cliStates: CliProviderState[],
|
|
153
|
+
): ManagedCliEntry[] {
|
|
154
|
+
return cliStates.map((s) => ({
|
|
155
|
+
id: s.instanceId,
|
|
156
|
+
instanceId: s.instanceId,
|
|
157
|
+
cliType: s.type,
|
|
158
|
+
cliName: s.name,
|
|
159
|
+
status: s.status,
|
|
160
|
+
mode: s.mode as 'terminal' | 'chat',
|
|
161
|
+
workspace: s.workspace || '',
|
|
162
|
+
activeChat: s.activeChat,
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Convert AcpProviderState[] → ManagedAcpEntry[]
|
|
168
|
+
*/
|
|
169
|
+
export function buildManagedAcps(
|
|
170
|
+
acpStates: AcpProviderState[],
|
|
171
|
+
): ManagedAcpEntry[] {
|
|
172
|
+
return acpStates.map((s) => ({
|
|
173
|
+
id: s.instanceId,
|
|
174
|
+
acpType: s.type,
|
|
175
|
+
acpName: s.name,
|
|
176
|
+
status: s.status,
|
|
177
|
+
mode: 'chat' as const,
|
|
178
|
+
workspace: s.workspace || '',
|
|
179
|
+
activeChat: s.activeChat,
|
|
180
|
+
currentModel: s.currentModel,
|
|
181
|
+
currentPlan: s.currentPlan,
|
|
182
|
+
acpConfigOptions: s.acpConfigOptions,
|
|
183
|
+
acpModes: s.acpModes,
|
|
184
|
+
errorMessage: s.errorMessage,
|
|
185
|
+
errorReason: s.errorReason,
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Convenience: collect & build all managed entries from instanceManager
|
|
191
|
+
*/
|
|
192
|
+
export function buildAllManagedEntries(
|
|
193
|
+
allStates: ProviderState[],
|
|
194
|
+
cdpManagers: Map<string, DaemonCdpManager>,
|
|
195
|
+
opts?: { detectedIdes?: { id: string; installed: boolean }[] },
|
|
196
|
+
): {
|
|
197
|
+
managedIdes: ManagedIdeEntry[];
|
|
198
|
+
managedClis: ManagedCliEntry[];
|
|
199
|
+
managedAcps: ManagedAcpEntry[];
|
|
200
|
+
} {
|
|
201
|
+
const ideStates = allStates.filter((s): s is IdeProviderState => s.category === 'ide');
|
|
202
|
+
const cliStates = allStates.filter((s): s is CliProviderState => s.category === 'cli');
|
|
203
|
+
const acpStates = allStates.filter((s): s is AcpProviderState => s.category === 'acp');
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
managedIdes: buildManagedIdes(ideStates, cdpManagers, opts),
|
|
207
|
+
managedClis: buildManagedClis(cliStates),
|
|
208
|
+
managedAcps: buildManagedAcps(acpStates),
|
|
209
|
+
};
|
|
210
|
+
}
|
package/src/status/reporter.ts
CHANGED
|
@@ -12,13 +12,12 @@ import { getWorkspaceState } from '../config/workspaces.js';
|
|
|
12
12
|
import { getHostMemorySnapshot } from '../system/host-memory.js';
|
|
13
13
|
import { getWorkspaceActivity } from '../config/workspace-activity.js';
|
|
14
14
|
import { LOG } from '../logging/logger.js';
|
|
15
|
-
import
|
|
15
|
+
import { buildAllManagedEntries } from './builders.js';
|
|
16
16
|
import type {
|
|
17
17
|
ProviderState,
|
|
18
18
|
IdeProviderState,
|
|
19
19
|
CliProviderState,
|
|
20
20
|
AcpProviderState,
|
|
21
|
-
ExtensionProviderState,
|
|
22
21
|
} from '../providers/provider-instance.js';
|
|
23
22
|
|
|
24
23
|
// ─── Daemon dependency interface ──────────────────────
|
|
@@ -156,62 +155,13 @@ export class DaemonStatusReporter {
|
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
// IDE states →
|
|
160
|
-
const managedIdes
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
aiAgents: [],
|
|
167
|
-
activeChat: s.activeChat,
|
|
168
|
-
chats: [],
|
|
169
|
-
agentStreams: s.extensions.map((ext) => ({
|
|
170
|
-
agentType: ext.type,
|
|
171
|
-
agentName: ext.name,
|
|
172
|
-
extensionId: ext.type,
|
|
173
|
-
status: ext.status || 'idle',
|
|
174
|
-
messages: ext.activeChat?.messages || [],
|
|
175
|
-
inputContent: ext.activeChat?.inputContent || '',
|
|
176
|
-
activeModal: ext.activeChat?.activeModal || null,
|
|
177
|
-
})),
|
|
178
|
-
cdpConnected: s.cdpConnected,
|
|
179
|
-
currentModel: s.currentModel,
|
|
180
|
-
currentPlan: s.currentPlan,
|
|
181
|
-
currentAutoApprove: s.currentAutoApprove,
|
|
182
|
-
}));
|
|
183
|
-
|
|
184
|
-
// Merge/add Extension data
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// CLI states → managedClis
|
|
188
|
-
const managedClis: ManagedCliEntry[] = cliStates.map((s) => ({
|
|
189
|
-
id: s.instanceId,
|
|
190
|
-
instanceId: s.instanceId,
|
|
191
|
-
cliType: s.type,
|
|
192
|
-
cliName: s.name,
|
|
193
|
-
status: s.status,
|
|
194
|
-
mode: s.mode,
|
|
195
|
-
workspace: s.workspace || '',
|
|
196
|
-
activeChat: s.activeChat,
|
|
197
|
-
}));
|
|
198
|
-
|
|
199
|
-
// ACP states → managedAcps
|
|
200
|
-
const managedAcps: ManagedAcpEntry[] = acpStates.map((s) => ({
|
|
201
|
-
id: s.instanceId,
|
|
202
|
-
acpType: s.type,
|
|
203
|
-
acpName: s.name,
|
|
204
|
-
status: s.status,
|
|
205
|
-
mode: s.mode,
|
|
206
|
-
workspace: s.workspace || '',
|
|
207
|
-
activeChat: s.activeChat,
|
|
208
|
-
currentModel: s.currentModel,
|
|
209
|
-
currentPlan: s.currentPlan,
|
|
210
|
-
acpConfigOptions: s.acpConfigOptions,
|
|
211
|
-
acpModes: s.acpModes,
|
|
212
|
-
errorMessage: s.errorMessage,
|
|
213
|
-
errorReason: s.errorReason,
|
|
214
|
-
}));
|
|
158
|
+
// IDE/CLI/ACP states → managed entries (shared builder)
|
|
159
|
+
const { managedIdes, managedClis, managedAcps } = buildAllManagedEntries(
|
|
160
|
+
allStates,
|
|
161
|
+
this.deps.cdpManagers as Map<string, any>,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
|
|
215
165
|
|
|
216
166
|
|
|
217
167
|
|
|
@@ -265,33 +215,30 @@ export class DaemonStatusReporter {
|
|
|
265
215
|
|
|
266
216
|
// ═══ Server transmit (minimal routing meta only — sanitizeForRelay removes everything else) ═══
|
|
267
217
|
if (opts?.p2pOnly) return;
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
defaultWorkspaceId: wsState.defaultWorkspaceId,
|
|
274
|
-
workspaceCount: (wsState.workspaces || []).length,
|
|
218
|
+
const wsPayload = {
|
|
219
|
+
daemonMode: true,
|
|
220
|
+
machineNickname: payload.machineNickname,
|
|
221
|
+
defaultWorkspaceId: wsState.defaultWorkspaceId,
|
|
222
|
+
workspaceCount: (wsState.workspaces || []).length,
|
|
275
223
|
// managedIdes: server only saves id, type, cdpConnected
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
224
|
+
managedIdes: managedIdes.map(ide => ({
|
|
225
|
+
ideType: ide.ideType,
|
|
226
|
+
instanceId: ide.instanceId,
|
|
227
|
+
cdpConnected: ide.cdpConnected,
|
|
228
|
+
})),
|
|
281
229
|
// managedClis: server only saves id, type, name
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
230
|
+
managedClis: managedClis.map(c => ({
|
|
231
|
+
id: c.id, cliType: c.cliType, cliName: c.cliName,
|
|
232
|
+
})),
|
|
285
233
|
// managedAcps: server only saves id, type, name
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
234
|
+
managedAcps: managedAcps?.map((a: any) => ({
|
|
235
|
+
id: a.id, acpType: a.acpType, acpName: a.acpName,
|
|
236
|
+
})),
|
|
237
|
+
p2p: payload.p2p,
|
|
238
|
+
timestamp: now,
|
|
239
|
+
};
|
|
240
|
+
serverConn.sendMessage('status_report', wsPayload);
|
|
241
|
+
LOG.debug('Server', `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
|
|
295
242
|
}
|
|
296
243
|
|
|
297
244
|
// ─── P2P ─────────────────────────────────────────
|