@adhdev/daemon-core 0.6.77 → 0.7.0
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 +2342 -0
- package/dist/index.d.ts +86 -932
- package/dist/index.js +879 -664
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14702 -0
- package/dist/index.mjs.map +1 -0
- package/dist/normalize-S2PmiRgB.d.mts +843 -0
- package/dist/normalize-S2PmiRgB.d.ts +843 -0
- package/dist/status/normalize.d.mts +1 -0
- package/dist/status/normalize.d.ts +1 -0
- package/dist/status/normalize.js +73 -0
- package/dist/status/normalize.js.map +1 -0
- package/dist/status/normalize.mjs +45 -0
- package/dist/status/normalize.mjs.map +1 -0
- package/package.json +8 -1
- package/src/agent-stream/manager.ts +213 -150
- package/src/agent-stream/poller.ts +57 -45
- package/src/boot/daemon-lifecycle.ts +30 -12
- package/src/cdp/initializer.ts +47 -0
- package/src/cdp/manager.ts +45 -4
- 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 +71 -109
- package/src/commands/router.ts +4 -20
- package/src/commands/stream-commands.ts +34 -156
- package/src/daemon-core.ts +3 -9
- package/src/index.ts +8 -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 +157 -120
- package/src/status/normalize.ts +64 -0
- 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.toLowerCase());
|
|
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,49 +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];
|
|
196
|
+
}
|
|
197
|
+
|
|
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 };
|
|
201
207
|
}
|
|
202
208
|
|
|
203
|
-
/** Extract
|
|
209
|
+
/** Extract CDP scope key from target session or explicit ideType */
|
|
204
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
|
+
|
|
205
217
|
// Also accept explicit ideType from args (P2P input, agentType for extensions)
|
|
206
218
|
if (args?.ideType) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (mappedKey) {
|
|
210
|
-
return mappedKey;
|
|
211
|
-
}
|
|
219
|
+
const target = this._ctx.sessionRegistry?.get(args.ideType);
|
|
220
|
+
if (target?.cdpManagerKey) return target.cdpManagerKey;
|
|
212
221
|
// Exact match first
|
|
213
222
|
if (this._ctx.cdpManagers.has(args.ideType)) {
|
|
214
223
|
return args.ideType;
|
|
@@ -223,45 +232,6 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
223
232
|
}
|
|
224
233
|
}
|
|
225
234
|
|
|
226
|
-
if (args?._targetInstance) {
|
|
227
|
-
let raw = args._targetInstance as string;
|
|
228
|
-
const ideMatch = raw.match(/:ide:(.+)$/);
|
|
229
|
-
const cliMatch = raw.match(/:cli:(.+)$/);
|
|
230
|
-
const acpMatch = raw.match(/:acp:(.+)$/);
|
|
231
|
-
if (ideMatch) raw = ideMatch[1];
|
|
232
|
-
else if (cliMatch) raw = cliMatch[1];
|
|
233
|
-
else if (acpMatch) raw = acpMatch[1];
|
|
234
|
-
|
|
235
|
-
if (this._ctx.instanceIdMap?.has(raw)) {
|
|
236
|
-
return this._ctx.instanceIdMap.get(raw)!;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Direct CDP manager key match (e.g. "cursor", "cursor_remote_vs")
|
|
240
|
-
if (this._ctx.cdpManagers.has(raw)) {
|
|
241
|
-
return raw;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Prefix match for multi-window keys
|
|
245
|
-
const found = findCdpManager(this._ctx.cdpManagers, raw);
|
|
246
|
-
if (found) {
|
|
247
|
-
for (const [k, m] of this._ctx.cdpManagers.entries()) {
|
|
248
|
-
if (m === found) return k;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Fallback removed: returning first-connected CDP was the root cause of
|
|
253
|
-
// input routing to wrong IDE (e.g. screenshot shows Cursor but input goes
|
|
254
|
-
// to Antigravity). If no match is found, return undefined so the caller
|
|
255
|
-
// gets an explicit error rather than silently routing to the wrong IDE.
|
|
256
|
-
|
|
257
|
-
// Legacy: strip trailing _N suffix (e.g. "cursor_1" → "cursor")
|
|
258
|
-
const lastUnderscore = raw.lastIndexOf('_');
|
|
259
|
-
if (lastUnderscore > 0) {
|
|
260
|
-
const stripped = raw.substring(0, lastUnderscore);
|
|
261
|
-
if (this._ctx.cdpManagers.has(stripped)) return stripped;
|
|
262
|
-
}
|
|
263
|
-
return raw;
|
|
264
|
-
}
|
|
265
235
|
return undefined;
|
|
266
236
|
}
|
|
267
237
|
|
|
@@ -272,15 +242,14 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
272
242
|
// ─── Command Dispatcher ──────────────────────────
|
|
273
243
|
|
|
274
244
|
async handle(cmd: string, args: any): Promise<CommandResult> {
|
|
275
|
-
// Per-request: extract target
|
|
276
|
-
this.
|
|
277
|
-
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);
|
|
278
247
|
|
|
279
248
|
// Commands without ideType CDP silently fail (prevent P2P retry spam)
|
|
280
|
-
if (!this.
|
|
249
|
+
if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
|
|
281
250
|
const cdpCommands = ['send_chat', 'read_chat', 'list_chats', 'new_chat', 'switch_chat', 'set_mode', 'change_model', 'set_thought_level', 'resolve_action'];
|
|
282
251
|
if (cdpCommands.includes(cmd)) {
|
|
283
|
-
return { success: false, error: 'No
|
|
252
|
+
return { success: false, error: 'No targetSessionId specified — cannot route command' };
|
|
284
253
|
}
|
|
285
254
|
}
|
|
286
255
|
|
|
@@ -351,14 +320,7 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
351
320
|
case 'refresh_scripts': return this.handleRefreshScripts(args);
|
|
352
321
|
|
|
353
322
|
// ─── Stream commands (stream-commands.ts) ───────────
|
|
354
|
-
case '
|
|
355
|
-
case 'agent_stream_read': return Stream.handleAgentStreamRead(this, args);
|
|
356
|
-
case 'agent_stream_send': return Stream.handleAgentStreamSend(this, args);
|
|
357
|
-
case 'agent_stream_resolve': return Stream.handleAgentStreamResolve(this, args);
|
|
358
|
-
case 'agent_stream_new': return Stream.handleAgentStreamNew(this, args);
|
|
359
|
-
case 'agent_stream_list_chats': return Stream.handleAgentStreamListChats(this, args);
|
|
360
|
-
case 'agent_stream_switch_session': return Stream.handleAgentStreamSwitchSession(this, args);
|
|
361
|
-
case 'agent_stream_focus': return Stream.handleAgentStreamFocus(this, args);
|
|
323
|
+
case 'focus_session': return Stream.handleFocusSession(this, args);
|
|
362
324
|
|
|
363
325
|
// ─── PTY Raw I/O (stream-commands.ts) ─────────
|
|
364
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,166 +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()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
15
|
-
const agentType = args?.agentType || args?.agent || null;
|
|
16
|
-
await h.agentStream.switchActiveAgent(h.getCdp()!, 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()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
22
|
-
const streams = await h.agentStream.collectAgentStreams(h.getCdp()!);
|
|
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.agentStream.activeAgentType;
|
|
50
|
-
if (!resolvedAgent) return { success: false, error: 'agentType required' };
|
|
51
|
-
const ok = await h.agentStream.sendToAgent(h.getCdp()!, resolvedAgent, text, h.currentIdeType);
|
|
52
|
-
return { success: ok };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export async function handleAgentStreamResolve(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
56
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
57
|
-
const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
|
|
58
|
-
const action = args?.action as 'approve' | 'reject' || 'approve';
|
|
59
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
60
|
-
const ok = await h.agentStream.resolveAgentAction(h.getCdp()!, agentType, action, h.currentIdeType);
|
|
61
|
-
return { success: ok };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export async function handleAgentStreamNew(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
65
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
66
|
-
const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
|
|
67
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
68
|
-
const ok = await h.agentStream.newAgentSession(h.getCdp()!, agentType, h.currentIdeType);
|
|
69
|
-
return { success: ok };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export async function handleAgentStreamListChats(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
73
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
74
|
-
const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
|
|
75
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
76
|
-
const chats = await h.agentStream.listAgentChats(h.getCdp()!, agentType);
|
|
77
|
-
return { success: true, chats };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export async function handleAgentStreamSwitchSession(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
11
|
+
export async function handleFocusSession(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
81
12
|
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const ok = await h.agentStream.switchAgentSession(h.getCdp()!, agentType, sessionId);
|
|
86
|
-
return { success: ok };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export async function handleAgentStreamFocus(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
90
|
-
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
91
|
-
const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
|
|
92
|
-
if (!agentType) return { success: false, error: 'agentType required' };
|
|
93
|
-
await h.agentStream.ensureAgentPanelOpen(agentType, h.currentIdeType);
|
|
94
|
-
const ok = await h.agentStream.focusAgentEditor(h.getCdp()!, 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);
|
|
95
16
|
return { success: ok };
|
|
96
17
|
}
|
|
97
18
|
|
|
98
19
|
// ─── PTY Raw I/O ──────────────────────────────────
|
|
99
20
|
|
|
100
21
|
export function handlePtyInput(h: CommandHelpers, args: any): CommandResult {
|
|
101
|
-
const { cliType, data } = args || {};
|
|
22
|
+
const { cliType, data, targetSessionId } = args || {};
|
|
102
23
|
if (!data) return { success: false, error: 'data required' };
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
if (!targetCli && h.ctx.adapters.size > 0) {
|
|
107
|
-
const first = h.ctx.adapters.values().next().value;
|
|
108
|
-
if (first && typeof first.writeRaw === 'function') {
|
|
109
|
-
first.writeRaw(data);
|
|
110
|
-
return { success: true };
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const directAdapter = h.ctx.adapters.get(targetCli);
|
|
114
|
-
if (directAdapter && typeof directAdapter.writeRaw === 'function') {
|
|
115
|
-
directAdapter.writeRaw(data);
|
|
116
|
-
return { success: true };
|
|
117
|
-
}
|
|
118
|
-
for (const [, adapter] of h.ctx.adapters) {
|
|
119
|
-
if (adapter.cliType === targetCli && typeof adapter.writeRaw === 'function') {
|
|
120
|
-
adapter.writeRaw(data);
|
|
121
|
-
return { success: true };
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
for (const [key, adapter] of h.ctx.adapters) {
|
|
125
|
-
if ((key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.writeRaw === 'function') {
|
|
126
|
-
adapter.writeRaw(data);
|
|
127
|
-
return { success: true };
|
|
128
|
-
}
|
|
129
|
-
}
|
|
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'}` };
|
|
130
27
|
}
|
|
131
|
-
|
|
28
|
+
adapter.writeRaw(data);
|
|
29
|
+
return { success: true };
|
|
132
30
|
}
|
|
133
31
|
|
|
134
32
|
export function handlePtyResize(h: CommandHelpers, args: any): CommandResult {
|
|
135
|
-
const { cliType, cols, rows, force } = args || {};
|
|
33
|
+
const { cliType, cols, rows, force, targetSessionId } = args || {};
|
|
136
34
|
if (!cols || !rows) return { success: false, error: 'cols and rows required' };
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
const directAdapter = h.ctx.adapters.get(targetCli);
|
|
149
|
-
if (directAdapter && typeof directAdapter.resize === 'function') {
|
|
150
|
-
if (force) {
|
|
151
|
-
directAdapter.resize(cols - 1, rows);
|
|
152
|
-
setTimeout(() => directAdapter.resize(cols, rows), 50);
|
|
153
|
-
} else {
|
|
154
|
-
directAdapter.resize(cols, rows);
|
|
155
|
-
}
|
|
156
|
-
return { success: true };
|
|
157
|
-
}
|
|
158
|
-
for (const [key, adapter] of h.ctx.adapters) {
|
|
159
|
-
if ((adapter.cliType === targetCli || key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.resize === 'function') {
|
|
160
|
-
if (force) {
|
|
161
|
-
adapter.resize(cols - 1, rows);
|
|
162
|
-
setTimeout(() => adapter.resize(cols, rows), 50);
|
|
163
|
-
} else {
|
|
164
|
-
adapter.resize(cols, rows);
|
|
165
|
-
}
|
|
166
|
-
return { success: true };
|
|
167
|
-
}
|
|
168
|
-
}
|
|
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);
|
|
169
44
|
}
|
|
170
|
-
return { success:
|
|
45
|
+
return { success: true };
|
|
171
46
|
}
|
|
172
47
|
|
|
173
48
|
// ─── Provider Settings ────────────────────────
|
|
@@ -210,7 +85,7 @@ export function handleSetProviderSetting(h: CommandHelpers, args: any): CommandR
|
|
|
210
85
|
|
|
211
86
|
export async function handleExtensionScript(h: CommandHelpers, args: any, scriptName: string): Promise<CommandResult> {
|
|
212
87
|
const { agentType, ideType } = args || {};
|
|
213
|
-
LOG.info('Command', `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType}
|
|
88
|
+
LOG.info('Command', `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} session=${h.currentSession?.sessionId || ''}`);
|
|
214
89
|
if (!agentType) return { success: false, error: 'agentType is required' };
|
|
215
90
|
|
|
216
91
|
const loader = h.ctx.providerLoader;
|
|
@@ -240,7 +115,9 @@ export async function handleExtensionScript(h: CommandHelpers, args: any, script
|
|
|
240
115
|
const scriptCode = scriptFn(normalizedArgs);
|
|
241
116
|
if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
|
|
242
117
|
|
|
243
|
-
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);
|
|
244
121
|
LOG.info('Command', `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
|
|
245
122
|
const cdp = h.getCdp(cdpKey);
|
|
246
123
|
if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || 'any'}` };
|
|
@@ -249,14 +126,15 @@ export async function handleExtensionScript(h: CommandHelpers, args: any, script
|
|
|
249
126
|
let result: unknown;
|
|
250
127
|
|
|
251
128
|
if (provider.category === 'extension') {
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
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);
|
|
259
135
|
}
|
|
136
|
+
const managed = runtimeSessionId ? h.agentStream?.getManagedSession(runtimeSessionId) : null;
|
|
137
|
+
const targetSessionId = managed?.cdpSessionId || null;
|
|
260
138
|
|
|
261
139
|
// IDE-level scripts (model/mode) — try session frame first, fallback to main page
|
|
262
140
|
const IDE_LEVEL_SCRIPTS = ['listModes', 'setMode', 'listModels', 'setModel'];
|
|
@@ -338,7 +216,7 @@ export function handleGetIdeExtensions(h: CommandHelpers, args: any): CommandRes
|
|
|
338
216
|
enabled: config.ideSettings?.[ide]?.extensions?.[p.type]?.enabled === true,
|
|
339
217
|
}));
|
|
340
218
|
}
|
|
341
|
-
return { success: true,
|
|
219
|
+
return { success: true, ideExtensions: result };
|
|
342
220
|
}
|
|
343
221
|
|
|
344
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
|
}
|
package/src/index.ts
CHANGED
|
@@ -20,10 +20,11 @@ export type {
|
|
|
20
20
|
|
|
21
21
|
// ── Shared Types (cross-package) ──
|
|
22
22
|
export type {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
SessionEntry,
|
|
24
|
+
SessionTransport,
|
|
25
|
+
SessionKind,
|
|
26
|
+
SessionCapability,
|
|
27
|
+
AgentSessionStream,
|
|
27
28
|
AvailableProviderInfo,
|
|
28
29
|
AcpConfigOption,
|
|
29
30
|
AcpMode,
|
|
@@ -74,8 +75,10 @@ export type { CommandRouterDeps, CommandRouterResult } from './commands/router.j
|
|
|
74
75
|
|
|
75
76
|
// ── Status ──
|
|
76
77
|
export { DaemonStatusReporter } from './status/reporter.js';
|
|
77
|
-
export {
|
|
78
|
+
export { buildSessionEntries, findCdpManager, hasCdpManager, isCdpConnected } from './status/builders.js';
|
|
78
79
|
export { buildStatusSnapshot } from './status/snapshot.js';
|
|
80
|
+
export { normalizeManagedStatus, isManagedStatusWorking, isManagedStatusWaiting, normalizeActiveChatData } from './status/normalize.js';
|
|
81
|
+
export type { ManagedStatus } from './status/normalize.js';
|
|
79
82
|
export type { StatusSnapshotOptions, StatusSnapshot } from './status/snapshot.js';
|
|
80
83
|
|
|
81
84
|
// ── Logger ──
|
|
@@ -50,7 +50,7 @@ function maskArgs(args: any): Record<string, unknown> | undefined {
|
|
|
50
50
|
? `[${value.length} chars]`
|
|
51
51
|
: '[masked]';
|
|
52
52
|
} else if (key.startsWith('_')) {
|
|
53
|
-
// internal fields: keep as-is (e.g.
|
|
53
|
+
// internal fields: keep as-is (e.g. targetSessionId)
|
|
54
54
|
masked[key] = value;
|
|
55
55
|
} else if (typeof value === 'object' && value !== null) {
|
|
56
56
|
// Don't recurse deeply — just note the type
|