@adhdev/daemon-core 0.6.79 → 0.7.1
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.mts +84 -87
- package/dist/index.d.ts +84 -87
- package/dist/index.js +798 -706
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +797 -702
- package/dist/index.mjs.map +1 -1
- package/dist/{normalize-igHDb198.d.mts → normalize-S2PmiRgB.d.mts} +32 -53
- package/dist/{normalize-igHDb198.d.ts → normalize-S2PmiRgB.d.ts} +32 -53
- package/dist/status/normalize.d.mts +1 -1
- package/dist/status/normalize.d.ts +1 -1
- package/package.json +1 -1
- package/src/agent-stream/manager.ts +203 -180
- package/src/agent-stream/poller.ts +45 -22
- package/src/boot/daemon-lifecycle.ts +28 -9
- package/src/cdp/initializer.ts +47 -0
- package/src/cdp/manager.ts +19 -1
- package/src/cdp/setup.ts +26 -11
- package/src/commands/chat-commands.ts +136 -88
- package/src/commands/cli-manager.ts +31 -6
- package/src/commands/handler.ts +69 -138
- package/src/commands/router.ts +4 -20
- package/src/commands/stream-commands.ts +34 -162
- package/src/daemon-core.ts +3 -9
- package/src/index.ts +6 -5
- package/src/logging/command-log.ts +1 -1
- package/src/providers/acp-provider-instance.ts +4 -0
- package/src/providers/provider-instance-manager.ts +1 -0
- package/src/sessions/registry.ts +76 -0
- package/src/shared-types.ts +45 -54
- package/src/status/builders.ts +156 -120
- package/src/status/reporter.ts +16 -15
- package/src/status/snapshot.ts +3 -11
package/src/commands/handler.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the correct CDP manager or CLI adapter.
|
|
6
6
|
*
|
|
7
7
|
* Key concepts:
|
|
8
|
-
* - extractIdeType(): determines target IDE from
|
|
8
|
+
* - extractIdeType(): determines target IDE from targetSessionId or ideType
|
|
9
9
|
* - getCdp(): returns the DaemonCdpManager for current command
|
|
10
10
|
* - getProvider(): returns the ProviderModule for current command
|
|
11
11
|
* - handle(): main entry point, sets context then dispatches
|
|
@@ -20,6 +20,7 @@ import type { ProviderModule } from '../providers/contracts.js';
|
|
|
20
20
|
import type { DaemonAgentStreamManager } from '../agent-stream/index.js';
|
|
21
21
|
import { loadConfig } from '../config/config.js';
|
|
22
22
|
import { ChatHistoryWriter } from '../config/chat-history.js';
|
|
23
|
+
import type { SessionRegistry, SessionRuntimeTarget } from '../sessions/registry.js';
|
|
23
24
|
import { LOG } from '../logging/logger.js';
|
|
24
25
|
|
|
25
26
|
// Sub-module imports
|
|
@@ -42,8 +43,7 @@ export interface CommandContext {
|
|
|
42
43
|
providerLoader?: ProviderLoader;
|
|
43
44
|
/** ProviderInstanceManager — for runtime settings propagation */
|
|
44
45
|
instanceManager?: ProviderInstanceManager;
|
|
45
|
-
|
|
46
|
-
instanceIdMap?: Map<string, string>;
|
|
46
|
+
sessionRegistry?: SessionRegistry;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
@@ -56,8 +56,10 @@ export interface CommandHelpers {
|
|
|
56
56
|
getProviderScript(scriptName: string, params?: Record<string, string>, ideType?: string): string | null;
|
|
57
57
|
evaluateProviderScript(scriptName: string, params?: Record<string, string>, timeout?: number): Promise<{ result: any; category: string } | null>;
|
|
58
58
|
getCliAdapter(type?: string): any | null;
|
|
59
|
+
readonly currentManagerKey: string | undefined;
|
|
59
60
|
readonly currentIdeType: string | undefined;
|
|
60
61
|
readonly currentProviderType: string | undefined;
|
|
62
|
+
readonly currentSession: SessionRuntimeTarget | undefined;
|
|
61
63
|
readonly agentStream: DaemonAgentStreamManager | null;
|
|
62
64
|
readonly ctx: CommandContext;
|
|
63
65
|
readonly historyWriter: ChatHistoryWriter;
|
|
@@ -69,10 +71,12 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
69
71
|
private domHandlers: CdpDomHandlers;
|
|
70
72
|
private _historyWriter: ChatHistoryWriter;
|
|
71
73
|
|
|
72
|
-
/** Current
|
|
73
|
-
private
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
/** Current request route context */
|
|
75
|
+
private _currentRoute: {
|
|
76
|
+
session?: SessionRuntimeTarget;
|
|
77
|
+
managerKey?: string;
|
|
78
|
+
providerType?: string;
|
|
79
|
+
} = {};
|
|
76
80
|
|
|
77
81
|
constructor(ctx: CommandContext) {
|
|
78
82
|
this._ctx = ctx;
|
|
@@ -85,19 +89,18 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
85
89
|
get ctx(): CommandContext { return this._ctx; }
|
|
86
90
|
get agentStream(): DaemonAgentStreamManager | null { return this._agentStream; }
|
|
87
91
|
get historyWriter(): ChatHistoryWriter { return this._historyWriter; }
|
|
88
|
-
get
|
|
89
|
-
get
|
|
92
|
+
get currentManagerKey(): string | undefined { return this._currentRoute.managerKey; }
|
|
93
|
+
get currentIdeType(): string | undefined { return this._currentRoute.managerKey; }
|
|
94
|
+
get currentProviderType(): string | undefined { return this._currentRoute.providerType; }
|
|
95
|
+
get currentSession(): SessionRuntimeTarget | undefined { return this._currentRoute.session; }
|
|
90
96
|
|
|
91
|
-
/** Get CDP manager for a specific
|
|
92
|
-
* Supports exact match, multi-window prefix match, and instanceIdMap UUID lookup.
|
|
93
|
-
* Returns null if no match — never falls back to another IDE. */
|
|
97
|
+
/** Get CDP manager for a specific session or manager key. */
|
|
94
98
|
getCdp(ideType?: string): DaemonCdpManager | null {
|
|
95
|
-
const
|
|
96
|
-
if (!
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
const m = findCdpManager(this._ctx.cdpManagers, resolved);
|
|
99
|
+
const requested = ideType || this._currentRoute.session?.sessionId || this._currentRoute.managerKey;
|
|
100
|
+
if (!requested) return null;
|
|
101
|
+
const session = this._ctx.sessionRegistry?.get(requested);
|
|
102
|
+
const managerKey = session?.cdpManagerKey || requested;
|
|
103
|
+
const m = findCdpManager(this._ctx.cdpManagers, managerKey);
|
|
101
104
|
if (m?.isConnected) return m;
|
|
102
105
|
return null;
|
|
103
106
|
}
|
|
@@ -106,7 +109,7 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
106
109
|
* Get provider module — _currentProviderType (agentType priority) use.
|
|
107
110
|
*/
|
|
108
111
|
getProvider(overrideType?: string): ProviderModule | undefined {
|
|
109
|
-
const key = overrideType || this.
|
|
112
|
+
const key = overrideType || this._currentRoute.providerType || this._currentRoute.session?.providerType || this._currentRoute.managerKey;
|
|
110
113
|
if (!key || !this._ctx.providerLoader) return undefined;
|
|
111
114
|
const result = this._ctx.providerLoader.resolve(key);
|
|
112
115
|
if (result) return result;
|
|
@@ -148,14 +151,22 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
148
151
|
|
|
149
152
|
// Extension: evaluateInSession
|
|
150
153
|
if (provider?.category === 'extension') {
|
|
151
|
-
let sessionId = this.
|
|
152
|
-
if (!sessionId && this.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
let sessionId: string | null = this._currentRoute.session?.sessionId || null;
|
|
155
|
+
if (!sessionId && this._currentRoute.session?.parentSessionId) {
|
|
156
|
+
sessionId = this._agentStream?.resolveSessionForAgent(this._currentRoute.session.parentSessionId, provider.type) || null;
|
|
157
|
+
}
|
|
158
|
+
if (sessionId && this._agentStream) {
|
|
159
|
+
const target = this._ctx.sessionRegistry?.get(sessionId);
|
|
160
|
+
if (target?.parentSessionId) {
|
|
161
|
+
await this._agentStream.setActiveSession(cdp, target.parentSessionId, sessionId);
|
|
162
|
+
await this._agentStream.syncActiveSession(cdp, target.parentSessionId);
|
|
163
|
+
}
|
|
156
164
|
}
|
|
157
165
|
if (!sessionId) return null;
|
|
158
|
-
const
|
|
166
|
+
const managed = this._agentStream?.getManagedSession(sessionId);
|
|
167
|
+
const cdpSessionId = managed?.cdpSessionId;
|
|
168
|
+
if (!cdpSessionId) return null;
|
|
169
|
+
const result = await cdp.evaluateInSessionFrame(cdpSessionId, script, timeout);
|
|
159
170
|
return { result, category: 'extension' };
|
|
160
171
|
}
|
|
161
172
|
|
|
@@ -166,79 +177,47 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
166
177
|
|
|
167
178
|
/** CLI adapter search */
|
|
168
179
|
getCliAdapter(type?: string): any | null {
|
|
169
|
-
const target = type || this.
|
|
180
|
+
const target = type || this._currentRoute.session?.sessionId || this._currentRoute.providerType || this._currentRoute.managerKey;
|
|
170
181
|
if (!target || !this._ctx.adapters) return null;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
let normalizedTarget = target;
|
|
175
|
-
const colonIdx = normalizedTarget.lastIndexOf(':');
|
|
176
|
-
if (colonIdx >= 0) normalizedTarget = normalizedTarget.substring(colonIdx + 1);
|
|
177
|
-
|
|
178
|
-
const direct = this._ctx.adapters.get(normalizedTarget);
|
|
179
|
-
if (direct) return direct;
|
|
180
|
-
|
|
181
|
-
for (const [key, adapter] of this._ctx.adapters.entries()) {
|
|
182
|
-
if (
|
|
183
|
-
(adapter as any).cliType === target
|
|
184
|
-
|| (adapter as any).cliType === normalizedTarget
|
|
185
|
-
|| key === normalizedTarget
|
|
186
|
-
|| key.startsWith(target)
|
|
187
|
-
|| key.startsWith(normalizedTarget)
|
|
188
|
-
) {
|
|
189
|
-
return adapter;
|
|
190
|
-
}
|
|
182
|
+
const session = this._ctx.sessionRegistry?.get(target);
|
|
183
|
+
if (session?.adapterKey) {
|
|
184
|
+
return this._ctx.adapters.get(session.adapterKey) || null;
|
|
191
185
|
}
|
|
192
|
-
return null;
|
|
186
|
+
return this._ctx.adapters.get(target) || null;
|
|
193
187
|
}
|
|
194
188
|
|
|
195
189
|
// ─── Private helpers ──────────────────────────────
|
|
196
190
|
|
|
197
|
-
private
|
|
198
|
-
if (
|
|
199
|
-
const
|
|
200
|
-
|
|
191
|
+
private inferProviderType(key: string | undefined): string | undefined {
|
|
192
|
+
if (!key) return undefined;
|
|
193
|
+
const session = this._ctx.sessionRegistry?.get(key);
|
|
194
|
+
if (session?.providerType) return session.providerType;
|
|
195
|
+
return key.split('_')[0];
|
|
201
196
|
}
|
|
202
197
|
|
|
203
|
-
private
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (typeof instance?.getInstanceId === 'function' && instance.getInstanceId() === instanceId) {
|
|
214
|
-
const managerKey = instanceKey.slice(4);
|
|
215
|
-
this._ctx.instanceIdMap?.set(instanceId, managerKey);
|
|
216
|
-
return managerKey;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (typeof instance?.getExtensionInstances === 'function') {
|
|
220
|
-
for (const ext of instance.getExtensionInstances() || []) {
|
|
221
|
-
if (typeof ext?.getInstanceId === 'function' && ext.getInstanceId() === instanceId) {
|
|
222
|
-
const managerKey = instanceKey.slice(4);
|
|
223
|
-
this._ctx.instanceIdMap?.set(instanceId, managerKey);
|
|
224
|
-
return managerKey;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return undefined;
|
|
198
|
+
private resolveRoute(args: any): { session?: SessionRuntimeTarget; managerKey?: string; providerType?: string } {
|
|
199
|
+
const session = this._ctx.sessionRegistry?.get(args?.targetSessionId);
|
|
200
|
+
const managerKey = this.extractIdeType(args);
|
|
201
|
+
const providerType =
|
|
202
|
+
args?.agentType
|
|
203
|
+
|| args?.providerType
|
|
204
|
+
|| session?.providerType
|
|
205
|
+
|| this.inferProviderType(managerKey);
|
|
206
|
+
return { session, managerKey, providerType };
|
|
231
207
|
}
|
|
232
208
|
|
|
233
|
-
/** Extract
|
|
209
|
+
/** Extract CDP scope key from target session or explicit ideType */
|
|
234
210
|
private extractIdeType(args: any): string | undefined {
|
|
211
|
+
if (args?.targetSessionId) {
|
|
212
|
+
const target = this._ctx.sessionRegistry?.get(args.targetSessionId);
|
|
213
|
+
if (target?.cdpManagerKey) return target.cdpManagerKey;
|
|
214
|
+
if (this._ctx.cdpManagers.has(args.targetSessionId)) return args.targetSessionId;
|
|
215
|
+
}
|
|
216
|
+
|
|
235
217
|
// Also accept explicit ideType from args (P2P input, agentType for extensions)
|
|
236
218
|
if (args?.ideType) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (mappedKey) {
|
|
240
|
-
return mappedKey;
|
|
241
|
-
}
|
|
219
|
+
const target = this._ctx.sessionRegistry?.get(args.ideType);
|
|
220
|
+
if (target?.cdpManagerKey) return target.cdpManagerKey;
|
|
242
221
|
// Exact match first
|
|
243
222
|
if (this._ctx.cdpManagers.has(args.ideType)) {
|
|
244
223
|
return args.ideType;
|
|
@@ -253,46 +232,6 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
253
232
|
}
|
|
254
233
|
}
|
|
255
234
|
|
|
256
|
-
if (args?._targetInstance) {
|
|
257
|
-
let raw = args._targetInstance as string;
|
|
258
|
-
const ideMatch = raw.match(/:ide:(.+)$/);
|
|
259
|
-
const cliMatch = raw.match(/:cli:(.+)$/);
|
|
260
|
-
const acpMatch = raw.match(/:acp:(.+)$/);
|
|
261
|
-
if (ideMatch) raw = ideMatch[1];
|
|
262
|
-
else if (cliMatch) raw = cliMatch[1];
|
|
263
|
-
else if (acpMatch) raw = acpMatch[1];
|
|
264
|
-
|
|
265
|
-
const mappedKey = this.resolveManagerKeyFromInstanceId(raw);
|
|
266
|
-
if (mappedKey) {
|
|
267
|
-
return mappedKey;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Direct CDP manager key match (e.g. "cursor", "cursor_remote_vs")
|
|
271
|
-
if (this._ctx.cdpManagers.has(raw)) {
|
|
272
|
-
return raw;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Prefix match for multi-window keys
|
|
276
|
-
const found = findCdpManager(this._ctx.cdpManagers, raw);
|
|
277
|
-
if (found) {
|
|
278
|
-
for (const [k, m] of this._ctx.cdpManagers.entries()) {
|
|
279
|
-
if (m === found) return k;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Fallback removed: returning first-connected CDP was the root cause of
|
|
284
|
-
// input routing to wrong IDE (e.g. screenshot shows Cursor but input goes
|
|
285
|
-
// to Antigravity). If no match is found, return undefined so the caller
|
|
286
|
-
// gets an explicit error rather than silently routing to the wrong IDE.
|
|
287
|
-
|
|
288
|
-
// Legacy: strip trailing _N suffix (e.g. "cursor_1" → "cursor")
|
|
289
|
-
const lastUnderscore = raw.lastIndexOf('_');
|
|
290
|
-
if (lastUnderscore > 0) {
|
|
291
|
-
const stripped = raw.substring(0, lastUnderscore);
|
|
292
|
-
if (this._ctx.cdpManagers.has(stripped)) return stripped;
|
|
293
|
-
}
|
|
294
|
-
return raw;
|
|
295
|
-
}
|
|
296
235
|
return undefined;
|
|
297
236
|
}
|
|
298
237
|
|
|
@@ -303,15 +242,14 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
303
242
|
// ─── Command Dispatcher ──────────────────────────
|
|
304
243
|
|
|
305
244
|
async handle(cmd: string, args: any): Promise<CommandResult> {
|
|
306
|
-
// Per-request: extract target
|
|
307
|
-
this.
|
|
308
|
-
this._currentProviderType = args?.agentType || args?.providerType || this._currentIdeType;
|
|
245
|
+
// Per-request: extract target session / CDP scope / provider type from args
|
|
246
|
+
this._currentRoute = this.resolveRoute(args);
|
|
309
247
|
|
|
310
248
|
// Commands without ideType CDP silently fail (prevent P2P retry spam)
|
|
311
|
-
if (!this.
|
|
249
|
+
if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
|
|
312
250
|
const cdpCommands = ['send_chat', 'read_chat', 'list_chats', 'new_chat', 'switch_chat', 'set_mode', 'change_model', 'set_thought_level', 'resolve_action'];
|
|
313
251
|
if (cdpCommands.includes(cmd)) {
|
|
314
|
-
return { success: false, error: 'No
|
|
252
|
+
return { success: false, error: 'No targetSessionId specified — cannot route command' };
|
|
315
253
|
}
|
|
316
254
|
}
|
|
317
255
|
|
|
@@ -382,14 +320,7 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
382
320
|
case 'refresh_scripts': return this.handleRefreshScripts(args);
|
|
383
321
|
|
|
384
322
|
// ─── Stream commands (stream-commands.ts) ───────────
|
|
385
|
-
case '
|
|
386
|
-
case 'agent_stream_read': return Stream.handleAgentStreamRead(this, args);
|
|
387
|
-
case 'agent_stream_send': return Stream.handleAgentStreamSend(this, args);
|
|
388
|
-
case 'agent_stream_resolve': return Stream.handleAgentStreamResolve(this, args);
|
|
389
|
-
case 'agent_stream_new': return Stream.handleAgentStreamNew(this, args);
|
|
390
|
-
case 'agent_stream_list_chats': return Stream.handleAgentStreamListChats(this, args);
|
|
391
|
-
case 'agent_stream_switch_session': return Stream.handleAgentStreamSwitchSession(this, args);
|
|
392
|
-
case 'agent_stream_focus': return Stream.handleAgentStreamFocus(this, args);
|
|
323
|
+
case 'focus_session': return Stream.handleFocusSession(this, args);
|
|
393
324
|
|
|
394
325
|
// ─── PTY Raw I/O (stream-commands.ts) ─────────
|
|
395
326
|
case 'pty_input': return Stream.handlePtyInput(this, args);
|
package/src/commands/router.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { resolveIdeLaunchWorkspace } from '../config/workspaces.js';
|
|
|
21
21
|
import { appendWorkspaceActivity } from '../config/workspace-activity.js';
|
|
22
22
|
import { addCliHistory } from '../config/config.js';
|
|
23
23
|
import { detectIDEs } from '../detection/ide-detector.js';
|
|
24
|
+
import { SessionRegistry } from '../sessions/registry.js';
|
|
24
25
|
import { LOG } from '../logging/logger.js';
|
|
25
26
|
import { logCommand } from '../logging/command-log.js';
|
|
26
27
|
import { getRecentLogs, LOG_PATH } from '../logging/logger.js';
|
|
@@ -36,8 +37,7 @@ export interface CommandRouterDeps {
|
|
|
36
37
|
instanceManager: ProviderInstanceManager;
|
|
37
38
|
/** Reference to detected IDEs array (mutable — router updates it) */
|
|
38
39
|
detectedIdes: { value: any[] };
|
|
39
|
-
|
|
40
|
-
instanceIdMap: Map<string, string>;
|
|
40
|
+
sessionRegistry: SessionRegistry;
|
|
41
41
|
/** Callback for CDP manager creation after launch_ide */
|
|
42
42
|
onCdpManagerCreated?: (ideType: string, manager: DaemonCdpManager) => void;
|
|
43
43
|
/** Callback after IDE connected (e.g., startAgentStreamPolling) */
|
|
@@ -60,7 +60,7 @@ export interface CommandRouterResult {
|
|
|
60
60
|
// Commands that trigger post-chat status updates
|
|
61
61
|
const CHAT_COMMANDS = [
|
|
62
62
|
'send_chat', 'new_chat', 'switch_chat', 'set_mode',
|
|
63
|
-
'change_model',
|
|
63
|
+
'change_model',
|
|
64
64
|
];
|
|
65
65
|
|
|
66
66
|
export class DaemonCommandRouter {
|
|
@@ -344,6 +344,7 @@ export class DaemonCommandRouter {
|
|
|
344
344
|
if (cdp) {
|
|
345
345
|
try { cdp.disconnect(); } catch { /* noop */ }
|
|
346
346
|
this.deps.cdpManagers.delete(key);
|
|
347
|
+
this.deps.sessionRegistry.unregisterByManagerKey(key);
|
|
347
348
|
LOG.info('StopIDE', `CDP disconnected: ${key}`);
|
|
348
349
|
}
|
|
349
350
|
}
|
|
@@ -358,15 +359,6 @@ export class DaemonCommandRouter {
|
|
|
358
359
|
for (const instanceKey of keysToRemove) {
|
|
359
360
|
const ideInstance = this.deps.instanceManager.getInstance(instanceKey) as any;
|
|
360
361
|
if (ideInstance) {
|
|
361
|
-
// Remove IDE and child Extension UUIDs from instanceIdMap
|
|
362
|
-
if (ideInstance.getInstanceId) {
|
|
363
|
-
this.deps.instanceIdMap.delete(ideInstance.getInstanceId());
|
|
364
|
-
}
|
|
365
|
-
if (ideInstance.getExtensionInstances) {
|
|
366
|
-
for (const ext of ideInstance.getExtensionInstances()) {
|
|
367
|
-
if (ext.getInstanceId) this.deps.instanceIdMap.delete(ext.getInstanceId());
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
362
|
this.deps.instanceManager.removeInstance(instanceKey);
|
|
371
363
|
LOG.info('StopIDE', `Instance removed: ${instanceKey}`);
|
|
372
364
|
}
|
|
@@ -376,14 +368,6 @@ export class DaemonCommandRouter {
|
|
|
376
368
|
const instanceKey = `ide:${ideType}`;
|
|
377
369
|
const ideInstance = this.deps.instanceManager.getInstance(instanceKey) as any;
|
|
378
370
|
if (ideInstance) {
|
|
379
|
-
if (ideInstance.getInstanceId) {
|
|
380
|
-
this.deps.instanceIdMap.delete(ideInstance.getInstanceId());
|
|
381
|
-
}
|
|
382
|
-
if (ideInstance.getExtensionInstances) {
|
|
383
|
-
for (const ext of ideInstance.getExtensionInstances()) {
|
|
384
|
-
if (ext.getInstanceId) this.deps.instanceIdMap.delete(ext.getInstanceId());
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
371
|
this.deps.instanceManager.removeInstance(instanceKey);
|
|
388
372
|
LOG.info('StopIDE', `Instance removed: ${instanceKey}`);
|
|
389
373
|
}
|
|
@@ -8,172 +8,41 @@ import type { ProviderLoader } from '../providers/provider-loader.js';
|
|
|
8
8
|
import { loadConfig } from '../config/config.js';
|
|
9
9
|
import { LOG } from '../logging/logger.js';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export async function handleAgentStreamSwitch(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
14
|
-
if (!h.agentStream || !h.getCdp() || !h.currentIdeType) return { success: false, error: 'AgentStream or CDP not available' };
|
|
15
|
-
const agentType = args?.agentType || args?.agent || null;
|
|
16
|
-
await h.agentStream.switchActiveAgent(h.getCdp()!, h.currentIdeType, agentType);
|
|
17
|
-
return { success: true, activeAgent: agentType };
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export async function handleAgentStreamRead(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
21
|
-
if (!h.agentStream || !h.getCdp() || !h.currentIdeType) return { success: false, error: 'AgentStream or CDP not available' };
|
|
22
|
-
const streams = await h.agentStream.collectAgentStreams(h.getCdp()!, h.currentIdeType);
|
|
23
|
-
return { success: true, streams };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function handleAgentStreamSend(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
27
|
-
const agentType = args?.agentType || args?.agent;
|
|
28
|
-
const text = args?.text || args?.message;
|
|
29
|
-
if (!text) return { success: false, error: 'text required' };
|
|
30
|
-
|
|
31
|
-
// CLI adapter routing
|
|
32
|
-
if (agentType && h.ctx.adapters) {
|
|
33
|
-
for (const [key, adapter] of h.ctx.adapters.entries()) {
|
|
34
|
-
if (adapter.cliType === agentType || key.includes(agentType)) {
|
|
35
|
-
LOG.info('Command', `[agent_stream_send] Routing to CLI adapter: ${adapter.cliType}`);
|
|
36
|
-
try {
|
|
37
|
-
await adapter.sendMessage(text);
|
|
38
|
-
return { success: true, sent: true, targetAgent: adapter.cliType };
|
|
39
|
-
} catch (e: any) {
|
|
40
|
-
LOG.info('Command', `[agent_stream_send] CLI adapter failed: ${e.message}`);
|
|
41
|
-
return { success: false, error: `CLI send failed: ${e.message}` };
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// CDP-based IDE agent routing
|
|
48
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
49
|
-
const resolvedAgent = agentType || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
|
|
50
|
-
if (!resolvedAgent) return { success: false, error: 'agentType required' };
|
|
51
|
-
if (!h.currentIdeType) return { success: false, error: 'ideType required' };
|
|
52
|
-
const ok = await h.agentStream.sendToAgent(h.getCdp()!, h.currentIdeType, resolvedAgent, text, h.currentIdeType);
|
|
53
|
-
return { success: ok };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export async function handleAgentStreamResolve(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
57
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
58
|
-
const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
|
|
59
|
-
const action = args?.action as 'approve' | 'reject' || 'approve';
|
|
60
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
61
|
-
if (!h.currentIdeType) return { success: false, error: 'ideType required' };
|
|
62
|
-
const ok = await h.agentStream.resolveAgentAction(h.getCdp()!, h.currentIdeType, agentType, action, h.currentIdeType);
|
|
63
|
-
return { success: ok };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export async function handleAgentStreamNew(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
67
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
68
|
-
const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
|
|
69
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
70
|
-
if (!h.currentIdeType) return { success: false, error: 'ideType required' };
|
|
71
|
-
const ok = await h.agentStream.newAgentSession(h.getCdp()!, h.currentIdeType, agentType, h.currentIdeType);
|
|
72
|
-
return { success: ok };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export async function handleAgentStreamListChats(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
76
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
77
|
-
const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
|
|
78
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
79
|
-
if (!h.currentIdeType) return { success: false, error: 'ideType required' };
|
|
80
|
-
const chats = await h.agentStream.listAgentChats(h.getCdp()!, h.currentIdeType, agentType);
|
|
81
|
-
return { success: true, chats };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export async function handleAgentStreamSwitchSession(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
11
|
+
export async function handleFocusSession(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
85
12
|
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (!h.currentIdeType) return { success: false, error: 'ideType required' };
|
|
90
|
-
const ok = await h.agentStream.switchAgentSession(h.getCdp()!, h.currentIdeType, agentType, sessionId);
|
|
91
|
-
return { success: ok };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export async function handleAgentStreamFocus(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
95
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
96
|
-
const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
|
|
97
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
98
|
-
await h.agentStream.ensureAgentPanelOpen(agentType, h.currentIdeType);
|
|
99
|
-
if (!h.currentIdeType) return { success: false, error: 'ideType required' };
|
|
100
|
-
const ok = await h.agentStream.focusAgentEditor(h.getCdp()!, h.currentIdeType, agentType);
|
|
13
|
+
const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
|
|
14
|
+
if (!sessionId) return { success: false, error: 'targetSessionId required' };
|
|
15
|
+
const ok = await h.agentStream.focusSession(h.getCdp()!, sessionId);
|
|
101
16
|
return { success: ok };
|
|
102
17
|
}
|
|
103
18
|
|
|
104
19
|
// ─── PTY Raw I/O ──────────────────────────────────
|
|
105
20
|
|
|
106
21
|
export function handlePtyInput(h: CommandHelpers, args: any): CommandResult {
|
|
107
|
-
const { cliType, data } = args || {};
|
|
22
|
+
const { cliType, data, targetSessionId } = args || {};
|
|
108
23
|
if (!data) return { success: false, error: 'data required' };
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
if (!targetCli && h.ctx.adapters.size > 0) {
|
|
113
|
-
const first = h.ctx.adapters.values().next().value;
|
|
114
|
-
if (first && typeof first.writeRaw === 'function') {
|
|
115
|
-
first.writeRaw(data);
|
|
116
|
-
return { success: true };
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const directAdapter = h.ctx.adapters.get(targetCli);
|
|
120
|
-
if (directAdapter && typeof directAdapter.writeRaw === 'function') {
|
|
121
|
-
directAdapter.writeRaw(data);
|
|
122
|
-
return { success: true };
|
|
123
|
-
}
|
|
124
|
-
for (const [, adapter] of h.ctx.adapters) {
|
|
125
|
-
if (adapter.cliType === targetCli && typeof adapter.writeRaw === 'function') {
|
|
126
|
-
adapter.writeRaw(data);
|
|
127
|
-
return { success: true };
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
for (const [key, adapter] of h.ctx.adapters) {
|
|
131
|
-
if ((key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.writeRaw === 'function') {
|
|
132
|
-
adapter.writeRaw(data);
|
|
133
|
-
return { success: true };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
24
|
+
const adapter = h.getCliAdapter(targetSessionId || cliType);
|
|
25
|
+
if (!adapter || typeof adapter.writeRaw !== 'function') {
|
|
26
|
+
return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || 'unknown'}` };
|
|
136
27
|
}
|
|
137
|
-
|
|
28
|
+
adapter.writeRaw(data);
|
|
29
|
+
return { success: true };
|
|
138
30
|
}
|
|
139
31
|
|
|
140
32
|
export function handlePtyResize(h: CommandHelpers, args: any): CommandResult {
|
|
141
|
-
const { cliType, cols, rows, force } = args || {};
|
|
33
|
+
const { cliType, cols, rows, force, targetSessionId } = args || {};
|
|
142
34
|
if (!cols || !rows) return { success: false, error: 'cols and rows required' };
|
|
143
|
-
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const directAdapter = h.ctx.adapters.get(targetCli);
|
|
155
|
-
if (directAdapter && typeof directAdapter.resize === 'function') {
|
|
156
|
-
if (force) {
|
|
157
|
-
directAdapter.resize(cols - 1, rows);
|
|
158
|
-
setTimeout(() => directAdapter.resize(cols, rows), 50);
|
|
159
|
-
} else {
|
|
160
|
-
directAdapter.resize(cols, rows);
|
|
161
|
-
}
|
|
162
|
-
return { success: true };
|
|
163
|
-
}
|
|
164
|
-
for (const [key, adapter] of h.ctx.adapters) {
|
|
165
|
-
if ((adapter.cliType === targetCli || key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.resize === 'function') {
|
|
166
|
-
if (force) {
|
|
167
|
-
adapter.resize(cols - 1, rows);
|
|
168
|
-
setTimeout(() => adapter.resize(cols, rows), 50);
|
|
169
|
-
} else {
|
|
170
|
-
adapter.resize(cols, rows);
|
|
171
|
-
}
|
|
172
|
-
return { success: true };
|
|
173
|
-
}
|
|
174
|
-
}
|
|
35
|
+
const adapter = h.getCliAdapter(targetSessionId || cliType);
|
|
36
|
+
if (!adapter || typeof adapter.resize !== 'function') {
|
|
37
|
+
return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || 'unknown'}` };
|
|
38
|
+
}
|
|
39
|
+
if (force) {
|
|
40
|
+
adapter.resize(cols - 1, rows);
|
|
41
|
+
setTimeout(() => adapter.resize(cols, rows), 50);
|
|
42
|
+
} else {
|
|
43
|
+
adapter.resize(cols, rows);
|
|
175
44
|
}
|
|
176
|
-
return { success:
|
|
45
|
+
return { success: true };
|
|
177
46
|
}
|
|
178
47
|
|
|
179
48
|
// ─── Provider Settings ────────────────────────
|
|
@@ -216,7 +85,7 @@ export function handleSetProviderSetting(h: CommandHelpers, args: any): CommandR
|
|
|
216
85
|
|
|
217
86
|
export async function handleExtensionScript(h: CommandHelpers, args: any, scriptName: string): Promise<CommandResult> {
|
|
218
87
|
const { agentType, ideType } = args || {};
|
|
219
|
-
LOG.info('Command', `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType}
|
|
88
|
+
LOG.info('Command', `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} session=${h.currentSession?.sessionId || ''}`);
|
|
220
89
|
if (!agentType) return { success: false, error: 'agentType is required' };
|
|
221
90
|
|
|
222
91
|
const loader = h.ctx.providerLoader;
|
|
@@ -246,7 +115,9 @@ export async function handleExtensionScript(h: CommandHelpers, args: any, script
|
|
|
246
115
|
const scriptCode = scriptFn(normalizedArgs);
|
|
247
116
|
if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
|
|
248
117
|
|
|
249
|
-
const cdpKey = provider.category === 'ide'
|
|
118
|
+
const cdpKey = provider.category === 'ide'
|
|
119
|
+
? (h.currentSession?.cdpManagerKey || h.currentManagerKey || agentType)
|
|
120
|
+
: (h.currentSession?.cdpManagerKey || h.currentManagerKey || ideType);
|
|
250
121
|
LOG.info('Command', `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
|
|
251
122
|
const cdp = h.getCdp(cdpKey);
|
|
252
123
|
if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || 'any'}` };
|
|
@@ -255,14 +126,15 @@ export async function handleExtensionScript(h: CommandHelpers, args: any, script
|
|
|
255
126
|
let result: unknown;
|
|
256
127
|
|
|
257
128
|
if (provider.category === 'extension') {
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
129
|
+
const runtimeSessionId = h.currentSession?.sessionId || args?.targetSessionId;
|
|
130
|
+
if (!runtimeSessionId) return { success: false, error: `No target session found for ${agentType}` };
|
|
131
|
+
const parentSessionId = h.currentSession?.parentSessionId;
|
|
132
|
+
if (parentSessionId) {
|
|
133
|
+
await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
|
|
134
|
+
await h.agentStream?.syncActiveSession(cdp, parentSessionId);
|
|
265
135
|
}
|
|
136
|
+
const managed = runtimeSessionId ? h.agentStream?.getManagedSession(runtimeSessionId) : null;
|
|
137
|
+
const targetSessionId = managed?.cdpSessionId || null;
|
|
266
138
|
|
|
267
139
|
// IDE-level scripts (model/mode) — try session frame first, fallback to main page
|
|
268
140
|
const IDE_LEVEL_SCRIPTS = ['listModes', 'setMode', 'listModels', 'setModel'];
|
|
@@ -344,7 +216,7 @@ export function handleGetIdeExtensions(h: CommandHelpers, args: any): CommandRes
|
|
|
344
216
|
enabled: config.ideSettings?.[ide]?.extensions?.[p.type]?.enabled === true,
|
|
345
217
|
}));
|
|
346
218
|
}
|
|
347
|
-
return { success: true,
|
|
219
|
+
return { success: true, ideExtensions: result };
|
|
348
220
|
}
|
|
349
221
|
|
|
350
222
|
export function handleSetIdeExtension(h: CommandHelpers, args: any): CommandResult {
|
package/src/daemon-core.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { StatusResponse, CommandResult, DaemonEvent } from './types.js';
|
|
9
|
-
import type {
|
|
9
|
+
import type { SessionEntry } from './shared-types.js';
|
|
10
10
|
|
|
11
11
|
export interface DaemonCoreOptions {
|
|
12
12
|
/** Data directory for config, logs */
|
|
@@ -40,12 +40,6 @@ export interface IDaemonCore {
|
|
|
40
40
|
/** Execute a command (send_chat, new_session, etc.) */
|
|
41
41
|
executeCommand(type: string, payload: any, target?: string): Promise<CommandResult>;
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/** Get currently detected/managed CLIs */
|
|
47
|
-
getManagedClis(): ManagedCliEntry[];
|
|
48
|
-
|
|
49
|
-
/** Get currently detected/managed ACP agents */
|
|
50
|
-
getManagedAcps(): ManagedAcpEntry[];
|
|
43
|
+
/** Get current canonical runtime sessions */
|
|
44
|
+
getSessions(): SessionEntry[];
|
|
51
45
|
}
|