adhdev 0.6.79 → 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.js CHANGED
@@ -1657,7 +1657,11 @@ var init_manager = __esm({
1657
1657
  async attachToAgent(target) {
1658
1658
  if (!this.isConnected) return null;
1659
1659
  for (const [sid, t] of this.agentSessions) {
1660
- if (t.agentType === target.agentType) return sid;
1660
+ if (t.targetId === target.targetId) return sid;
1661
+ if (t.agentType === target.agentType && t.targetId !== target.targetId) {
1662
+ await this.detachAgent(sid).catch(() => {
1663
+ });
1664
+ }
1661
1665
  }
1662
1666
  try {
1663
1667
  const sendFn = this._browserConnected ? this.sendBrowser.bind(this) : this.sendInternal.bind(this);
@@ -1781,6 +1785,20 @@ var init_manager = __esm({
1781
1785
  }
1782
1786
  async getCurrentPageWebviewUrls() {
1783
1787
  if (!this.isConnected) return /* @__PURE__ */ new Set();
1788
+ try {
1789
+ const urls = /* @__PURE__ */ new Set();
1790
+ const { frameTree } = await this.sendInternal("Page.getFrameTree", {}, 5e3);
1791
+ const visit = (node) => {
1792
+ const url2 = node?.frame?.url;
1793
+ if (typeof url2 === "string" && url2.includes("vscode-webview")) {
1794
+ urls.add(url2);
1795
+ }
1796
+ for (const child of node?.childFrames || []) visit(child);
1797
+ };
1798
+ if (frameTree) visit(frameTree);
1799
+ if (urls.size > 0) return urls;
1800
+ } catch {
1801
+ }
1784
1802
  try {
1785
1803
  const raw = await this.evaluate(
1786
1804
  `JSON.stringify(Array.from(document.querySelectorAll('iframe,webview'))
@@ -2966,7 +2984,7 @@ function registerExtensionProviders(providerLoader, manager, ideType) {
2966
2984
  manager.setExtensionProviders(enabledExtProviders);
2967
2985
  }
2968
2986
  async function setupIdeInstance(ctx, opts) {
2969
- const { providerLoader, instanceManager, instanceIdMap } = ctx;
2987
+ const { providerLoader, instanceManager, sessionRegistry } = ctx;
2970
2988
  const { ideType, manager, settings } = opts;
2971
2989
  const managerKey = opts.managerKey || ideType;
2972
2990
  registerExtensionProviders(providerLoader, manager, ideType);
@@ -2982,14 +3000,30 @@ async function setupIdeInstance(ctx, opts) {
2982
3000
  serverConn: ctx.serverConn,
2983
3001
  settings: resolvedSettings
2984
3002
  });
2985
- instanceIdMap.set(ideInstance.getInstanceId(), managerKey);
3003
+ sessionRegistry.register({
3004
+ sessionId: ideInstance.getInstanceId(),
3005
+ parentSessionId: null,
3006
+ providerType: ideType,
3007
+ providerCategory: "ide",
3008
+ transport: "cdp-page",
3009
+ cdpManagerKey: managerKey,
3010
+ instanceKey: `ide:${managerKey}`
3011
+ });
2986
3012
  const extensionProviders = providerLoader.getEnabledByCategory("extension", ideType);
2987
3013
  for (const extProvider of extensionProviders) {
2988
3014
  const extSettings = providerLoader.getSettings(extProvider.type);
2989
3015
  await ideInstance.addExtension(extProvider, extSettings);
2990
- for (const ext of ideInstance.getExtensionInstances()) {
2991
- instanceIdMap.set(ext.getInstanceId(), managerKey);
2992
- }
3016
+ }
3017
+ for (const ext of ideInstance.getExtensionInstances()) {
3018
+ sessionRegistry.register({
3019
+ sessionId: ext.getInstanceId(),
3020
+ parentSessionId: ideInstance.getInstanceId(),
3021
+ providerType: ext.type,
3022
+ providerCategory: "extension",
3023
+ transport: "cdp-webview",
3024
+ cdpManagerKey: managerKey,
3025
+ instanceKey: `ide:${managerKey}`
3026
+ });
2993
3027
  }
2994
3028
  return ideInstance;
2995
3029
  }
@@ -3075,6 +3109,7 @@ var init_initializer = __esm({
3075
3109
  async connectIdePort(port, ide) {
3076
3110
  const { providerLoader, cdpManagers } = this.config;
3077
3111
  const targets = await DaemonCdpManager.listAllTargets(port);
3112
+ await this.pruneStaleManagers(port, ide, targets);
3078
3113
  if (targets.length === 0) {
3079
3114
  if (cdpManagers.has(ide)) return;
3080
3115
  if (!await probeCdpPort(port)) return;
@@ -3127,6 +3162,34 @@ var init_initializer = __esm({
3127
3162
  }
3128
3163
  }
3129
3164
  }
3165
+ async pruneStaleManagers(port, ide, targets) {
3166
+ const trackedTargetIds = new Set(targets.map((target) => target.id));
3167
+ const removals = [];
3168
+ for (const [key, manager] of this.config.cdpManagers.entries()) {
3169
+ if (!(key === ide || key.startsWith(`${ide}_`))) continue;
3170
+ if (manager.getPort() !== port) continue;
3171
+ if (targets.length === 0) {
3172
+ removals.push({ key, manager, reason: "ide_closed" });
3173
+ continue;
3174
+ }
3175
+ if (manager.targetId && !trackedTargetIds.has(manager.targetId)) {
3176
+ removals.push({ key, manager, reason: "target_closed" });
3177
+ continue;
3178
+ }
3179
+ if (key === ide && !manager.targetId && targets.length > 1) {
3180
+ removals.push({ key, manager, reason: "target_rekeyed" });
3181
+ }
3182
+ }
3183
+ for (const { key, manager, reason } of removals) {
3184
+ try {
3185
+ manager.disconnect();
3186
+ } catch {
3187
+ }
3188
+ this.config.cdpManagers.delete(key);
3189
+ LOG.info("CDP", `Removed stale manager: ${key} (${reason})`);
3190
+ await this.config.onDisconnected?.(ide, manager, key, reason);
3191
+ }
3192
+ }
3130
3193
  // ─── Periodic scanning ───
3131
3194
  /**
3132
3195
  * Start periodic scanning for newly opened IDEs.
@@ -3224,112 +3287,191 @@ function isCdpConnected(cdpManagers, key) {
3224
3287
  const m = findCdpManager(cdpManagers, key);
3225
3288
  return m?.isConnected ?? false;
3226
3289
  }
3227
- function buildManagedIdes(ideStates, cdpManagers, opts) {
3228
- const result = [];
3229
- for (const state of ideStates) {
3230
- const cdpConnected = state.cdpConnected ?? isCdpConnected(cdpManagers, state.type);
3231
- result.push({
3232
- ideType: state.type,
3233
- ideVersion: "",
3234
- instanceId: state.instanceId || state.type,
3235
- workspace: state.workspace || null,
3236
- terminals: 0,
3237
- aiAgents: [],
3238
- activeChat: normalizeActiveChatData(state.activeChat),
3239
- chats: [],
3240
- agentStreams: state.extensions.map((ext) => ({
3241
- agentType: ext.type,
3242
- agentName: ext.name,
3243
- extensionId: ext.type,
3244
- status: normalizeManagedStatus(ext.status, { activeModal: ext.activeChat?.activeModal || null }),
3245
- messages: ext.activeChat?.messages || [],
3246
- inputContent: ext.activeChat?.inputContent || "",
3247
- activeModal: ext.activeChat?.activeModal || null
3248
- })),
3249
- cdpConnected,
3250
- currentModel: state.currentModel,
3251
- currentPlan: state.currentPlan,
3252
- currentAutoApprove: state.currentAutoApprove
3253
- });
3254
- }
3255
- if (opts?.detectedIdes) {
3256
- const coveredTypes = new Set(ideStates.map((s15) => s15.type));
3257
- for (const ide of opts.detectedIdes) {
3258
- if (!ide.installed || coveredTypes.has(ide.id)) continue;
3259
- if (!isCdpConnected(cdpManagers, ide.id)) continue;
3260
- result.push({
3261
- ideType: ide.id,
3262
- ideVersion: "",
3263
- instanceId: ide.id,
3264
- workspace: null,
3265
- terminals: 0,
3266
- aiAgents: [],
3267
- activeChat: null,
3268
- chats: [],
3269
- agentStreams: [],
3270
- cdpConnected: true,
3271
- currentModel: void 0,
3272
- currentPlan: void 0
3273
- });
3274
- }
3275
- }
3276
- return result;
3290
+ function buildIdeWorkspaceSession(state, cdpManagers) {
3291
+ const activeChat = normalizeActiveChatData(state.activeChat);
3292
+ const title = activeChat?.title || state.name;
3293
+ return {
3294
+ id: state.instanceId || state.type,
3295
+ parentId: null,
3296
+ providerType: state.type,
3297
+ providerName: state.name,
3298
+ kind: "workspace",
3299
+ transport: "cdp-page",
3300
+ status: normalizeManagedStatus(activeChat?.status || state.status, {
3301
+ activeModal: activeChat?.activeModal || null
3302
+ }),
3303
+ title,
3304
+ workspace: state.workspace || null,
3305
+ activeChat,
3306
+ capabilities: IDE_SESSION_CAPABILITIES,
3307
+ cdpConnected: state.cdpConnected ?? isCdpConnected(cdpManagers, state.type),
3308
+ currentModel: state.currentModel,
3309
+ currentPlan: state.currentPlan,
3310
+ currentAutoApprove: state.currentAutoApprove,
3311
+ errorMessage: state.errorMessage,
3312
+ errorReason: state.errorReason
3313
+ };
3277
3314
  }
3278
- function buildManagedClis(cliStates) {
3279
- return cliStates.map((s15) => ({
3280
- id: s15.instanceId,
3281
- instanceId: s15.instanceId,
3282
- cliType: s15.type,
3283
- cliName: s15.name,
3284
- status: normalizeManagedStatus(s15.status, { activeModal: s15.activeChat?.activeModal || null }),
3285
- mode: "terminal",
3286
- workspace: s15.workspace || "",
3287
- activeChat: normalizeActiveChatData(s15.activeChat)
3288
- }));
3315
+ function buildExtensionAgentSession(parent, ext) {
3316
+ const activeChat = normalizeActiveChatData(ext.activeChat);
3317
+ return {
3318
+ id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
3319
+ parentId: parent.instanceId || parent.type,
3320
+ providerType: ext.type,
3321
+ providerName: ext.name,
3322
+ kind: "agent",
3323
+ transport: "cdp-webview",
3324
+ status: normalizeManagedStatus(activeChat?.status || ext.status, {
3325
+ activeModal: activeChat?.activeModal || null
3326
+ }),
3327
+ title: activeChat?.title || ext.name,
3328
+ workspace: parent.workspace || null,
3329
+ activeChat,
3330
+ capabilities: EXTENSION_SESSION_CAPABILITIES,
3331
+ currentModel: ext.currentModel,
3332
+ currentPlan: ext.currentPlan,
3333
+ errorMessage: ext.errorMessage,
3334
+ errorReason: ext.errorReason
3335
+ };
3289
3336
  }
3290
- function buildManagedAcps(acpStates) {
3291
- return acpStates.map((s15) => ({
3292
- id: s15.instanceId,
3293
- acpType: s15.type,
3294
- acpName: s15.name,
3295
- status: normalizeManagedStatus(s15.status, { activeModal: s15.activeChat?.activeModal || null }),
3296
- mode: "chat",
3297
- workspace: s15.workspace || "",
3298
- activeChat: normalizeActiveChatData(s15.activeChat),
3299
- currentModel: s15.currentModel,
3300
- currentPlan: s15.currentPlan,
3301
- acpConfigOptions: s15.acpConfigOptions,
3302
- acpModes: s15.acpModes,
3303
- errorMessage: s15.errorMessage,
3304
- errorReason: s15.errorReason
3305
- }));
3337
+ function buildCliSession(state) {
3338
+ const activeChat = normalizeActiveChatData(state.activeChat);
3339
+ return {
3340
+ id: state.instanceId,
3341
+ parentId: null,
3342
+ providerType: state.type,
3343
+ providerName: state.name,
3344
+ kind: "agent",
3345
+ transport: "pty",
3346
+ status: normalizeManagedStatus(activeChat?.status || state.status, {
3347
+ activeModal: activeChat?.activeModal || null
3348
+ }),
3349
+ title: activeChat?.title || state.name,
3350
+ workspace: state.workspace || null,
3351
+ activeChat,
3352
+ capabilities: PTY_SESSION_CAPABILITIES,
3353
+ errorMessage: state.errorMessage,
3354
+ errorReason: state.errorReason
3355
+ };
3306
3356
  }
3307
- function buildAllManagedEntries(allStates, cdpManagers, opts) {
3357
+ function buildAcpSession(state) {
3358
+ const activeChat = normalizeActiveChatData(state.activeChat);
3359
+ return {
3360
+ id: state.instanceId,
3361
+ parentId: null,
3362
+ providerType: state.type,
3363
+ providerName: state.name,
3364
+ kind: "agent",
3365
+ transport: "acp",
3366
+ status: normalizeManagedStatus(activeChat?.status || state.status, {
3367
+ activeModal: activeChat?.activeModal || null
3368
+ }),
3369
+ title: activeChat?.title || state.name,
3370
+ workspace: state.workspace || null,
3371
+ activeChat,
3372
+ capabilities: ACP_SESSION_CAPABILITIES,
3373
+ currentModel: state.currentModel,
3374
+ currentPlan: state.currentPlan,
3375
+ acpConfigOptions: state.acpConfigOptions,
3376
+ acpModes: state.acpModes,
3377
+ errorMessage: state.errorMessage,
3378
+ errorReason: state.errorReason
3379
+ };
3380
+ }
3381
+ function buildSessionEntries(allStates, cdpManagers) {
3382
+ const sessions = [];
3308
3383
  const ideStates = allStates.filter((s15) => s15.category === "ide");
3309
3384
  const cliStates = allStates.filter((s15) => s15.category === "cli");
3310
3385
  const acpStates = allStates.filter((s15) => s15.category === "acp");
3311
- return {
3312
- managedIdes: buildManagedIdes(ideStates, cdpManagers, opts),
3313
- managedClis: buildManagedClis(cliStates),
3314
- managedAcps: buildManagedAcps(acpStates)
3315
- };
3386
+ for (const state of ideStates) {
3387
+ sessions.push(buildIdeWorkspaceSession(state, cdpManagers));
3388
+ for (const ext of state.extensions) {
3389
+ sessions.push(buildExtensionAgentSession(state, ext));
3390
+ }
3391
+ }
3392
+ for (const state of cliStates) {
3393
+ sessions.push(buildCliSession(state));
3394
+ }
3395
+ for (const state of acpStates) {
3396
+ sessions.push(buildAcpSession(state));
3397
+ }
3398
+ return sessions;
3316
3399
  }
3400
+ var IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES;
3317
3401
  var init_builders = __esm({
3318
3402
  "../../oss/packages/daemon-core/src/status/builders.ts"() {
3319
3403
  "use strict";
3320
3404
  init_normalize();
3405
+ IDE_SESSION_CAPABILITIES = [
3406
+ "read_chat",
3407
+ "send_message",
3408
+ "new_session",
3409
+ "list_sessions",
3410
+ "switch_session",
3411
+ "resolve_action",
3412
+ "change_model",
3413
+ "set_mode",
3414
+ "set_thought_level"
3415
+ ];
3416
+ EXTENSION_SESSION_CAPABILITIES = [
3417
+ "read_chat",
3418
+ "send_message",
3419
+ "new_session",
3420
+ "list_sessions",
3421
+ "switch_session",
3422
+ "resolve_action",
3423
+ "change_model",
3424
+ "set_mode"
3425
+ ];
3426
+ PTY_SESSION_CAPABILITIES = [
3427
+ "read_chat",
3428
+ "send_message",
3429
+ "resolve_action",
3430
+ "terminal_io",
3431
+ "resize_terminal"
3432
+ ];
3433
+ ACP_SESSION_CAPABILITIES = [
3434
+ "read_chat",
3435
+ "send_message",
3436
+ "new_session",
3437
+ "resolve_action",
3438
+ "change_model",
3439
+ "set_mode",
3440
+ "set_thought_level"
3441
+ ];
3321
3442
  }
3322
3443
  });
3323
3444
 
3324
3445
  // ../../oss/packages/daemon-core/src/commands/chat-commands.ts
3446
+ function getCurrentProviderType(h, fallback = "") {
3447
+ return h.currentSession?.providerType || h.currentProviderType || fallback;
3448
+ }
3449
+ function getCurrentManagerKey(h) {
3450
+ return h.currentSession?.cdpManagerKey || h.currentManagerKey || "";
3451
+ }
3325
3452
  function getTargetedCliAdapter(h, args, providerType) {
3326
- return h.getCliAdapter(args?._targetInstance || h.currentIdeType || providerType);
3453
+ return h.getCliAdapter(args?.targetSessionId || providerType || h.currentSession?.providerType || h.currentManagerKey);
3454
+ }
3455
+ function buildRecentSendKey(h, args, provider, text) {
3456
+ const target = args?.targetSessionId || args?.agentType || h.currentSession?.providerType || h.currentProviderType || h.currentManagerKey || "unknown";
3457
+ return `${provider?.category || "unknown"}:${target}:${text.trim()}`;
3458
+ }
3459
+ function isRecentDuplicateSend(key) {
3460
+ const now = Date.now();
3461
+ for (const [candidate, ts3] of recentSendByTarget.entries()) {
3462
+ if (now - ts3 > RECENT_SEND_WINDOW_MS) recentSendByTarget.delete(candidate);
3463
+ }
3464
+ const previous = recentSendByTarget.get(key);
3465
+ if (previous && now - previous <= RECENT_SEND_WINDOW_MS) return true;
3466
+ recentSendByTarget.set(key, now);
3467
+ return false;
3327
3468
  }
3328
3469
  async function handleChatHistory(h, args) {
3329
- const { agentType, offset, limit, instanceId } = args;
3470
+ const { agentType, offset, limit } = args;
3471
+ const instanceId = args?.targetSessionId;
3330
3472
  try {
3331
3473
  const provider = h.getProvider(agentType);
3332
- const agentStr = provider?.type || agentType || h.currentIdeType || "";
3474
+ const agentStr = provider?.type || agentType || getCurrentProviderType(h);
3333
3475
  const result = readChatHistory(agentStr, offset || 0, limit || 30, instanceId);
3334
3476
  return { success: true, ...result, agent: agentStr };
3335
3477
  } catch (e) {
@@ -3373,7 +3515,7 @@ async function handleReadChat(h, args) {
3373
3515
  provider.type || "unknown_extension",
3374
3516
  parsed.messages || [],
3375
3517
  parsed.title,
3376
- args?.instanceId
3518
+ args?.targetSessionId
3377
3519
  );
3378
3520
  return { success: true, ...parsed };
3379
3521
  }
@@ -3383,15 +3525,18 @@ async function handleReadChat(h, args) {
3383
3525
  }
3384
3526
  if (h.agentStream) {
3385
3527
  const cdp2 = h.getCdp();
3386
- if (cdp2 && h.currentIdeType) {
3387
- const streams = await h.agentStream.collectAgentStreams(cdp2, h.currentIdeType);
3388
- const stream = streams.find((s15) => s15.agentType === provider.type);
3528
+ const parentSessionId = h.currentSession?.parentSessionId;
3529
+ if (cdp2 && parentSessionId) {
3530
+ const stream = await h.agentStream.collectActiveSession(cdp2, parentSessionId);
3531
+ if (stream?.agentType !== provider.type) {
3532
+ return { success: true, messages: [], status: "idle" };
3533
+ }
3389
3534
  if (stream) {
3390
3535
  h.historyWriter.appendNewMessages(
3391
3536
  stream.agentType,
3392
3537
  stream.messages || [],
3393
3538
  void 0,
3394
- args?.instanceId
3539
+ args?.targetSessionId
3395
3540
  );
3396
3541
  return { success: true, messages: stream.messages || [], status: stream.status, agentType: stream.agentType };
3397
3542
  }
@@ -3418,10 +3563,10 @@ async function handleReadChat(h, args) {
3418
3563
  if (parsed && typeof parsed === "object") {
3419
3564
  _log(`Webview OK: ${parsed.messages?.length || 0} msgs`);
3420
3565
  h.historyWriter.appendNewMessages(
3421
- provider?.type || h.currentIdeType || "unknown_webview",
3566
+ provider?.type || getCurrentProviderType(h, "unknown_webview"),
3422
3567
  parsed.messages || [],
3423
3568
  parsed.title,
3424
- args?.instanceId
3569
+ args?.targetSessionId
3425
3570
  );
3426
3571
  return { success: true, ...parsed };
3427
3572
  }
@@ -3445,10 +3590,10 @@ async function handleReadChat(h, args) {
3445
3590
  if (parsed && typeof parsed === "object" && parsed.messages?.length > 0) {
3446
3591
  _log(`OK: ${parsed.messages?.length} msgs`);
3447
3592
  h.historyWriter.appendNewMessages(
3448
- provider?.type || h.currentIdeType || "unknown_ide",
3593
+ provider?.type || getCurrentProviderType(h, "unknown_ide"),
3449
3594
  parsed.messages || [],
3450
3595
  parsed.title,
3451
- args?.instanceId
3596
+ args?.targetSessionId
3452
3597
  );
3453
3598
  return { success: true, ...parsed };
3454
3599
  }
@@ -3463,16 +3608,21 @@ async function handleSendChat(h, args) {
3463
3608
  if (!text) return { success: false, error: "text required" };
3464
3609
  const _log = (msg) => LOG.debug("Command", `[send_chat] ${msg}`);
3465
3610
  const provider = h.getProvider(args?.agentType);
3611
+ const dedupeKey = buildRecentSendKey(h, args, provider, text);
3466
3612
  const _logSendSuccess = (method, targetAgent) => {
3467
3613
  h.historyWriter.appendNewMessages(
3468
- targetAgent || provider?.type || h.currentIdeType || "unknown_agent",
3614
+ targetAgent || provider?.type || getCurrentProviderType(h, "unknown_agent"),
3469
3615
  [{ role: "user", content: text, receivedAt: Date.now() }],
3470
3616
  void 0,
3471
3617
  // title
3472
- args?.instanceId
3618
+ args?.targetSessionId
3473
3619
  );
3474
3620
  return { success: true, sent: true, method, targetAgent };
3475
3621
  };
3622
+ if (isRecentDuplicateSend(dedupeKey)) {
3623
+ _log(`Suppressed duplicate send for ${dedupeKey}`);
3624
+ return { success: true, sent: false, deduplicated: true };
3625
+ }
3476
3626
  if (provider?.category === "cli" || provider?.category === "acp") {
3477
3627
  const adapter = getTargetedCliAdapter(h, args, provider.type);
3478
3628
  if (adapter) {
@@ -3508,8 +3658,9 @@ async function handleSendChat(h, args) {
3508
3658
  } catch (e) {
3509
3659
  _log(`Extension script error: ${e.message}`);
3510
3660
  }
3511
- if (h.agentStream && h.getCdp() && h.currentIdeType) {
3512
- const ok = await h.agentStream.sendToAgent(h.getCdp(), h.currentIdeType, provider.type, text, h.currentIdeType);
3661
+ const extensionSessionId = h.currentSession?.sessionId;
3662
+ if (h.agentStream && h.getCdp() && extensionSessionId) {
3663
+ const ok = await h.agentStream.sendToSession(h.getCdp(), extensionSessionId, text);
3513
3664
  if (ok) {
3514
3665
  _log(`AgentStreamManager sent OK`);
3515
3666
  return _logSendSuccess("agent-stream");
@@ -3519,45 +3670,11 @@ async function handleSendChat(h, args) {
3519
3670
  }
3520
3671
  const targetCdp = h.getCdp();
3521
3672
  if (!targetCdp?.isConnected) {
3522
- _log(`No CDP for ${h.currentIdeType}`);
3523
- return { success: false, error: `CDP for ${h.currentIdeType || "unknown"} not connected` };
3524
- }
3525
- _log(`Targeting IDE: ${h.currentIdeType}`);
3526
- if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
3527
- try {
3528
- const webviewScript = provider.scripts.webviewSendMessage(text);
3529
- if (webviewScript && targetCdp.evaluateInWebviewFrame) {
3530
- const matchText = provider.webviewMatchText;
3531
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
3532
- const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
3533
- let wvParsed = wvResult;
3534
- if (typeof wvResult === "string") {
3535
- try {
3536
- wvParsed = JSON.parse(wvResult);
3537
- } catch {
3538
- }
3539
- }
3540
- if (wvParsed?.sent) {
3541
- _log(`webviewSendMessage (priority) OK`);
3542
- return _logSendSuccess("webview-script-priority");
3543
- }
3544
- _log(`webviewSendMessage (priority) did not confirm sent, falling through`);
3545
- }
3546
- } catch (e) {
3547
- _log(`webviewSendMessage (priority) failed: ${e.message}, falling through`);
3548
- }
3549
- }
3550
- if (provider?.inputMethod === "cdp-type-and-send" && provider.inputSelector) {
3551
- try {
3552
- const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
3553
- if (sent) {
3554
- _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
3555
- return _logSendSuccess("typeAndSend-provider");
3556
- }
3557
- } catch (e) {
3558
- _log(`typeAndSend(provider) failed: ${e.message}`);
3559
- }
3673
+ const managerKey = getCurrentManagerKey(h);
3674
+ _log(`No CDP for ${managerKey}`);
3675
+ return { success: false, error: `CDP for ${managerKey || "unknown"} not connected` };
3560
3676
  }
3677
+ _log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
3561
3678
  const sendScript = h.getProviderScript("sendMessage", { MESSAGE: text });
3562
3679
  if (sendScript) {
3563
3680
  try {
@@ -3584,7 +3701,30 @@ async function handleSendChat(h, args) {
3584
3701
  _log(`typeAndSend(script.selector) failed: ${e.message}`);
3585
3702
  }
3586
3703
  }
3587
- if (parsed?.needsTypeAndSend && provider?.scripts?.webviewSendMessage) {
3704
+ if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
3705
+ try {
3706
+ const { x, y } = parsed.clickCoords;
3707
+ const sent = await targetCdp.typeAndSendAt(x, y, text);
3708
+ if (sent) {
3709
+ _log(`typeAndSendAt(${x},${y}) success`);
3710
+ return _logSendSuccess("typeAndSendAt-script");
3711
+ }
3712
+ } catch (e) {
3713
+ _log(`typeAndSendAt failed: ${e.message}`);
3714
+ }
3715
+ }
3716
+ if (parsed?.needsTypeAndSend && provider?.inputMethod === "cdp-type-and-send" && provider.inputSelector) {
3717
+ try {
3718
+ const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
3719
+ if (sent) {
3720
+ _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
3721
+ return _logSendSuccess("typeAndSend-provider");
3722
+ }
3723
+ } catch (e) {
3724
+ _log(`typeAndSend(provider) failed: ${e.message}`);
3725
+ }
3726
+ }
3727
+ if (parsed?.needsTypeAndSend && provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
3588
3728
  try {
3589
3729
  const webviewScript = provider.scripts.webviewSendMessage(text);
3590
3730
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
@@ -3607,20 +3747,44 @@ async function handleSendChat(h, args) {
3607
3747
  _log(`webviewSendMessage failed: ${e.message}`);
3608
3748
  }
3609
3749
  }
3610
- if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
3611
- try {
3612
- const { x, y } = parsed.clickCoords;
3613
- const sent = await targetCdp.typeAndSendAt(x, y, text);
3614
- if (sent) {
3615
- _log(`typeAndSendAt(${x},${y}) success`);
3616
- return _logSendSuccess("typeAndSendAt-script");
3750
+ return { success: false, error: parsed?.error || "Provider sendMessage did not confirm send" };
3751
+ } catch (e) {
3752
+ _log(`sendMessage script failed: ${e.message}`);
3753
+ return { success: false, error: `Provider sendMessage failed: ${e.message}` };
3754
+ }
3755
+ }
3756
+ if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
3757
+ try {
3758
+ const webviewScript = provider.scripts.webviewSendMessage(text);
3759
+ if (webviewScript && targetCdp.evaluateInWebviewFrame) {
3760
+ const matchText = provider.webviewMatchText;
3761
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
3762
+ const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
3763
+ let wvParsed = wvResult;
3764
+ if (typeof wvResult === "string") {
3765
+ try {
3766
+ wvParsed = JSON.parse(wvResult);
3767
+ } catch {
3617
3768
  }
3618
- } catch (e) {
3619
- _log(`typeAndSendAt failed: ${e.message}`);
3769
+ }
3770
+ if (wvParsed?.sent) {
3771
+ _log(`webviewSendMessage OK`);
3772
+ return _logSendSuccess("webview-script");
3620
3773
  }
3621
3774
  }
3622
3775
  } catch (e) {
3623
- _log(`sendMessage script failed: ${e.message}`);
3776
+ _log(`webviewSendMessage failed: ${e.message}`);
3777
+ }
3778
+ }
3779
+ if (provider?.inputMethod === "cdp-type-and-send" && provider.inputSelector) {
3780
+ try {
3781
+ const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
3782
+ if (sent) {
3783
+ _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
3784
+ return _logSendSuccess("typeAndSend-provider");
3785
+ }
3786
+ } catch (e) {
3787
+ _log(`typeAndSend(provider) failed: ${e.message}`);
3624
3788
  }
3625
3789
  }
3626
3790
  _log("All methods failed");
@@ -3628,9 +3792,9 @@ async function handleSendChat(h, args) {
3628
3792
  }
3629
3793
  async function handleListChats(h, args) {
3630
3794
  const provider = h.getProvider(args?.agentType);
3631
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
3795
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
3632
3796
  try {
3633
- const chats = await h.agentStream.listAgentChats(h.getCdp(), h.currentIdeType, provider.type);
3797
+ const chats = await h.agentStream.listSessionChats(h.getCdp(), h.currentSession.sessionId);
3634
3798
  LOG.info("Command", `[list_chats] Extension: ${chats.length} chats`);
3635
3799
  return { success: true, chats };
3636
3800
  } catch (e) {
@@ -3689,8 +3853,8 @@ async function handleNewChat(h, args) {
3689
3853
  }
3690
3854
  return { success: false, error: "new_chat not supported by this CLI provider" };
3691
3855
  }
3692
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
3693
- const ok = await h.agentStream.newAgentSession(h.getCdp(), h.currentIdeType, provider.type, h.currentIdeType);
3856
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
3857
+ const ok = await h.agentStream.newSession(h.getCdp(), h.currentSession.sessionId);
3694
3858
  return { success: ok };
3695
3859
  }
3696
3860
  try {
@@ -3714,15 +3878,15 @@ async function handleNewChat(h, args) {
3714
3878
  }
3715
3879
  async function handleSwitchChat(h, args) {
3716
3880
  const provider = h.getProvider(args?.agentType);
3717
- const ideType = h.currentIdeType;
3881
+ const managerKey = getCurrentManagerKey(h);
3718
3882
  const sessionId = args?.sessionId || args?.id || args?.chatId;
3719
3883
  if (!sessionId) return { success: false, error: "sessionId required" };
3720
- LOG.info("Command", `[switch_chat] sessionId=${sessionId}, ideType=${ideType}`);
3721
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
3722
- const ok = await h.agentStream.switchAgentSession(h.getCdp(), h.currentIdeType, provider.type, sessionId);
3884
+ LOG.info("Command", `[switch_chat] sessionId=${sessionId}, manager=${managerKey}`);
3885
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
3886
+ const ok = await h.agentStream.switchConversation(h.getCdp(), h.currentSession.sessionId, sessionId);
3723
3887
  return { success: ok, result: ok ? "switched" : "failed" };
3724
3888
  }
3725
- const cdp = h.getCdp(ideType);
3889
+ const cdp = h.getCdp(managerKey);
3726
3890
  if (!cdp?.isConnected) return { success: false, error: "CDP not connected" };
3727
3891
  try {
3728
3892
  const webviewScript = h.getProviderScript("webviewSwitchSession", { SESSION_ID: JSON.stringify(sessionId) });
@@ -3864,7 +4028,7 @@ async function handleSetMode(h, args) {
3864
4028
  async function handleChangeModel(h, args) {
3865
4029
  const provider = h.getProvider(args?.agentType);
3866
4030
  const model = args?.model;
3867
- LOG.info("Command", `[change_model] model=${model} provider=${provider?.type} category=${provider?.category} ideType=${h.currentIdeType} providerType=${h.currentProviderType}`);
4031
+ LOG.info("Command", `[change_model] model=${model} provider=${provider?.type} category=${provider?.category} manager=${getCurrentManagerKey(h)} providerType=${getCurrentProviderType(h)}`);
3868
4032
  if (provider?.category === "acp") {
3869
4033
  const adapter = getTargetedCliAdapter(h, args, provider.type);
3870
4034
  LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
@@ -3985,14 +4149,8 @@ async function handleResolveAction(h, args) {
3985
4149
  LOG.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
3986
4150
  return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
3987
4151
  }
3988
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
3989
- const ok = await h.agentStream.resolveAgentAction(
3990
- h.getCdp(),
3991
- h.currentIdeType,
3992
- provider.type,
3993
- action,
3994
- h.currentIdeType
3995
- );
4152
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
4153
+ const ok = await h.agentStream.resolveSessionAction(h.getCdp(), h.currentSession.sessionId, action);
3996
4154
  return { success: ok };
3997
4155
  }
3998
4156
  if (provider?.scripts?.webviewResolveAction || provider?.scripts?.webview_resolve_action) {
@@ -4070,11 +4228,14 @@ async function handleResolveAction(h, args) {
4070
4228
  }
4071
4229
  return { success: false, error: "resolveAction script not available for this provider" };
4072
4230
  }
4231
+ var RECENT_SEND_WINDOW_MS, recentSendByTarget;
4073
4232
  var init_chat_commands = __esm({
4074
4233
  "../../oss/packages/daemon-core/src/commands/chat-commands.ts"() {
4075
4234
  "use strict";
4076
4235
  init_chat_history();
4077
4236
  init_logger();
4237
+ RECENT_SEND_WINDOW_MS = 1200;
4238
+ recentSendByTarget = /* @__PURE__ */ new Map();
4078
4239
  }
4079
4240
  });
4080
4241
 
@@ -4363,157 +4524,37 @@ var init_cdp_commands = __esm({
4363
4524
  });
4364
4525
 
4365
4526
  // ../../oss/packages/daemon-core/src/commands/stream-commands.ts
4366
- async function handleAgentStreamSwitch(h, args) {
4367
- if (!h.agentStream || !h.getCdp() || !h.currentIdeType) return { success: false, error: "AgentStream or CDP not available" };
4368
- const agentType = args?.agentType || args?.agent || null;
4369
- await h.agentStream.switchActiveAgent(h.getCdp(), h.currentIdeType, agentType);
4370
- return { success: true, activeAgent: agentType };
4371
- }
4372
- async function handleAgentStreamRead(h, args) {
4373
- if (!h.agentStream || !h.getCdp() || !h.currentIdeType) return { success: false, error: "AgentStream or CDP not available" };
4374
- const streams = await h.agentStream.collectAgentStreams(h.getCdp(), h.currentIdeType);
4375
- return { success: true, streams };
4376
- }
4377
- async function handleAgentStreamSend(h, args) {
4378
- const agentType = args?.agentType || args?.agent;
4379
- const text = args?.text || args?.message;
4380
- if (!text) return { success: false, error: "text required" };
4381
- if (agentType && h.ctx.adapters) {
4382
- for (const [key, adapter] of h.ctx.adapters.entries()) {
4383
- if (adapter.cliType === agentType || key.includes(agentType)) {
4384
- LOG.info("Command", `[agent_stream_send] Routing to CLI adapter: ${adapter.cliType}`);
4385
- try {
4386
- await adapter.sendMessage(text);
4387
- return { success: true, sent: true, targetAgent: adapter.cliType };
4388
- } catch (e) {
4389
- LOG.info("Command", `[agent_stream_send] CLI adapter failed: ${e.message}`);
4390
- return { success: false, error: `CLI send failed: ${e.message}` };
4391
- }
4392
- }
4393
- }
4394
- }
4395
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4396
- const resolvedAgent = agentType || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4397
- if (!resolvedAgent) return { success: false, error: "agentType required" };
4398
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4399
- const ok = await h.agentStream.sendToAgent(h.getCdp(), h.currentIdeType, resolvedAgent, text, h.currentIdeType);
4400
- return { success: ok };
4401
- }
4402
- async function handleAgentStreamResolve(h, args) {
4403
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4404
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4405
- const action = args?.action || "approve";
4406
- if (!agentType) return { success: false, error: "agentType required" };
4407
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4408
- const ok = await h.agentStream.resolveAgentAction(h.getCdp(), h.currentIdeType, agentType, action, h.currentIdeType);
4409
- return { success: ok };
4410
- }
4411
- async function handleAgentStreamNew(h, args) {
4412
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4413
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4414
- if (!agentType) return { success: false, error: "agentType required" };
4415
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4416
- const ok = await h.agentStream.newAgentSession(h.getCdp(), h.currentIdeType, agentType, h.currentIdeType);
4417
- return { success: ok };
4418
- }
4419
- async function handleAgentStreamListChats(h, args) {
4420
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4421
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4422
- if (!agentType) return { success: false, error: "agentType required" };
4423
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4424
- const chats = await h.agentStream.listAgentChats(h.getCdp(), h.currentIdeType, agentType);
4425
- return { success: true, chats };
4426
- }
4427
- async function handleAgentStreamSwitchSession(h, args) {
4428
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4429
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4430
- const sessionId = args?.sessionId || args?.id;
4431
- if (!agentType || !sessionId) return { success: false, error: "agentType and sessionId required" };
4432
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4433
- const ok = await h.agentStream.switchAgentSession(h.getCdp(), h.currentIdeType, agentType, sessionId);
4434
- return { success: ok };
4435
- }
4436
- async function handleAgentStreamFocus(h, args) {
4527
+ async function handleFocusSession(h, args) {
4437
4528
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4438
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4439
- if (!agentType) return { success: false, error: "agentType required" };
4440
- await h.agentStream.ensureAgentPanelOpen(agentType, h.currentIdeType);
4441
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4442
- const ok = await h.agentStream.focusAgentEditor(h.getCdp(), h.currentIdeType, agentType);
4529
+ const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
4530
+ if (!sessionId) return { success: false, error: "targetSessionId required" };
4531
+ const ok = await h.agentStream.focusSession(h.getCdp(), sessionId);
4443
4532
  return { success: ok };
4444
4533
  }
4445
4534
  function handlePtyInput(h, args) {
4446
- const { cliType, data } = args || {};
4535
+ const { cliType, data, targetSessionId } = args || {};
4447
4536
  if (!data) return { success: false, error: "data required" };
4448
- if (h.ctx.adapters) {
4449
- const targetCli = cliType || "";
4450
- if (!targetCli && h.ctx.adapters.size > 0) {
4451
- const first = h.ctx.adapters.values().next().value;
4452
- if (first && typeof first.writeRaw === "function") {
4453
- first.writeRaw(data);
4454
- return { success: true };
4455
- }
4456
- }
4457
- const directAdapter = h.ctx.adapters.get(targetCli);
4458
- if (directAdapter && typeof directAdapter.writeRaw === "function") {
4459
- directAdapter.writeRaw(data);
4460
- return { success: true };
4461
- }
4462
- for (const [, adapter] of h.ctx.adapters) {
4463
- if (adapter.cliType === targetCli && typeof adapter.writeRaw === "function") {
4464
- adapter.writeRaw(data);
4465
- return { success: true };
4466
- }
4467
- }
4468
- for (const [key, adapter] of h.ctx.adapters) {
4469
- if ((key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.writeRaw === "function") {
4470
- adapter.writeRaw(data);
4471
- return { success: true };
4472
- }
4473
- }
4537
+ const adapter = h.getCliAdapter(targetSessionId || cliType);
4538
+ if (!adapter || typeof adapter.writeRaw !== "function") {
4539
+ return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
4474
4540
  }
4475
- return { success: false, error: `CLI adapter not found: ${cliType}` };
4541
+ adapter.writeRaw(data);
4542
+ return { success: true };
4476
4543
  }
4477
4544
  function handlePtyResize(h, args) {
4478
- const { cliType, cols, rows, force } = args || {};
4545
+ const { cliType, cols, rows, force, targetSessionId } = args || {};
4479
4546
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
4480
- if (h.ctx.adapters) {
4481
- const targetCli = cliType || "";
4482
- if (!targetCli && h.ctx.adapters.size > 0) {
4483
- const first = h.ctx.adapters.values().next().value;
4484
- if (first && typeof first.resize === "function") {
4485
- if (force) {
4486
- first.resize(cols - 1, rows);
4487
- setTimeout(() => first.resize(cols, rows), 50);
4488
- } else {
4489
- first.resize(cols, rows);
4490
- }
4491
- return { success: true };
4492
- }
4493
- }
4494
- const directAdapter = h.ctx.adapters.get(targetCli);
4495
- if (directAdapter && typeof directAdapter.resize === "function") {
4496
- if (force) {
4497
- directAdapter.resize(cols - 1, rows);
4498
- setTimeout(() => directAdapter.resize(cols, rows), 50);
4499
- } else {
4500
- directAdapter.resize(cols, rows);
4501
- }
4502
- return { success: true };
4503
- }
4504
- for (const [key, adapter] of h.ctx.adapters) {
4505
- if ((adapter.cliType === targetCli || key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.resize === "function") {
4506
- if (force) {
4507
- adapter.resize(cols - 1, rows);
4508
- setTimeout(() => adapter.resize(cols, rows), 50);
4509
- } else {
4510
- adapter.resize(cols, rows);
4511
- }
4512
- return { success: true };
4513
- }
4514
- }
4547
+ const adapter = h.getCliAdapter(targetSessionId || cliType);
4548
+ if (!adapter || typeof adapter.resize !== "function") {
4549
+ return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
4550
+ }
4551
+ if (force) {
4552
+ adapter.resize(cols - 1, rows);
4553
+ setTimeout(() => adapter.resize(cols, rows), 50);
4554
+ } else {
4555
+ adapter.resize(cols, rows);
4515
4556
  }
4516
- return { success: false, error: `CLI adapter not found: ${cliType}` };
4557
+ return { success: true };
4517
4558
  }
4518
4559
  function handleGetProviderSettings(h, args) {
4519
4560
  const loader = h.ctx.providerLoader;
@@ -4549,7 +4590,7 @@ function handleSetProviderSetting(h, args) {
4549
4590
  }
4550
4591
  async function handleExtensionScript(h, args, scriptName) {
4551
4592
  const { agentType, ideType } = args || {};
4552
- LOG.info("Command", `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} _currentIdeType=${h.currentIdeType}`);
4593
+ LOG.info("Command", `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} session=${h.currentSession?.sessionId || ""}`);
4553
4594
  if (!agentType) return { success: false, error: "agentType is required" };
4554
4595
  const loader = h.ctx.providerLoader;
4555
4596
  if (!loader) return { success: false, error: "ProviderLoader not initialized" };
@@ -4570,21 +4611,22 @@ async function handleExtensionScript(h, args, scriptName) {
4570
4611
  }
4571
4612
  const scriptCode = scriptFn(normalizedArgs);
4572
4613
  if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
4573
- const cdpKey = provider.category === "ide" ? h.currentIdeType || agentType : h.currentIdeType || ideType;
4614
+ const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || agentType : h.currentSession?.cdpManagerKey || h.currentManagerKey || ideType;
4574
4615
  LOG.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
4575
4616
  const cdp = h.getCdp(cdpKey);
4576
4617
  if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
4577
4618
  try {
4578
4619
  let result;
4579
4620
  if (provider.category === "extension") {
4580
- const sessions = cdp.getAgentSessions();
4581
- let targetSessionId = null;
4582
- for (const [sessionId, target] of sessions) {
4583
- if (target.agentType === agentType) {
4584
- targetSessionId = sessionId;
4585
- break;
4586
- }
4587
- }
4621
+ const runtimeSessionId = h.currentSession?.sessionId || args?.targetSessionId;
4622
+ if (!runtimeSessionId) return { success: false, error: `No target session found for ${agentType}` };
4623
+ const parentSessionId = h.currentSession?.parentSessionId;
4624
+ if (parentSessionId) {
4625
+ await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
4626
+ await h.agentStream?.syncActiveSession(cdp, parentSessionId);
4627
+ }
4628
+ const managed = runtimeSessionId ? h.agentStream?.getManagedSession(runtimeSessionId) : null;
4629
+ const targetSessionId = managed?.cdpSessionId || null;
4588
4630
  const IDE_LEVEL_SCRIPTS = ["listModes", "setMode", "listModels", "setModel"];
4589
4631
  if (IDE_LEVEL_SCRIPTS.includes(scriptName)) {
4590
4632
  if (targetSessionId) {
@@ -4655,7 +4697,7 @@ function handleGetIdeExtensions(h, args) {
4655
4697
  enabled: config2.ideSettings?.[ide]?.extensions?.[p.type]?.enabled === true
4656
4698
  }));
4657
4699
  }
4658
- return { success: true, ides: result };
4700
+ return { success: true, ideExtensions: result };
4659
4701
  }
4660
4702
  function handleSetIdeExtension(h, args) {
4661
4703
  const { ideType, extensionType, enabled } = args || {};
@@ -4794,10 +4836,8 @@ var init_handler = __esm({
4794
4836
  _agentStream = null;
4795
4837
  domHandlers;
4796
4838
  _historyWriter;
4797
- /** Current IDE type extracted from command args (per-request) */
4798
- _currentIdeType;
4799
- /** Current provider type — agentType priority, ideType use */
4800
- _currentProviderType;
4839
+ /** Current request route context */
4840
+ _currentRoute = {};
4801
4841
  constructor(ctx) {
4802
4842
  this._ctx = ctx;
4803
4843
  this.domHandlers = new CdpDomHandlers((ideType) => this.getCdp(ideType));
@@ -4813,20 +4853,25 @@ var init_handler = __esm({
4813
4853
  get historyWriter() {
4814
4854
  return this._historyWriter;
4815
4855
  }
4856
+ get currentManagerKey() {
4857
+ return this._currentRoute.managerKey;
4858
+ }
4816
4859
  get currentIdeType() {
4817
- return this._currentIdeType;
4860
+ return this._currentRoute.managerKey;
4818
4861
  }
4819
4862
  get currentProviderType() {
4820
- return this._currentProviderType;
4863
+ return this._currentRoute.providerType;
4821
4864
  }
4822
- /** Get CDP manager for a specific ideType or managerKey.
4823
- * Supports exact match, multi-window prefix match, and instanceIdMap UUID lookup.
4824
- * Returns null if no match — never falls back to another IDE. */
4865
+ get currentSession() {
4866
+ return this._currentRoute.session;
4867
+ }
4868
+ /** Get CDP manager for a specific session or manager key. */
4825
4869
  getCdp(ideType) {
4826
- const key = ideType || this._currentIdeType;
4827
- if (!key) return null;
4828
- const resolved = this._ctx.instanceIdMap?.get(key) || key;
4829
- const m = findCdpManager(this._ctx.cdpManagers, resolved);
4870
+ const requested = ideType || this._currentRoute.session?.sessionId || this._currentRoute.managerKey;
4871
+ if (!requested) return null;
4872
+ const session = this._ctx.sessionRegistry?.get(requested);
4873
+ const managerKey = session?.cdpManagerKey || requested;
4874
+ const m = findCdpManager(this._ctx.cdpManagers, managerKey);
4830
4875
  if (m?.isConnected) return m;
4831
4876
  return null;
4832
4877
  }
@@ -4834,7 +4879,7 @@ var init_handler = __esm({
4834
4879
  * Get provider module — _currentProviderType (agentType priority) use.
4835
4880
  */
4836
4881
  getProvider(overrideType) {
4837
- const key = overrideType || this._currentProviderType || this._currentIdeType;
4882
+ const key = overrideType || this._currentRoute.providerType || this._currentRoute.session?.providerType || this._currentRoute.managerKey;
4838
4883
  if (!key || !this._ctx.providerLoader) return void 0;
4839
4884
  const result = this._ctx.providerLoader.resolve(key);
4840
4885
  if (result) return result;
@@ -4867,14 +4912,22 @@ var init_handler = __esm({
4867
4912
  const cdp = this.getCdp();
4868
4913
  if (!cdp?.isConnected) return null;
4869
4914
  if (provider?.category === "extension") {
4870
- let sessionId = this.getExtensionSessionId(provider, this._currentIdeType);
4871
- if (!sessionId && this._agentStream && this._currentIdeType) {
4872
- await this._agentStream.switchActiveAgent(cdp, this._currentIdeType, provider.type);
4873
- await this._agentStream.syncAgentSessions(cdp, this._currentIdeType);
4874
- sessionId = this.getExtensionSessionId(provider, this._currentIdeType);
4915
+ let sessionId = this._currentRoute.session?.sessionId || null;
4916
+ if (!sessionId && this._currentRoute.session?.parentSessionId) {
4917
+ sessionId = this._agentStream?.resolveSessionForAgent(this._currentRoute.session.parentSessionId, provider.type) || null;
4918
+ }
4919
+ if (sessionId && this._agentStream) {
4920
+ const target = this._ctx.sessionRegistry?.get(sessionId);
4921
+ if (target?.parentSessionId) {
4922
+ await this._agentStream.setActiveSession(cdp, target.parentSessionId, sessionId);
4923
+ await this._agentStream.syncActiveSession(cdp, target.parentSessionId);
4924
+ }
4875
4925
  }
4876
4926
  if (!sessionId) return null;
4877
- const result2 = await cdp.evaluateInSessionFrame(sessionId, script, timeout);
4927
+ const managed = this._agentStream?.getManagedSession(sessionId);
4928
+ const cdpSessionId = managed?.cdpSessionId;
4929
+ if (!cdpSessionId) return null;
4930
+ const result2 = await cdp.evaluateInSessionFrame(cdpSessionId, script, timeout);
4878
4931
  return { result: result2, category: "extension" };
4879
4932
  }
4880
4933
  const result = await cdp.evaluate(script, timeout);
@@ -4882,57 +4935,37 @@ var init_handler = __esm({
4882
4935
  }
4883
4936
  /** CLI adapter search */
4884
4937
  getCliAdapter(type) {
4885
- const target = type || this._currentIdeType;
4938
+ const target = type || this._currentRoute.session?.sessionId || this._currentRoute.providerType || this._currentRoute.managerKey;
4886
4939
  if (!target || !this._ctx.adapters) return null;
4887
- let normalizedTarget = target;
4888
- const colonIdx = normalizedTarget.lastIndexOf(":");
4889
- if (colonIdx >= 0) normalizedTarget = normalizedTarget.substring(colonIdx + 1);
4890
- const direct = this._ctx.adapters.get(normalizedTarget);
4891
- if (direct) return direct;
4892
- for (const [key, adapter] of this._ctx.adapters.entries()) {
4893
- if (adapter.cliType === target || adapter.cliType === normalizedTarget || key === normalizedTarget || key.startsWith(target) || key.startsWith(normalizedTarget)) {
4894
- return adapter;
4895
- }
4940
+ const session = this._ctx.sessionRegistry?.get(target);
4941
+ if (session?.adapterKey) {
4942
+ return this._ctx.adapters.get(session.adapterKey) || null;
4896
4943
  }
4897
- return null;
4944
+ return this._ctx.adapters.get(target) || null;
4898
4945
  }
4899
4946
  // ─── Private helpers ──────────────────────────────
4900
- getExtensionSessionId(provider, scopeKey) {
4901
- if (provider.category !== "extension" || !this._agentStream || !scopeKey) return null;
4902
- const managed = this._agentStream.getManagedAgent(provider.type, scopeKey);
4903
- return managed?.sessionId || null;
4904
- }
4905
- resolveManagerKeyFromInstanceId(instanceId) {
4906
- const mapped = this._ctx.instanceIdMap?.get(instanceId);
4907
- if (mapped) return mapped;
4908
- const entries = this._ctx.instanceManager?.instances?.entries?.();
4909
- if (!entries) return void 0;
4910
- for (const [instanceKey, instance] of entries) {
4911
- if (typeof instanceKey !== "string" || !instanceKey.startsWith("ide:")) continue;
4912
- if (typeof instance?.getInstanceId === "function" && instance.getInstanceId() === instanceId) {
4913
- const managerKey = instanceKey.slice(4);
4914
- this._ctx.instanceIdMap?.set(instanceId, managerKey);
4915
- return managerKey;
4916
- }
4917
- if (typeof instance?.getExtensionInstances === "function") {
4918
- for (const ext of instance.getExtensionInstances() || []) {
4919
- if (typeof ext?.getInstanceId === "function" && ext.getInstanceId() === instanceId) {
4920
- const managerKey = instanceKey.slice(4);
4921
- this._ctx.instanceIdMap?.set(instanceId, managerKey);
4922
- return managerKey;
4923
- }
4924
- }
4925
- }
4926
- }
4927
- return void 0;
4928
- }
4929
- /** Extract ideType from _targetInstance or explicit ideType */
4947
+ inferProviderType(key) {
4948
+ if (!key) return void 0;
4949
+ const session = this._ctx.sessionRegistry?.get(key);
4950
+ if (session?.providerType) return session.providerType;
4951
+ return key.split("_")[0];
4952
+ }
4953
+ resolveRoute(args) {
4954
+ const session = this._ctx.sessionRegistry?.get(args?.targetSessionId);
4955
+ const managerKey = this.extractIdeType(args);
4956
+ const providerType = args?.agentType || args?.providerType || session?.providerType || this.inferProviderType(managerKey);
4957
+ return { session, managerKey, providerType };
4958
+ }
4959
+ /** Extract CDP scope key from target session or explicit ideType */
4930
4960
  extractIdeType(args) {
4961
+ if (args?.targetSessionId) {
4962
+ const target = this._ctx.sessionRegistry?.get(args.targetSessionId);
4963
+ if (target?.cdpManagerKey) return target.cdpManagerKey;
4964
+ if (this._ctx.cdpManagers.has(args.targetSessionId)) return args.targetSessionId;
4965
+ }
4931
4966
  if (args?.ideType) {
4932
- const mappedKey = this.resolveManagerKeyFromInstanceId(args.ideType);
4933
- if (mappedKey) {
4934
- return mappedKey;
4935
- }
4967
+ const target = this._ctx.sessionRegistry?.get(args.ideType);
4968
+ if (target?.cdpManagerKey) return target.cdpManagerKey;
4936
4969
  if (this._ctx.cdpManagers.has(args.ideType)) {
4937
4970
  return args.ideType;
4938
4971
  }
@@ -4943,34 +4976,6 @@ var init_handler = __esm({
4943
4976
  }
4944
4977
  }
4945
4978
  }
4946
- if (args?._targetInstance) {
4947
- let raw = args._targetInstance;
4948
- const ideMatch = raw.match(/:ide:(.+)$/);
4949
- const cliMatch = raw.match(/:cli:(.+)$/);
4950
- const acpMatch = raw.match(/:acp:(.+)$/);
4951
- if (ideMatch) raw = ideMatch[1];
4952
- else if (cliMatch) raw = cliMatch[1];
4953
- else if (acpMatch) raw = acpMatch[1];
4954
- const mappedKey = this.resolveManagerKeyFromInstanceId(raw);
4955
- if (mappedKey) {
4956
- return mappedKey;
4957
- }
4958
- if (this._ctx.cdpManagers.has(raw)) {
4959
- return raw;
4960
- }
4961
- const found = findCdpManager(this._ctx.cdpManagers, raw);
4962
- if (found) {
4963
- for (const [k, m] of this._ctx.cdpManagers.entries()) {
4964
- if (m === found) return k;
4965
- }
4966
- }
4967
- const lastUnderscore = raw.lastIndexOf("_");
4968
- if (lastUnderscore > 0) {
4969
- const stripped = raw.substring(0, lastUnderscore);
4970
- if (this._ctx.cdpManagers.has(stripped)) return stripped;
4971
- }
4972
- return raw;
4973
- }
4974
4979
  return void 0;
4975
4980
  }
4976
4981
  setAgentStreamManager(manager) {
@@ -4978,12 +4983,11 @@ var init_handler = __esm({
4978
4983
  }
4979
4984
  // ─── Command Dispatcher ──────────────────────────
4980
4985
  async handle(cmd, args) {
4981
- this._currentIdeType = this.extractIdeType(args);
4982
- this._currentProviderType = args?.agentType || args?.providerType || this._currentIdeType;
4983
- if (!this._currentIdeType && !this._currentProviderType) {
4986
+ this._currentRoute = this.resolveRoute(args);
4987
+ if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
4984
4988
  const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
4985
4989
  if (cdpCommands.includes(cmd)) {
4986
- return { success: false, error: "No ideType specified \u2014 cannot route command" };
4990
+ return { success: false, error: "No targetSessionId specified \u2014 cannot route command" };
4987
4991
  }
4988
4992
  }
4989
4993
  try {
@@ -5074,22 +5078,8 @@ var init_handler = __esm({
5074
5078
  case "refresh_scripts":
5075
5079
  return this.handleRefreshScripts(args);
5076
5080
  // ─── Stream commands (stream-commands.ts) ───────────
5077
- case "agent_stream_switch":
5078
- return handleAgentStreamSwitch(this, args);
5079
- case "agent_stream_read":
5080
- return handleAgentStreamRead(this, args);
5081
- case "agent_stream_send":
5082
- return handleAgentStreamSend(this, args);
5083
- case "agent_stream_resolve":
5084
- return handleAgentStreamResolve(this, args);
5085
- case "agent_stream_new":
5086
- return handleAgentStreamNew(this, args);
5087
- case "agent_stream_list_chats":
5088
- return handleAgentStreamListChats(this, args);
5089
- case "agent_stream_switch_session":
5090
- return handleAgentStreamSwitchSession(this, args);
5091
- case "agent_stream_focus":
5092
- return handleAgentStreamFocus(this, args);
5081
+ case "focus_session":
5082
+ return handleFocusSession(this, args);
5093
5083
  // ─── PTY Raw I/O (stream-commands.ts) ─────────
5094
5084
  case "pty_input":
5095
5085
  return handlePtyInput(this, args);
@@ -8487,8 +8477,7 @@ var init_router = __esm({
8487
8477
  "new_chat",
8488
8478
  "switch_chat",
8489
8479
  "set_mode",
8490
- "change_model",
8491
- "agent_stream_send"
8480
+ "change_model"
8492
8481
  ];
8493
8482
  DaemonCommandRouter = class {
8494
8483
  deps;
@@ -8726,6 +8715,7 @@ var init_router = __esm({
8726
8715
  } catch {
8727
8716
  }
8728
8717
  this.deps.cdpManagers.delete(key);
8718
+ this.deps.sessionRegistry.unregisterByManagerKey(key);
8729
8719
  LOG.info("StopIDE", `CDP disconnected: ${key}`);
8730
8720
  }
8731
8721
  }
@@ -8738,14 +8728,6 @@ var init_router = __esm({
8738
8728
  for (const instanceKey of keysToRemove) {
8739
8729
  const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
8740
8730
  if (ideInstance) {
8741
- if (ideInstance.getInstanceId) {
8742
- this.deps.instanceIdMap.delete(ideInstance.getInstanceId());
8743
- }
8744
- if (ideInstance.getExtensionInstances) {
8745
- for (const ext of ideInstance.getExtensionInstances()) {
8746
- if (ext.getInstanceId) this.deps.instanceIdMap.delete(ext.getInstanceId());
8747
- }
8748
- }
8749
8731
  this.deps.instanceManager.removeInstance(instanceKey);
8750
8732
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
8751
8733
  }
@@ -8754,14 +8736,6 @@ var init_router = __esm({
8754
8736
  const instanceKey = `ide:${ideType}`;
8755
8737
  const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
8756
8738
  if (ideInstance) {
8757
- if (ideInstance.getInstanceId) {
8758
- this.deps.instanceIdMap.delete(ideInstance.getInstanceId());
8759
- }
8760
- if (ideInstance.getExtensionInstances) {
8761
- for (const ext of ideInstance.getExtensionInstances()) {
8762
- if (ext.getInstanceId) this.deps.instanceIdMap.delete(ext.getInstanceId());
8763
- }
8764
- }
8765
8739
  this.deps.instanceManager.removeInstance(instanceKey);
8766
8740
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
8767
8741
  }
@@ -8810,15 +8784,9 @@ function buildStatusSnapshot(options) {
8810
8784
  const cfg = loadConfig();
8811
8785
  const wsState = getWorkspaceState(cfg);
8812
8786
  const memSnap = getHostMemorySnapshot();
8813
- const { managedIdes, managedClis, managedAcps } = buildAllManagedEntries(
8787
+ const sessions = buildSessionEntries(
8814
8788
  options.allStates,
8815
- options.cdpManagers,
8816
- {
8817
- detectedIdes: options.detectedIdes.map((ide) => ({
8818
- id: ide.id,
8819
- installed: ide.installed !== false
8820
- }))
8821
- }
8789
+ options.cdpManagers
8822
8790
  );
8823
8791
  return {
8824
8792
  instanceId: options.instanceId,
@@ -8840,9 +8808,7 @@ function buildStatusSnapshot(options) {
8840
8808
  timestamp: options.timestamp ?? Date.now(),
8841
8809
  detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
8842
8810
  ...options.p2p ? { p2p: options.p2p } : {},
8843
- managedIdes,
8844
- managedClis,
8845
- managedAcps,
8811
+ sessions,
8846
8812
  workspaces: wsState.workspaces,
8847
8813
  defaultWorkspaceId: wsState.defaultWorkspaceId,
8848
8814
  defaultWorkspacePath: wsState.defaultWorkspacePath,
@@ -8973,7 +8939,7 @@ var init_reporter = __esm({
8973
8939
  LOG.info("StatusReport", `\u2192${target} ${baseSummary}`);
8974
8940
  }
8975
8941
  }
8976
- const { managedIdes, managedClis, managedAcps } = buildAllManagedEntries(
8942
+ const sessions = buildSessionEntries(
8977
8943
  allStates,
8978
8944
  this.deps.cdpManagers
8979
8945
  );
@@ -9004,23 +8970,20 @@ var init_reporter = __esm({
9004
8970
  if (opts?.p2pOnly) return;
9005
8971
  const wsPayload = {
9006
8972
  daemonMode: true,
9007
- // managedIdes: server only saves id, type, cdpConnected
9008
- managedIdes: managedIdes.map((ide) => ({
9009
- ideType: ide.ideType,
9010
- instanceId: ide.instanceId,
9011
- cdpConnected: ide.cdpConnected
9012
- })),
9013
- // managedClis: server only saves id, type, name
9014
- managedClis: managedClis.map((c) => ({
9015
- id: c.id,
9016
- cliType: c.cliType,
9017
- cliName: c.cliName
9018
- })),
9019
- // managedAcps: server only saves id, type, name
9020
- managedAcps: managedAcps?.map((a) => ({
9021
- id: a.id,
9022
- acpType: a.acpType,
9023
- acpName: a.acpName
8973
+ sessions: sessions.map((session) => ({
8974
+ id: session.id,
8975
+ parentId: session.parentId,
8976
+ providerType: session.providerType,
8977
+ providerName: session.providerName,
8978
+ kind: session.kind,
8979
+ transport: session.transport,
8980
+ status: session.status,
8981
+ workspace: session.workspace,
8982
+ title: session.title,
8983
+ cdpConnected: session.cdpConnected,
8984
+ currentModel: session.currentModel,
8985
+ currentPlan: session.currentPlan,
8986
+ currentAutoApprove: session.currentAutoApprove
9024
8987
  })),
9025
8988
  p2p: payload.p2p,
9026
8989
  timestamp: now
@@ -36001,6 +35964,9 @@ var init_acp_provider_instance = __esm({
36001
35964
  );
36002
35965
  }
36003
35966
  }
35967
+ getInstanceId() {
35968
+ return this.instanceId;
35969
+ }
36004
35970
  // ─── ACP Config Options & Modes ─────────────────────
36005
35971
  parseConfigOptions(raw) {
36006
35972
  if (!Array.isArray(raw)) return;
@@ -36797,6 +36763,7 @@ var init_cli_manager = __esm({
36797
36763
  const normalizedType = this.providerLoader.resolveAlias(cliType);
36798
36764
  const provider = this.providerLoader.getByAlias(cliType);
36799
36765
  const key = crypto4.randomUUID();
36766
+ const sessionRegistry = this.deps.getSessionRegistry?.() || null;
36800
36767
  if (provider && provider.category === "acp") {
36801
36768
  const instanceManager2 = this.deps.getInstanceManager();
36802
36769
  if (!instanceManager2) throw new Error("InstanceManager not available");
@@ -36820,6 +36787,16 @@ ${installInfo}`
36820
36787
  await instanceManager2.addInstance(key, acpInstance, {
36821
36788
  settings: this.providerLoader.getSettings(normalizedType)
36822
36789
  });
36790
+ const sessionId = acpInstance.getInstanceId();
36791
+ sessionRegistry?.register({
36792
+ sessionId,
36793
+ parentSessionId: null,
36794
+ providerType: normalizedType,
36795
+ providerCategory: "acp",
36796
+ transport: "acp",
36797
+ adapterKey: key,
36798
+ instanceKey: key
36799
+ });
36823
36800
  this.adapters.set(key, {
36824
36801
  cliType: normalizedType,
36825
36802
  workingDir: resolvedDir,
@@ -36877,9 +36854,18 @@ ${installInfo}`
36877
36854
  serverConn: this.deps.getServerConn(),
36878
36855
  settings: {},
36879
36856
  onPtyData: (data) => {
36880
- this.deps.getP2p()?.broadcastPtyOutput(key, data);
36857
+ this.deps.getP2p()?.broadcastPtyOutput(cliInstance.instanceId, data);
36881
36858
  }
36882
36859
  });
36860
+ sessionRegistry?.register({
36861
+ sessionId: cliInstance.instanceId,
36862
+ parentSessionId: null,
36863
+ providerType: normalizedType,
36864
+ providerCategory: "cli",
36865
+ transport: "pty",
36866
+ adapterKey: key,
36867
+ instanceKey: key
36868
+ });
36883
36869
  } catch (spawnErr) {
36884
36870
  LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
36885
36871
  instanceManager.removeInstance(key);
@@ -36901,6 +36887,7 @@ ${installInfo}`
36901
36887
  if (this.adapters.has(key)) {
36902
36888
  this.adapters.delete(key);
36903
36889
  this.deps.removeAgentTracking(key);
36890
+ sessionRegistry?.unregisterByInstanceKey(key);
36904
36891
  instanceManager.removeInstance(key);
36905
36892
  LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${cliType}`);
36906
36893
  this.deps.onStatusChange();
@@ -36961,12 +36948,14 @@ ${installInfo}`
36961
36948
  }
36962
36949
  this.adapters.delete(key);
36963
36950
  this.deps.removeAgentTracking(key);
36951
+ this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
36964
36952
  this.deps.getInstanceManager()?.removeInstance(key);
36965
36953
  LOG.info("CLI", `\u{1F6D1} Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
36966
36954
  this.deps.onStatusChange();
36967
36955
  } else {
36968
36956
  const im = this.deps.getInstanceManager();
36969
36957
  if (im) {
36958
+ this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
36970
36959
  im.removeInstance(key);
36971
36960
  this.deps.removeAgentTracking(key);
36972
36961
  LOG.warn("CLI", `\u{1F9F9} Force-removed orphan entry: ${key}`);
@@ -36981,7 +36970,7 @@ ${installInfo}`
36981
36970
  // ─── Adapter search ─────────────────────────────
36982
36971
  /**
36983
36972
  * Search for CLI adapter. Priority order:
36984
- * 0. instanceKey (UUID direct match) — extracted from _targetInstance / composite ID
36973
+ * 0. sessionId (UUID direct match)
36985
36974
  * 1. agentType + dir (iteration match)
36986
36975
  * 2. agentType fuzzy match (⚠ returns first match when multiple sessions exist)
36987
36976
  */
@@ -37049,7 +37038,7 @@ ${installInfo}`
37049
37038
  const cliType = args?.cliType;
37050
37039
  const dir = args?.dir || "";
37051
37040
  if (!cliType) throw new Error("cliType required");
37052
- const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
37041
+ const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
37053
37042
  if (found) {
37054
37043
  await this.stopSession(found.key);
37055
37044
  } else {
@@ -37081,7 +37070,7 @@ ${installInfo}`
37081
37070
  }
37082
37071
  const dir = rdir.path;
37083
37072
  if (!cliType) throw new Error("cliType required");
37084
- const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
37073
+ const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
37085
37074
  if (found) await this.stopSession(found.key);
37086
37075
  await this.startSession(cliType, dir);
37087
37076
  this.persistRecentDir(cliType, dir);
@@ -37093,7 +37082,7 @@ ${installInfo}`
37093
37082
  if (!agentType || !action) throw new Error("agentType and action required");
37094
37083
  const found = this.findAdapter(agentType, {
37095
37084
  dir: args?.dir,
37096
- instanceKey: args?._targetInstance
37085
+ instanceKey: args?.targetSessionId
37097
37086
  });
37098
37087
  if (!found) throw new Error(`CLI agent not running: ${agentType}`);
37099
37088
  const { adapter, key } = found;
@@ -37257,14 +37246,8 @@ var init_manager2 = __esm({
37257
37246
  init_provider_adapter();
37258
37247
  init_logger();
37259
37248
  DaemonAgentStreamManager = class {
37260
- allAdapters = [];
37261
- managedByScope = /* @__PURE__ */ new Map();
37262
- enabled = true;
37263
- logFn;
37264
- lastDiscoveryTimeByScope = /* @__PURE__ */ new Map();
37265
- discoveryIntervalMsByScope = /* @__PURE__ */ new Map();
37266
- activeAgentTypeByScope = /* @__PURE__ */ new Map();
37267
- constructor(logFn, providerLoader) {
37249
+ constructor(logFn, providerLoader, sessionRegistry) {
37250
+ this.sessionRegistry = sessionRegistry;
37268
37251
  this.logFn = logFn || LOG.forComponent("AgentStream").asLogFn();
37269
37252
  if (providerLoader) {
37270
37253
  const allExtProviders = providerLoader.getByCategory("extension");
@@ -37272,257 +37255,278 @@ var init_manager2 = __esm({
37272
37255
  const resolved = providerLoader.resolve(p.type);
37273
37256
  if (!resolved) continue;
37274
37257
  const adapter = new ProviderStreamAdapter(resolved);
37275
- this.allAdapters.push(adapter);
37258
+ this.adaptersByType.set(p.type, adapter);
37276
37259
  this.logFn(`[AgentStream] Adapter created: ${p.type} (${p.name}) scripts=${Object.keys(resolved.scripts || {}).join(",") || "none"}`);
37277
37260
  }
37278
37261
  }
37279
37262
  }
37263
+ adaptersByType = /* @__PURE__ */ new Map();
37264
+ managedBySessionId = /* @__PURE__ */ new Map();
37265
+ enabled = true;
37266
+ logFn;
37267
+ lastDiscoveryTimeByParent = /* @__PURE__ */ new Map();
37268
+ discoveryIntervalMsByParent = /* @__PURE__ */ new Map();
37269
+ activeSessionIdByParent = /* @__PURE__ */ new Map();
37280
37270
  setEnabled(enabled) {
37281
37271
  this.enabled = enabled;
37282
37272
  }
37283
37273
  get isEnabled() {
37284
37274
  return this.enabled;
37285
37275
  }
37286
- getActiveAgentType(scopeKey) {
37287
- return this.activeAgentTypeByScope.get(scopeKey) || null;
37276
+ getActiveSessionId(parentSessionId) {
37277
+ return this.activeSessionIdByParent.get(parentSessionId) || null;
37288
37278
  }
37289
- getManagedScope(scopeKey) {
37290
- let managed = this.managedByScope.get(scopeKey);
37291
- if (!managed) {
37292
- managed = /* @__PURE__ */ new Map();
37293
- this.managedByScope.set(scopeKey, managed);
37294
- }
37295
- return managed;
37279
+ getSessionTarget(sessionId) {
37280
+ return this.sessionRegistry?.get(sessionId);
37296
37281
  }
37297
- resetScope(scopeKey) {
37298
- this.managedByScope.delete(scopeKey);
37299
- this.activeAgentTypeByScope.delete(scopeKey);
37300
- this.lastDiscoveryTimeByScope.delete(scopeKey);
37301
- this.discoveryIntervalMsByScope.delete(scopeKey);
37282
+ resetParentSession(parentSessionId) {
37283
+ const activeSessionId = this.activeSessionIdByParent.get(parentSessionId);
37284
+ if (activeSessionId) this.managedBySessionId.delete(activeSessionId);
37285
+ for (const child of this.sessionRegistry?.listChildren(parentSessionId) || []) {
37286
+ this.managedBySessionId.delete(child.sessionId);
37287
+ }
37288
+ this.activeSessionIdByParent.delete(parentSessionId);
37289
+ this.lastDiscoveryTimeByParent.delete(parentSessionId);
37290
+ this.discoveryIntervalMsByParent.delete(parentSessionId);
37302
37291
  }
37303
37292
  /** Panel focus based on provider.js focusPanel or extensionId (currently no-op) */
37304
- async ensureAgentPanelOpen(agentType, targetIdeType) {
37305
- }
37306
- async switchActiveAgent(cdp, scopeKey, agentType) {
37307
- const managed = this.getManagedScope(scopeKey);
37308
- const previousAgentType = this.getActiveAgentType(scopeKey);
37309
- if (previousAgentType === agentType) return;
37310
- if (previousAgentType) {
37311
- const prev = managed.get(previousAgentType);
37293
+ async ensureSessionPanelOpen(_sessionId) {
37294
+ }
37295
+ async setActiveSession(cdp, parentSessionId, sessionId) {
37296
+ const previousSessionId = this.getActiveSessionId(parentSessionId);
37297
+ if (previousSessionId === sessionId) return;
37298
+ if (previousSessionId) {
37299
+ const prev = this.managedBySessionId.get(previousSessionId);
37312
37300
  if (prev) {
37313
37301
  try {
37314
- await cdp.detachAgent(prev.sessionId);
37302
+ await cdp.detachAgent(prev.cdpSessionId);
37315
37303
  } catch {
37316
37304
  }
37317
- managed.delete(previousAgentType);
37318
- this.logFn(`[AgentStream] Deactivated: ${prev.adapter.agentName} (${scopeKey})`);
37319
- }
37320
- }
37321
- this.activeAgentTypeByScope.set(scopeKey, agentType);
37322
- this.lastDiscoveryTimeByScope.set(scopeKey, 0);
37323
- if (!agentType && managed.size === 0) {
37324
- this.managedByScope.delete(scopeKey);
37325
- }
37326
- this.logFn(`[AgentStream] Active agent (${scopeKey}): ${agentType || "none"}`);
37305
+ this.managedBySessionId.delete(previousSessionId);
37306
+ this.logFn(`[AgentStream] Deactivated: ${prev.adapter.agentName} (${parentSessionId})`);
37307
+ }
37308
+ }
37309
+ this.activeSessionIdByParent.set(parentSessionId, sessionId);
37310
+ this.lastDiscoveryTimeByParent.set(parentSessionId, 0);
37311
+ this.logFn(`[AgentStream] Active session (${parentSessionId}): ${sessionId || "none"}`);
37312
+ }
37313
+ resolveSessionIdForTarget(parentSessionId, agentType) {
37314
+ const child = (this.sessionRegistry?.listChildren(parentSessionId) || []).find((entry) => entry.providerCategory === "extension" && entry.providerType === agentType);
37315
+ return child?.sessionId || null;
37316
+ }
37317
+ async connectManagedSession(cdp, parentSessionId, runtimeSessionId) {
37318
+ const target = this.getSessionTarget(runtimeSessionId);
37319
+ if (!target || target.providerCategory !== "extension") return null;
37320
+ const adapter = this.adaptersByType.get(target.providerType);
37321
+ if (!adapter) return null;
37322
+ const targets = await cdp.discoverAgentWebviews();
37323
+ const activeTarget = targets.find((entry) => entry.agentType === target.providerType);
37324
+ if (!activeTarget) return null;
37325
+ const cdpSessionId = await cdp.attachToAgent(activeTarget);
37326
+ if (!cdpSessionId) return null;
37327
+ const managed = {
37328
+ adapter,
37329
+ runtimeSessionId,
37330
+ parentSessionId,
37331
+ cdpSessionId,
37332
+ target: activeTarget,
37333
+ lastState: null,
37334
+ lastError: null,
37335
+ lastHiddenCheckTime: 0
37336
+ };
37337
+ this.managedBySessionId.set(runtimeSessionId, managed);
37338
+ this.logFn(`[AgentStream] Connected: ${adapter.agentName} (${parentSessionId})`);
37339
+ return managed;
37327
37340
  }
37328
37341
  /** Agent webview discovery + session connection */
37329
- async syncAgentSessions(cdp, scopeKey) {
37330
- const activeAgentType = this.getActiveAgentType(scopeKey);
37331
- if (!this.enabled || !activeAgentType) return;
37342
+ async syncActiveSession(cdp, parentSessionId) {
37343
+ const activeSessionId = this.getActiveSessionId(parentSessionId);
37344
+ if (!this.enabled || !activeSessionId) return;
37332
37345
  const now = Date.now();
37333
- const managed = this.getManagedScope(scopeKey);
37334
- const lastDiscoveryTime = this.lastDiscoveryTimeByScope.get(scopeKey) || 0;
37335
- const discoveryIntervalMs = this.discoveryIntervalMsByScope.get(scopeKey) || 1e4;
37336
- if (managed.has(activeAgentType) && now - lastDiscoveryTime < discoveryIntervalMs) {
37346
+ const managed = this.managedBySessionId.get(activeSessionId);
37347
+ const lastDiscoveryTime = this.lastDiscoveryTimeByParent.get(parentSessionId) || 0;
37348
+ const discoveryIntervalMs = this.discoveryIntervalMsByParent.get(parentSessionId) || 1e4;
37349
+ if (managed && now - lastDiscoveryTime < discoveryIntervalMs) {
37337
37350
  return;
37338
37351
  }
37339
- this.lastDiscoveryTimeByScope.set(scopeKey, now);
37352
+ this.lastDiscoveryTimeByParent.set(parentSessionId, now);
37340
37353
  try {
37341
- const targets = await cdp.discoverAgentWebviews();
37342
- const activeTarget = targets.find((t) => t.agentType === activeAgentType);
37343
- if (activeTarget && !managed.has(activeAgentType)) {
37344
- const adapter = this.allAdapters.find((a) => a.agentType === activeAgentType);
37345
- if (adapter) {
37346
- const sessionId = await cdp.attachToAgent(activeTarget);
37347
- if (sessionId) {
37348
- managed.set(activeAgentType, {
37349
- adapter,
37350
- sessionId,
37351
- target: activeTarget,
37352
- lastState: null,
37353
- lastError: null,
37354
- lastHiddenCheckTime: 0
37355
- });
37356
- this.logFn(`[AgentStream] Connected: ${adapter.agentName} (${scopeKey})`);
37357
- }
37358
- }
37359
- }
37360
- for (const [type, agent] of managed) {
37361
- if (type !== activeAgentType) {
37362
- await cdp.detachAgent(agent.sessionId);
37363
- managed.delete(type);
37364
- }
37354
+ if (!managed) {
37355
+ await this.connectManagedSession(cdp, parentSessionId, activeSessionId);
37365
37356
  }
37366
- this.discoveryIntervalMsByScope.set(scopeKey, managed.has(activeAgentType) ? 3e4 : 1e4);
37357
+ this.discoveryIntervalMsByParent.set(parentSessionId, this.managedBySessionId.has(activeSessionId) ? 3e4 : 1e4);
37367
37358
  } catch (e) {
37368
- this.logFn(`[AgentStream] sync error (${scopeKey}): ${e.message}`);
37359
+ this.logFn(`[AgentStream] sync error (${parentSessionId}): ${e.message}`);
37369
37360
  }
37370
37361
  }
37371
- /** Collect active agent status */
37372
- async collectAgentStreams(cdp, scopeKey) {
37373
- if (!this.enabled) return [];
37374
- const results = [];
37375
- const activeAgentType = this.getActiveAgentType(scopeKey);
37376
- const managed = this.managedByScope.get(scopeKey);
37377
- if (activeAgentType && managed?.has(activeAgentType)) {
37378
- const agent = managed.get(activeAgentType);
37379
- const type = activeAgentType;
37380
- const isHidden = agent.lastState?.status === "panel_hidden";
37381
- const hiddenCacheFresh = isHidden && Date.now() - agent.lastHiddenCheckTime < 3e4;
37382
- if (hiddenCacheFresh) {
37383
- results.push(agent.lastState);
37384
- } else {
37362
+ /** Collect active extension session state */
37363
+ async collectActiveSession(cdp, parentSessionId) {
37364
+ if (!this.enabled) return null;
37365
+ const activeSessionId = this.getActiveSessionId(parentSessionId);
37366
+ if (!activeSessionId) return null;
37367
+ let agent = this.managedBySessionId.get(activeSessionId);
37368
+ if (!agent) {
37369
+ agent = await this.connectManagedSession(cdp, parentSessionId, activeSessionId) || void 0;
37370
+ }
37371
+ if (!agent) return null;
37372
+ const type = agent.adapter.agentType;
37373
+ const isHidden = agent.lastState?.status === "panel_hidden";
37374
+ const hiddenCacheFresh = isHidden && Date.now() - agent.lastHiddenCheckTime < 3e4;
37375
+ if (hiddenCacheFresh) return agent.lastState;
37376
+ try {
37377
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37378
+ const state = await agent.adapter.readChat(evaluate);
37379
+ LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${state.model || ""}${state.status === "error" ? " error=" + JSON.stringify(state.error || state._error || "unknown") : ""}`);
37380
+ agent.lastState = state;
37381
+ agent.lastError = null;
37382
+ if (state.status === "panel_hidden") {
37383
+ agent.lastHiddenCheckTime = Date.now();
37384
+ }
37385
+ return state;
37386
+ } catch (e) {
37387
+ const errorMsg = e?.message || String(e);
37388
+ this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
37389
+ agent.lastError = errorMsg;
37390
+ if (errorMsg.includes("timeout") || errorMsg.includes("not connected") || errorMsg.includes("Session")) {
37385
37391
  try {
37386
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37387
- const state = await agent.adapter.readChat(evaluate);
37388
- LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${state.model || ""}${state.status === "error" ? " error=" + JSON.stringify(state.error || state._error || "unknown") : ""}`);
37389
- agent.lastState = state;
37390
- agent.lastError = null;
37391
- if (state.status === "panel_hidden") {
37392
- agent.lastHiddenCheckTime = Date.now();
37393
- }
37394
- results.push(state);
37395
- } catch (e) {
37396
- const errorMsg = e?.message || String(e);
37397
- this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
37398
- agent.lastError = errorMsg;
37399
- results.push({
37400
- agentType: type,
37401
- agentName: agent.adapter.agentName,
37402
- extensionId: agent.adapter.extensionId,
37403
- status: "disconnected",
37404
- messages: agent.lastState?.messages || [],
37405
- inputContent: ""
37406
- });
37407
- if (errorMsg.includes("timeout") || errorMsg.includes("not connected") || errorMsg.includes("Session")) {
37408
- try {
37409
- await cdp.detachAgent(agent.sessionId);
37410
- } catch {
37411
- }
37412
- managed.delete(type);
37413
- this.lastDiscoveryTimeByScope.set(scopeKey, 0);
37414
- }
37392
+ await cdp.detachAgent(agent.cdpSessionId);
37393
+ } catch {
37415
37394
  }
37395
+ this.managedBySessionId.delete(activeSessionId);
37396
+ this.lastDiscoveryTimeByParent.set(parentSessionId, 0);
37416
37397
  }
37398
+ return {
37399
+ agentType: type,
37400
+ agentName: agent.adapter.agentName,
37401
+ extensionId: agent.adapter.extensionId,
37402
+ status: "disconnected",
37403
+ messages: agent.lastState?.messages || [],
37404
+ inputContent: ""
37405
+ };
37417
37406
  }
37418
- return results;
37419
37407
  }
37420
- async sendToAgent(cdp, scopeKey, agentType, text, targetIdeType) {
37421
- await this.ensureAgentPanelOpen(agentType, targetIdeType);
37422
- const agent = this.getManagedAgent(agentType, scopeKey);
37408
+ async sendToSession(cdp, sessionId, text) {
37409
+ await this.ensureSessionPanelOpen(sessionId);
37410
+ const target = this.getSessionTarget(sessionId);
37411
+ if (!target?.parentSessionId) return false;
37412
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37413
+ await this.syncActiveSession(cdp, target.parentSessionId);
37414
+ const agent = this.managedBySessionId.get(sessionId);
37423
37415
  if (!agent) return false;
37424
37416
  try {
37425
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37417
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37426
37418
  await agent.adapter.sendMessage(evaluate, text);
37427
37419
  return true;
37428
37420
  } catch (e) {
37429
- this.logFn(`[AgentStream] sendToAgent(${agentType}) error: ${e.message}`);
37421
+ this.logFn(`[AgentStream] sendToSession(${sessionId}) error: ${e.message}`);
37430
37422
  return false;
37431
37423
  }
37432
37424
  }
37433
- async resolveAgentAction(cdp, scopeKey, agentType, action, targetIdeType) {
37434
- await this.ensureAgentPanelOpen(agentType, targetIdeType);
37435
- const agent = this.getManagedAgent(agentType, scopeKey);
37425
+ async resolveSessionAction(cdp, sessionId, action) {
37426
+ await this.ensureSessionPanelOpen(sessionId);
37427
+ const target = this.getSessionTarget(sessionId);
37428
+ if (!target?.parentSessionId) return false;
37429
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37430
+ await this.syncActiveSession(cdp, target.parentSessionId);
37431
+ const agent = this.managedBySessionId.get(sessionId);
37436
37432
  if (!agent) return false;
37437
37433
  try {
37438
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37434
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37439
37435
  return await agent.adapter.resolveAction(evaluate, action);
37440
37436
  } catch (e) {
37441
- this.logFn(`[AgentStream] resolveAction(${agentType}) error: ${e.message}`);
37437
+ this.logFn(`[AgentStream] resolveAction(${sessionId}) error: ${e.message}`);
37442
37438
  return false;
37443
37439
  }
37444
37440
  }
37445
- async newAgentSession(cdp, scopeKey, agentType, targetIdeType) {
37446
- await this.ensureAgentPanelOpen(agentType, targetIdeType);
37447
- const agent = this.getManagedAgent(agentType, scopeKey);
37441
+ async newSession(cdp, sessionId) {
37442
+ await this.ensureSessionPanelOpen(sessionId);
37443
+ const target = this.getSessionTarget(sessionId);
37444
+ if (!target?.parentSessionId) return false;
37445
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37446
+ await this.syncActiveSession(cdp, target.parentSessionId);
37447
+ const agent = this.managedBySessionId.get(sessionId);
37448
37448
  if (!agent) return false;
37449
37449
  try {
37450
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37450
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37451
37451
  await agent.adapter.newSession(evaluate);
37452
37452
  return true;
37453
37453
  } catch (e) {
37454
- this.logFn(`[AgentStream] newSession(${agentType}) error: ${e.message}`);
37454
+ this.logFn(`[AgentStream] newSession(${sessionId}) error: ${e.message}`);
37455
37455
  return false;
37456
37456
  }
37457
37457
  }
37458
- async listAgentChats(cdp, scopeKey, agentType) {
37459
- let agent = this.getManagedAgent(agentType, scopeKey);
37460
- if (!agent) {
37461
- this.logFn(`[AgentStream] listChats: ${agentType} not managed in ${scopeKey}, trying on-demand activation`);
37462
- await this.switchActiveAgent(cdp, scopeKey, agentType);
37463
- await this.syncAgentSessions(cdp, scopeKey);
37464
- agent = this.getManagedAgent(agentType, scopeKey);
37465
- }
37458
+ async listSessionChats(cdp, sessionId) {
37459
+ const target = this.getSessionTarget(sessionId);
37460
+ if (!target?.parentSessionId) return [];
37461
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37462
+ await this.syncActiveSession(cdp, target.parentSessionId);
37463
+ const agent = this.managedBySessionId.get(sessionId);
37466
37464
  if (!agent || typeof agent.adapter.listChats !== "function") return [];
37467
37465
  try {
37468
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37466
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37469
37467
  return await agent.adapter.listChats(evaluate);
37470
37468
  } catch (e) {
37471
- this.logFn(`[AgentStream] listChats(${agentType}) error: ${e.message}`);
37469
+ this.logFn(`[AgentStream] listChats(${sessionId}) error: ${e.message}`);
37472
37470
  return [];
37473
37471
  }
37474
37472
  }
37475
- async switchAgentSession(cdp, scopeKey, agentType, sessionId) {
37476
- let agent = this.getManagedAgent(agentType, scopeKey);
37477
- if (!agent) {
37478
- this.logFn(`[AgentStream] switchSession: ${agentType} not managed in ${scopeKey}, trying on-demand activation`);
37479
- await this.switchActiveAgent(cdp, scopeKey, agentType);
37480
- await this.syncAgentSessions(cdp, scopeKey);
37481
- agent = this.getManagedAgent(agentType, scopeKey);
37482
- }
37473
+ async switchConversation(cdp, sessionId, conversationId) {
37474
+ const target = this.getSessionTarget(sessionId);
37475
+ if (!target?.parentSessionId) return false;
37476
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37477
+ await this.syncActiveSession(cdp, target.parentSessionId);
37478
+ const agent = this.managedBySessionId.get(sessionId);
37483
37479
  if (!agent || typeof agent.adapter.switchSession !== "function") return false;
37484
37480
  try {
37485
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37486
- return await agent.adapter.switchSession(evaluate, sessionId);
37481
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37482
+ return await agent.adapter.switchSession(evaluate, conversationId);
37487
37483
  } catch (e) {
37488
- this.logFn(`[AgentStream] switchSession(${agentType}) error: ${e.message}`);
37484
+ this.logFn(`[AgentStream] switchSession(${sessionId}) error: ${e.message}`);
37489
37485
  return false;
37490
37486
  }
37491
37487
  }
37492
- async focusAgentEditor(cdp, scopeKey, agentType) {
37493
- const agent = this.getManagedAgent(agentType, scopeKey);
37488
+ async focusSession(cdp, sessionId) {
37489
+ const target = this.getSessionTarget(sessionId);
37490
+ if (!target?.parentSessionId) return false;
37491
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37492
+ await this.syncActiveSession(cdp, target.parentSessionId);
37493
+ const agent = this.managedBySessionId.get(sessionId);
37494
37494
  if (!agent || typeof agent.adapter.focusEditor !== "function") return false;
37495
37495
  try {
37496
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37496
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37497
37497
  await agent.adapter.focusEditor(evaluate);
37498
37498
  return true;
37499
37499
  } catch (e) {
37500
- this.logFn(`[AgentStream] focusEditor(${agentType}) error: ${e.message}`);
37500
+ this.logFn(`[AgentStream] focusEditor(${sessionId}) error: ${e.message}`);
37501
37501
  return false;
37502
37502
  }
37503
37503
  }
37504
- getConnectedAgents(scopeKey) {
37505
- if (scopeKey) return Array.from((this.managedByScope.get(scopeKey) || /* @__PURE__ */ new Map()).keys());
37506
- return Array.from(this.managedByScope.values()).flatMap((scope) => Array.from(scope.keys()));
37504
+ getConnectedSessions(parentSessionId) {
37505
+ if (parentSessionId) {
37506
+ return [...this.managedBySessionId.values()].filter((entry) => entry.parentSessionId === parentSessionId).map((entry) => entry.runtimeSessionId);
37507
+ }
37508
+ return [...this.managedBySessionId.keys()];
37507
37509
  }
37508
- getManagedAgent(agentType, scopeKey) {
37509
- return this.managedByScope.get(scopeKey)?.get(agentType);
37510
+ getManagedSession(sessionId) {
37511
+ return this.managedBySessionId.get(sessionId);
37510
37512
  }
37511
37513
  async dispose(cdpManagers) {
37512
- for (const [scopeKey, managed] of this.managedByScope) {
37513
- const cdp = cdpManagers.get(scopeKey);
37514
+ for (const managed of this.managedBySessionId.values()) {
37515
+ const managerKey = this.getSessionTarget(managed.runtimeSessionId)?.cdpManagerKey;
37516
+ const cdp = managerKey ? cdpManagers.get(managerKey) : null;
37514
37517
  if (!cdp) continue;
37515
- for (const [, agent] of managed) {
37516
- try {
37517
- await cdp.detachAgent(agent.sessionId);
37518
- } catch {
37519
- }
37518
+ try {
37519
+ await cdp.detachAgent(managed.cdpSessionId);
37520
+ } catch {
37520
37521
  }
37521
37522
  }
37522
- this.managedByScope.clear();
37523
- this.activeAgentTypeByScope.clear();
37524
- this.lastDiscoveryTimeByScope.clear();
37525
- this.discoveryIntervalMsByScope.clear();
37523
+ this.managedBySessionId.clear();
37524
+ this.activeSessionIdByParent.clear();
37525
+ this.lastDiscoveryTimeByParent.clear();
37526
+ this.discoveryIntervalMsByParent.clear();
37527
+ }
37528
+ resolveSessionForAgent(parentSessionId, agentType) {
37529
+ return this.resolveSessionIdForTarget(parentSessionId, agentType);
37526
37530
  }
37527
37531
  };
37528
37532
  }
@@ -37553,8 +37557,8 @@ var init_poller = __esm({
37553
37557
  return null;
37554
37558
  }
37555
37559
  /** Reset active IDE tracking (e.g., when IDE is stopped) */
37556
- resetActiveIde(ideType) {
37557
- this.deps.agentStreamManager.resetScope(ideType);
37560
+ resetActiveIde(parentSessionId) {
37561
+ this.deps.agentStreamManager.resetParentSession(parentSessionId);
37558
37562
  }
37559
37563
  /** Start polling (idempotent — ignored if already started) */
37560
37564
  start(intervalMs = 5e3) {
@@ -37576,12 +37580,14 @@ var init_poller = __esm({
37576
37580
  agentStreamManager,
37577
37581
  providerLoader,
37578
37582
  instanceManager,
37579
- cdpManagers
37583
+ cdpManagers,
37584
+ sessionRegistry
37580
37585
  } = this.deps;
37581
37586
  if (!agentStreamManager || cdpManagers.size === 0) return;
37582
37587
  for (const [ideType, cdp] of cdpManagers) {
37583
37588
  registerExtensionProviders(providerLoader, cdp, ideType);
37584
37589
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
37590
+ const parentSessionId = ideInstance?.getInstanceId?.();
37585
37591
  if (ideInstance?.getExtensionTypes && ideInstance?.addExtension && ideInstance?.removeExtension) {
37586
37592
  const currentExtTypes = new Set(ideInstance.getExtensionTypes());
37587
37593
  const enabledExtTypes = new Set(
@@ -37589,6 +37595,10 @@ var init_poller = __esm({
37589
37595
  );
37590
37596
  for (const extType of currentExtTypes) {
37591
37597
  if (!enabledExtTypes.has(extType)) {
37598
+ const extInstance = ideInstance.getExtension?.(extType);
37599
+ if (extInstance?.getInstanceId) {
37600
+ sessionRegistry.unregister(extInstance.getInstanceId());
37601
+ }
37592
37602
  ideInstance.removeExtension(extType);
37593
37603
  LOG.info("AgentStream", `Extension removed: ${extType} (disabled for ${ideType})`);
37594
37604
  }
@@ -37599,46 +37609,61 @@ var init_poller = __esm({
37599
37609
  if (extProvider) {
37600
37610
  const extSettings = providerLoader.getSettings(extType);
37601
37611
  ideInstance.addExtension(extProvider, extSettings);
37612
+ const extInstance = ideInstance.getExtension?.(extType);
37613
+ if (parentSessionId && extInstance?.getInstanceId) {
37614
+ sessionRegistry.register({
37615
+ sessionId: extInstance.getInstanceId(),
37616
+ parentSessionId,
37617
+ providerType: extType,
37618
+ providerCategory: "extension",
37619
+ transport: "cdp-webview",
37620
+ cdpManagerKey: ideType,
37621
+ instanceKey: `ide:${ideType}`
37622
+ });
37623
+ }
37602
37624
  LOG.info("AgentStream", `Extension added: ${extType} (enabled for ${ideType})`);
37603
37625
  }
37604
37626
  }
37605
37627
  }
37606
37628
  }
37607
- const activeType = agentStreamManager.getActiveAgentType(ideType);
37608
- if (activeType) {
37609
- const enabledExtTypes = new Set(
37610
- providerLoader.getEnabledExtensionProviders(ideType).map((p) => p.type)
37611
- );
37612
- if (!enabledExtTypes.has(activeType)) {
37613
- LOG.info("AgentStream", `Active agent ${activeType} was disabled for ${ideType} \u2014 detaching`);
37614
- await agentStreamManager.switchActiveAgent(cdp, ideType, null);
37629
+ const activeSessionId = parentSessionId ? agentStreamManager.getActiveSessionId(parentSessionId) : null;
37630
+ if (activeSessionId) {
37631
+ const activeTarget = sessionRegistry.get(activeSessionId);
37632
+ const enabledExtTypes = new Set(providerLoader.getEnabledExtensionProviders(ideType).map((p) => p.type));
37633
+ if (!activeTarget || !enabledExtTypes.has(activeTarget.providerType)) {
37634
+ LOG.info("AgentStream", `Active agent ${activeTarget?.providerType || activeSessionId} was disabled for ${ideType} \u2014 detaching`);
37635
+ await agentStreamManager.setActiveSession(cdp, parentSessionId, null);
37615
37636
  this.deps.onStreamsUpdated?.(ideType, []);
37616
37637
  }
37617
37638
  }
37618
37639
  if (!cdp.isConnected) {
37619
- if (activeType) {
37620
- agentStreamManager.resetScope(ideType);
37640
+ if (parentSessionId && activeSessionId) {
37641
+ agentStreamManager.resetParentSession(parentSessionId);
37621
37642
  this.deps.onStreamsUpdated?.(ideType, []);
37622
37643
  }
37623
37644
  continue;
37624
37645
  }
37625
- let resolvedActiveType = activeType;
37626
- if (!resolvedActiveType) {
37646
+ let resolvedActiveSessionId = activeSessionId;
37647
+ if (!resolvedActiveSessionId && parentSessionId) {
37627
37648
  try {
37628
37649
  const discovered = await cdp.discoverAgentWebviews();
37629
- if (discovered.length > 0) {
37630
- resolvedActiveType = discovered[0].agentType;
37631
- await agentStreamManager.switchActiveAgent(cdp, ideType, resolvedActiveType);
37632
- LOG.info("AgentStream", `Auto-activated: ${resolvedActiveType} (${ideType})`);
37650
+ for (const target of discovered) {
37651
+ const sessionId = agentStreamManager.resolveSessionForAgent(parentSessionId, target.agentType);
37652
+ if (sessionId) {
37653
+ resolvedActiveSessionId = sessionId;
37654
+ await agentStreamManager.setActiveSession(cdp, parentSessionId, sessionId);
37655
+ LOG.info("AgentStream", `Auto-activated: ${target.agentType} (${ideType})`);
37656
+ break;
37657
+ }
37633
37658
  }
37634
37659
  } catch {
37635
37660
  }
37636
37661
  }
37637
- if (!resolvedActiveType) continue;
37662
+ if (!resolvedActiveSessionId || !parentSessionId) continue;
37638
37663
  try {
37639
- await agentStreamManager.syncAgentSessions(cdp, ideType);
37640
- const streams = await agentStreamManager.collectAgentStreams(cdp, ideType);
37641
- this.deps.onStreamsUpdated?.(ideType, streams);
37664
+ await agentStreamManager.syncActiveSession(cdp, parentSessionId);
37665
+ const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
37666
+ this.deps.onStreamsUpdated?.(ideType, stream ? [stream] : []);
37642
37667
  } catch {
37643
37668
  }
37644
37669
  }
@@ -37749,6 +37774,7 @@ var init_provider_instance_manager = __esm({
37749
37774
  ...event,
37750
37775
  providerType: instance.type,
37751
37776
  instanceId: state.instanceId,
37777
+ targetSessionId: state.instanceId,
37752
37778
  providerCategory: state.category
37753
37779
  });
37754
37780
  }
@@ -41403,6 +41429,69 @@ var init_installer = __esm({
41403
41429
  }
41404
41430
  });
41405
41431
 
41432
+ // ../../oss/packages/daemon-core/src/sessions/registry.ts
41433
+ var SessionRegistry;
41434
+ var init_registry = __esm({
41435
+ "../../oss/packages/daemon-core/src/sessions/registry.ts"() {
41436
+ "use strict";
41437
+ SessionRegistry = class {
41438
+ bySessionId = /* @__PURE__ */ new Map();
41439
+ byManagerKey = /* @__PURE__ */ new Map();
41440
+ byInstanceKey = /* @__PURE__ */ new Map();
41441
+ byParentSessionId = /* @__PURE__ */ new Map();
41442
+ register(target) {
41443
+ this.unregister(target.sessionId);
41444
+ this.bySessionId.set(target.sessionId, target);
41445
+ if (target.cdpManagerKey) this.addIndex(this.byManagerKey, target.cdpManagerKey, target.sessionId);
41446
+ if (target.instanceKey) this.addIndex(this.byInstanceKey, target.instanceKey, target.sessionId);
41447
+ if (target.parentSessionId) this.addIndex(this.byParentSessionId, target.parentSessionId, target.sessionId);
41448
+ }
41449
+ get(sessionId) {
41450
+ if (!sessionId) return void 0;
41451
+ return this.bySessionId.get(sessionId);
41452
+ }
41453
+ unregister(sessionId) {
41454
+ if (!sessionId) return;
41455
+ const target = this.bySessionId.get(sessionId);
41456
+ if (!target) return;
41457
+ this.bySessionId.delete(sessionId);
41458
+ if (target.cdpManagerKey) this.removeIndex(this.byManagerKey, target.cdpManagerKey, sessionId);
41459
+ if (target.instanceKey) this.removeIndex(this.byInstanceKey, target.instanceKey, sessionId);
41460
+ if (target.parentSessionId) this.removeIndex(this.byParentSessionId, target.parentSessionId, sessionId);
41461
+ }
41462
+ unregisterByManagerKey(managerKey) {
41463
+ for (const sessionId of [...this.byManagerKey.get(managerKey) || []]) {
41464
+ this.unregister(sessionId);
41465
+ }
41466
+ }
41467
+ unregisterByInstanceKey(instanceKey) {
41468
+ for (const sessionId of [...this.byInstanceKey.get(instanceKey) || []]) {
41469
+ this.unregister(sessionId);
41470
+ }
41471
+ }
41472
+ listChildren(parentSessionId) {
41473
+ const ids = this.byParentSessionId.get(parentSessionId);
41474
+ if (!ids) return [];
41475
+ return [...ids].map((id) => this.bySessionId.get(id)).filter(Boolean);
41476
+ }
41477
+ addIndex(index, key, sessionId) {
41478
+ let set2 = index.get(key);
41479
+ if (!set2) {
41480
+ set2 = /* @__PURE__ */ new Set();
41481
+ index.set(key, set2);
41482
+ }
41483
+ set2.add(sessionId);
41484
+ }
41485
+ removeIndex(index, key, sessionId) {
41486
+ const set2 = index.get(key);
41487
+ if (!set2) return;
41488
+ set2.delete(sessionId);
41489
+ if (set2.size === 0) index.delete(key);
41490
+ }
41491
+ };
41492
+ }
41493
+ });
41494
+
41406
41495
  // ../../oss/packages/daemon-core/src/boot/daemon-lifecycle.ts
41407
41496
  async function initDaemonComponents(config2) {
41408
41497
  installGlobalInterceptor();
@@ -41440,11 +41529,14 @@ async function initDaemonComponents(config2) {
41440
41529
  });
41441
41530
  const instanceManager = new ProviderInstanceManager();
41442
41531
  const cdpManagers = /* @__PURE__ */ new Map();
41443
- const instanceIdMap = /* @__PURE__ */ new Map();
41532
+ const sessionRegistry = new SessionRegistry();
41444
41533
  const detectedIdesRef = { value: [] };
41534
+ let agentStreamManager = null;
41535
+ let poller = null;
41445
41536
  const cliManager = new DaemonCliManager({
41446
41537
  ...config2.cliManagerDeps,
41447
- getInstanceManager: () => instanceManager
41538
+ getInstanceManager: () => instanceManager,
41539
+ getSessionRegistry: () => sessionRegistry
41448
41540
  }, providerLoader);
41449
41541
  LOG.info("Init", "Detecting IDEs...");
41450
41542
  detectedIdesRef.value = await detectIDEs();
@@ -41454,7 +41546,7 @@ async function initDaemonComponents(config2) {
41454
41546
  providerLoader,
41455
41547
  instanceManager,
41456
41548
  cdpManagers,
41457
- instanceIdMap
41549
+ sessionRegistry
41458
41550
  };
41459
41551
  const cdpInitializer = new DaemonCdpInitializer({
41460
41552
  providerLoader,
@@ -41463,6 +41555,19 @@ async function initDaemonComponents(config2) {
41463
41555
  onConnected: async (ideType, manager, managerKey) => {
41464
41556
  await setupIdeInstance(cdpSetupContext, { ideType, manager, managerKey });
41465
41557
  await config2.onCdpManagerSetup?.(ideType, manager, managerKey);
41558
+ },
41559
+ onDisconnected: async (_ideType, _manager, managerKey) => {
41560
+ sessionRegistry.unregisterByManagerKey(managerKey);
41561
+ const instanceKey = `ide:${managerKey}`;
41562
+ const ideInstance = instanceManager.getInstance(instanceKey);
41563
+ if (ideInstance) {
41564
+ instanceManager.removeInstance(instanceKey);
41565
+ LOG.info("CDP", `Instance removed after disconnect: ${instanceKey}`);
41566
+ }
41567
+ if (ideInstance?.getInstanceId) {
41568
+ agentStreamManager?.resetParentSession(ideInstance.getInstanceId());
41569
+ }
41570
+ config2.onStatusChange?.();
41466
41571
  }
41467
41572
  });
41468
41573
  await cdpInitializer.connectAll(detectedIdesRef.value);
@@ -41474,14 +41579,14 @@ async function initDaemonComponents(config2) {
41474
41579
  adapters: cliManager.adapters,
41475
41580
  providerLoader,
41476
41581
  instanceManager,
41477
- instanceIdMap
41582
+ sessionRegistry
41478
41583
  });
41479
- const agentStreamManager = new DaemonAgentStreamManager(
41584
+ agentStreamManager = new DaemonAgentStreamManager(
41480
41585
  LOG.forComponent("AgentStream").asLogFn(),
41481
- providerLoader
41586
+ providerLoader,
41587
+ sessionRegistry
41482
41588
  );
41483
41589
  commandHandler.setAgentStreamManager(agentStreamManager);
41484
- let poller;
41485
41590
  const router = new DaemonCommandRouter({
41486
41591
  commandHandler,
41487
41592
  cliManager,
@@ -41489,7 +41594,7 @@ async function initDaemonComponents(config2) {
41489
41594
  providerLoader,
41490
41595
  instanceManager,
41491
41596
  detectedIdes: detectedIdesRef,
41492
- instanceIdMap,
41597
+ sessionRegistry,
41493
41598
  onCdpManagerCreated: async (ideType, manager) => {
41494
41599
  await setupIdeInstance(cdpSetupContext, { ideType, manager });
41495
41600
  await config2.onCdpManagerSetup?.(ideType, manager, ideType);
@@ -41504,6 +41609,7 @@ async function initDaemonComponents(config2) {
41504
41609
  providerLoader,
41505
41610
  instanceManager,
41506
41611
  cdpManagers,
41612
+ sessionRegistry,
41507
41613
  onStreamsUpdated: config2.onStreamsUpdated
41508
41614
  });
41509
41615
  poller.start();
@@ -41518,7 +41624,7 @@ async function initDaemonComponents(config2) {
41518
41624
  poller,
41519
41625
  cdpInitializer,
41520
41626
  cdpManagers,
41521
- instanceIdMap,
41627
+ sessionRegistry,
41522
41628
  detectedIdes: detectedIdesRef
41523
41629
  };
41524
41630
  }
@@ -41571,6 +41677,7 @@ var init_daemon_lifecycle = __esm({
41571
41677
  init_provider_instance_manager();
41572
41678
  init_dev_server();
41573
41679
  init_ide_detector();
41680
+ init_registry();
41574
41681
  init_logger();
41575
41682
  init_config();
41576
41683
  }
@@ -42926,7 +43033,7 @@ var init_adhdev_daemon = __esm({
42926
43033
  fs12 = __toESM(require("fs"));
42927
43034
  path14 = __toESM(require("path"));
42928
43035
  import_chalk2 = __toESM(require("chalk"));
42929
- pkgVersion = "0.6.79";
43036
+ pkgVersion = "0.7.0";
42930
43037
  if (pkgVersion === "unknown") {
42931
43038
  try {
42932
43039
  const possiblePaths = [
@@ -43204,7 +43311,7 @@ ${err?.stack || ""}`);
43204
43311
  });
43205
43312
  }
43206
43313
  async handleCommand(msg, cmd, args) {
43207
- LOG.info("Command", `${cmd}${args?._targetInstance ? ` \u2192 ${args._targetType}:${args._targetInstance.split("_")[0]}` : ""}`);
43314
+ LOG.info("Command", `${cmd}${args?.targetSessionId ? ` \u2192 session:${String(args.targetSessionId).split("_")[0]}` : ""}`);
43208
43315
  const cmdStart = Date.now();
43209
43316
  const source = msg.ipcWs ? "ext" : "ws";
43210
43317
  try {
@@ -43320,24 +43427,13 @@ ${err?.stack || ""}`);
43320
43427
  // ─── CDP helpers ─────────────────────────────
43321
43428
  /** Return CDP manager for specific IDE.
43322
43429
  * Lookup order:
43323
- * 1. instanceIdMap (UUID managerKey) for multi-window UUID instance IDs
43324
- * 2. Exact match on cdpManagers (key = "cursor", "antigravity")
43325
- * 3. Prefix match (multi-window: "antigravity_WorkspaceName")
43430
+ * 1. Exact match on cdpManagers (full manager key)
43431
+ * 2. Prefix match on cdpManagers (ideType_workspace)
43326
43432
  */
43327
43433
  getCdpFor(ideType) {
43328
43434
  if (!this.components) return null;
43329
43435
  const key = ideType.toLowerCase();
43330
- const mappedKey = this.components.instanceIdMap.get(ideType) || this.components.instanceIdMap.get(key);
43331
- if (mappedKey) {
43332
- const mapped = this.components.cdpManagers.get(mappedKey);
43333
- if (mapped?.isConnected) return mapped;
43334
- }
43335
- const exact = this.components.cdpManagers.get(key);
43336
- if (exact) return exact;
43337
- for (const [k, m] of this.components.cdpManagers.entries()) {
43338
- if (k.startsWith(key + "_") && m.isConnected) return m;
43339
- }
43340
- return null;
43436
+ return findCdpManager(this.components.cdpManagers, key);
43341
43437
  }
43342
43438
  };
43343
43439
  }