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/cli/index.js CHANGED
@@ -1664,7 +1664,11 @@ var init_manager = __esm({
1664
1664
  async attachToAgent(target) {
1665
1665
  if (!this.isConnected) return null;
1666
1666
  for (const [sid, t] of this.agentSessions) {
1667
- if (t.agentType === target.agentType) return sid;
1667
+ if (t.targetId === target.targetId) return sid;
1668
+ if (t.agentType === target.agentType && t.targetId !== target.targetId) {
1669
+ await this.detachAgent(sid).catch(() => {
1670
+ });
1671
+ }
1668
1672
  }
1669
1673
  try {
1670
1674
  const sendFn = this._browserConnected ? this.sendBrowser.bind(this) : this.sendInternal.bind(this);
@@ -1788,6 +1792,20 @@ var init_manager = __esm({
1788
1792
  }
1789
1793
  async getCurrentPageWebviewUrls() {
1790
1794
  if (!this.isConnected) return /* @__PURE__ */ new Set();
1795
+ try {
1796
+ const urls = /* @__PURE__ */ new Set();
1797
+ const { frameTree } = await this.sendInternal("Page.getFrameTree", {}, 5e3);
1798
+ const visit = (node) => {
1799
+ const url2 = node?.frame?.url;
1800
+ if (typeof url2 === "string" && url2.includes("vscode-webview")) {
1801
+ urls.add(url2);
1802
+ }
1803
+ for (const child of node?.childFrames || []) visit(child);
1804
+ };
1805
+ if (frameTree) visit(frameTree);
1806
+ if (urls.size > 0) return urls;
1807
+ } catch {
1808
+ }
1791
1809
  try {
1792
1810
  const raw = await this.evaluate(
1793
1811
  `JSON.stringify(Array.from(document.querySelectorAll('iframe,webview'))
@@ -2973,7 +2991,7 @@ function registerExtensionProviders(providerLoader, manager, ideType) {
2973
2991
  manager.setExtensionProviders(enabledExtProviders);
2974
2992
  }
2975
2993
  async function setupIdeInstance(ctx, opts) {
2976
- const { providerLoader, instanceManager, instanceIdMap } = ctx;
2994
+ const { providerLoader, instanceManager, sessionRegistry } = ctx;
2977
2995
  const { ideType, manager, settings } = opts;
2978
2996
  const managerKey = opts.managerKey || ideType;
2979
2997
  registerExtensionProviders(providerLoader, manager, ideType);
@@ -2989,14 +3007,30 @@ async function setupIdeInstance(ctx, opts) {
2989
3007
  serverConn: ctx.serverConn,
2990
3008
  settings: resolvedSettings
2991
3009
  });
2992
- instanceIdMap.set(ideInstance.getInstanceId(), managerKey);
3010
+ sessionRegistry.register({
3011
+ sessionId: ideInstance.getInstanceId(),
3012
+ parentSessionId: null,
3013
+ providerType: ideType,
3014
+ providerCategory: "ide",
3015
+ transport: "cdp-page",
3016
+ cdpManagerKey: managerKey,
3017
+ instanceKey: `ide:${managerKey}`
3018
+ });
2993
3019
  const extensionProviders = providerLoader.getEnabledByCategory("extension", ideType);
2994
3020
  for (const extProvider of extensionProviders) {
2995
3021
  const extSettings = providerLoader.getSettings(extProvider.type);
2996
3022
  await ideInstance.addExtension(extProvider, extSettings);
2997
- for (const ext of ideInstance.getExtensionInstances()) {
2998
- instanceIdMap.set(ext.getInstanceId(), managerKey);
2999
- }
3023
+ }
3024
+ for (const ext of ideInstance.getExtensionInstances()) {
3025
+ sessionRegistry.register({
3026
+ sessionId: ext.getInstanceId(),
3027
+ parentSessionId: ideInstance.getInstanceId(),
3028
+ providerType: ext.type,
3029
+ providerCategory: "extension",
3030
+ transport: "cdp-webview",
3031
+ cdpManagerKey: managerKey,
3032
+ instanceKey: `ide:${managerKey}`
3033
+ });
3000
3034
  }
3001
3035
  return ideInstance;
3002
3036
  }
@@ -3235,6 +3269,7 @@ var init_initializer = __esm({
3235
3269
  async connectIdePort(port, ide) {
3236
3270
  const { providerLoader, cdpManagers } = this.config;
3237
3271
  const targets = await DaemonCdpManager.listAllTargets(port);
3272
+ await this.pruneStaleManagers(port, ide, targets);
3238
3273
  if (targets.length === 0) {
3239
3274
  if (cdpManagers.has(ide)) return;
3240
3275
  if (!await probeCdpPort(port)) return;
@@ -3287,6 +3322,34 @@ var init_initializer = __esm({
3287
3322
  }
3288
3323
  }
3289
3324
  }
3325
+ async pruneStaleManagers(port, ide, targets) {
3326
+ const trackedTargetIds = new Set(targets.map((target) => target.id));
3327
+ const removals = [];
3328
+ for (const [key, manager] of this.config.cdpManagers.entries()) {
3329
+ if (!(key === ide || key.startsWith(`${ide}_`))) continue;
3330
+ if (manager.getPort() !== port) continue;
3331
+ if (targets.length === 0) {
3332
+ removals.push({ key, manager, reason: "ide_closed" });
3333
+ continue;
3334
+ }
3335
+ if (manager.targetId && !trackedTargetIds.has(manager.targetId)) {
3336
+ removals.push({ key, manager, reason: "target_closed" });
3337
+ continue;
3338
+ }
3339
+ if (key === ide && !manager.targetId && targets.length > 1) {
3340
+ removals.push({ key, manager, reason: "target_rekeyed" });
3341
+ }
3342
+ }
3343
+ for (const { key, manager, reason } of removals) {
3344
+ try {
3345
+ manager.disconnect();
3346
+ } catch {
3347
+ }
3348
+ this.config.cdpManagers.delete(key);
3349
+ LOG.info("CDP", `Removed stale manager: ${key} (${reason})`);
3350
+ await this.config.onDisconnected?.(ide, manager, key, reason);
3351
+ }
3352
+ }
3290
3353
  // ─── Periodic scanning ───
3291
3354
  /**
3292
3355
  * Start periodic scanning for newly opened IDEs.
@@ -3398,112 +3461,191 @@ function isCdpConnected(cdpManagers, key) {
3398
3461
  const m = findCdpManager(cdpManagers, key);
3399
3462
  return m?.isConnected ?? false;
3400
3463
  }
3401
- function buildManagedIdes(ideStates, cdpManagers, opts) {
3402
- const result = [];
3403
- for (const state of ideStates) {
3404
- const cdpConnected = state.cdpConnected ?? isCdpConnected(cdpManagers, state.type);
3405
- result.push({
3406
- ideType: state.type,
3407
- ideVersion: "",
3408
- instanceId: state.instanceId || state.type,
3409
- workspace: state.workspace || null,
3410
- terminals: 0,
3411
- aiAgents: [],
3412
- activeChat: normalizeActiveChatData(state.activeChat),
3413
- chats: [],
3414
- agentStreams: state.extensions.map((ext) => ({
3415
- agentType: ext.type,
3416
- agentName: ext.name,
3417
- extensionId: ext.type,
3418
- status: normalizeManagedStatus(ext.status, { activeModal: ext.activeChat?.activeModal || null }),
3419
- messages: ext.activeChat?.messages || [],
3420
- inputContent: ext.activeChat?.inputContent || "",
3421
- activeModal: ext.activeChat?.activeModal || null
3422
- })),
3423
- cdpConnected,
3424
- currentModel: state.currentModel,
3425
- currentPlan: state.currentPlan,
3426
- currentAutoApprove: state.currentAutoApprove
3427
- });
3428
- }
3429
- if (opts?.detectedIdes) {
3430
- const coveredTypes = new Set(ideStates.map((s15) => s15.type));
3431
- for (const ide of opts.detectedIdes) {
3432
- if (!ide.installed || coveredTypes.has(ide.id)) continue;
3433
- if (!isCdpConnected(cdpManagers, ide.id)) continue;
3434
- result.push({
3435
- ideType: ide.id,
3436
- ideVersion: "",
3437
- instanceId: ide.id,
3438
- workspace: null,
3439
- terminals: 0,
3440
- aiAgents: [],
3441
- activeChat: null,
3442
- chats: [],
3443
- agentStreams: [],
3444
- cdpConnected: true,
3445
- currentModel: void 0,
3446
- currentPlan: void 0
3447
- });
3448
- }
3449
- }
3450
- return result;
3464
+ function buildIdeWorkspaceSession(state, cdpManagers) {
3465
+ const activeChat = normalizeActiveChatData(state.activeChat);
3466
+ const title = activeChat?.title || state.name;
3467
+ return {
3468
+ id: state.instanceId || state.type,
3469
+ parentId: null,
3470
+ providerType: state.type,
3471
+ providerName: state.name,
3472
+ kind: "workspace",
3473
+ transport: "cdp-page",
3474
+ status: normalizeManagedStatus(activeChat?.status || state.status, {
3475
+ activeModal: activeChat?.activeModal || null
3476
+ }),
3477
+ title,
3478
+ workspace: state.workspace || null,
3479
+ activeChat,
3480
+ capabilities: IDE_SESSION_CAPABILITIES,
3481
+ cdpConnected: state.cdpConnected ?? isCdpConnected(cdpManagers, state.type),
3482
+ currentModel: state.currentModel,
3483
+ currentPlan: state.currentPlan,
3484
+ currentAutoApprove: state.currentAutoApprove,
3485
+ errorMessage: state.errorMessage,
3486
+ errorReason: state.errorReason
3487
+ };
3451
3488
  }
3452
- function buildManagedClis(cliStates) {
3453
- return cliStates.map((s15) => ({
3454
- id: s15.instanceId,
3455
- instanceId: s15.instanceId,
3456
- cliType: s15.type,
3457
- cliName: s15.name,
3458
- status: normalizeManagedStatus(s15.status, { activeModal: s15.activeChat?.activeModal || null }),
3459
- mode: "terminal",
3460
- workspace: s15.workspace || "",
3461
- activeChat: normalizeActiveChatData(s15.activeChat)
3462
- }));
3489
+ function buildExtensionAgentSession(parent, ext) {
3490
+ const activeChat = normalizeActiveChatData(ext.activeChat);
3491
+ return {
3492
+ id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
3493
+ parentId: parent.instanceId || parent.type,
3494
+ providerType: ext.type,
3495
+ providerName: ext.name,
3496
+ kind: "agent",
3497
+ transport: "cdp-webview",
3498
+ status: normalizeManagedStatus(activeChat?.status || ext.status, {
3499
+ activeModal: activeChat?.activeModal || null
3500
+ }),
3501
+ title: activeChat?.title || ext.name,
3502
+ workspace: parent.workspace || null,
3503
+ activeChat,
3504
+ capabilities: EXTENSION_SESSION_CAPABILITIES,
3505
+ currentModel: ext.currentModel,
3506
+ currentPlan: ext.currentPlan,
3507
+ errorMessage: ext.errorMessage,
3508
+ errorReason: ext.errorReason
3509
+ };
3463
3510
  }
3464
- function buildManagedAcps(acpStates) {
3465
- return acpStates.map((s15) => ({
3466
- id: s15.instanceId,
3467
- acpType: s15.type,
3468
- acpName: s15.name,
3469
- status: normalizeManagedStatus(s15.status, { activeModal: s15.activeChat?.activeModal || null }),
3470
- mode: "chat",
3471
- workspace: s15.workspace || "",
3472
- activeChat: normalizeActiveChatData(s15.activeChat),
3473
- currentModel: s15.currentModel,
3474
- currentPlan: s15.currentPlan,
3475
- acpConfigOptions: s15.acpConfigOptions,
3476
- acpModes: s15.acpModes,
3477
- errorMessage: s15.errorMessage,
3478
- errorReason: s15.errorReason
3479
- }));
3511
+ function buildCliSession(state) {
3512
+ const activeChat = normalizeActiveChatData(state.activeChat);
3513
+ return {
3514
+ id: state.instanceId,
3515
+ parentId: null,
3516
+ providerType: state.type,
3517
+ providerName: state.name,
3518
+ kind: "agent",
3519
+ transport: "pty",
3520
+ status: normalizeManagedStatus(activeChat?.status || state.status, {
3521
+ activeModal: activeChat?.activeModal || null
3522
+ }),
3523
+ title: activeChat?.title || state.name,
3524
+ workspace: state.workspace || null,
3525
+ activeChat,
3526
+ capabilities: PTY_SESSION_CAPABILITIES,
3527
+ errorMessage: state.errorMessage,
3528
+ errorReason: state.errorReason
3529
+ };
3530
+ }
3531
+ function buildAcpSession(state) {
3532
+ const activeChat = normalizeActiveChatData(state.activeChat);
3533
+ return {
3534
+ id: state.instanceId,
3535
+ parentId: null,
3536
+ providerType: state.type,
3537
+ providerName: state.name,
3538
+ kind: "agent",
3539
+ transport: "acp",
3540
+ status: normalizeManagedStatus(activeChat?.status || state.status, {
3541
+ activeModal: activeChat?.activeModal || null
3542
+ }),
3543
+ title: activeChat?.title || state.name,
3544
+ workspace: state.workspace || null,
3545
+ activeChat,
3546
+ capabilities: ACP_SESSION_CAPABILITIES,
3547
+ currentModel: state.currentModel,
3548
+ currentPlan: state.currentPlan,
3549
+ acpConfigOptions: state.acpConfigOptions,
3550
+ acpModes: state.acpModes,
3551
+ errorMessage: state.errorMessage,
3552
+ errorReason: state.errorReason
3553
+ };
3480
3554
  }
3481
- function buildAllManagedEntries(allStates, cdpManagers, opts) {
3555
+ function buildSessionEntries(allStates, cdpManagers) {
3556
+ const sessions = [];
3482
3557
  const ideStates = allStates.filter((s15) => s15.category === "ide");
3483
3558
  const cliStates = allStates.filter((s15) => s15.category === "cli");
3484
3559
  const acpStates = allStates.filter((s15) => s15.category === "acp");
3485
- return {
3486
- managedIdes: buildManagedIdes(ideStates, cdpManagers, opts),
3487
- managedClis: buildManagedClis(cliStates),
3488
- managedAcps: buildManagedAcps(acpStates)
3489
- };
3560
+ for (const state of ideStates) {
3561
+ sessions.push(buildIdeWorkspaceSession(state, cdpManagers));
3562
+ for (const ext of state.extensions) {
3563
+ sessions.push(buildExtensionAgentSession(state, ext));
3564
+ }
3565
+ }
3566
+ for (const state of cliStates) {
3567
+ sessions.push(buildCliSession(state));
3568
+ }
3569
+ for (const state of acpStates) {
3570
+ sessions.push(buildAcpSession(state));
3571
+ }
3572
+ return sessions;
3490
3573
  }
3574
+ var IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES;
3491
3575
  var init_builders = __esm({
3492
3576
  "../../oss/packages/daemon-core/src/status/builders.ts"() {
3493
3577
  "use strict";
3494
3578
  init_normalize();
3579
+ IDE_SESSION_CAPABILITIES = [
3580
+ "read_chat",
3581
+ "send_message",
3582
+ "new_session",
3583
+ "list_sessions",
3584
+ "switch_session",
3585
+ "resolve_action",
3586
+ "change_model",
3587
+ "set_mode",
3588
+ "set_thought_level"
3589
+ ];
3590
+ EXTENSION_SESSION_CAPABILITIES = [
3591
+ "read_chat",
3592
+ "send_message",
3593
+ "new_session",
3594
+ "list_sessions",
3595
+ "switch_session",
3596
+ "resolve_action",
3597
+ "change_model",
3598
+ "set_mode"
3599
+ ];
3600
+ PTY_SESSION_CAPABILITIES = [
3601
+ "read_chat",
3602
+ "send_message",
3603
+ "resolve_action",
3604
+ "terminal_io",
3605
+ "resize_terminal"
3606
+ ];
3607
+ ACP_SESSION_CAPABILITIES = [
3608
+ "read_chat",
3609
+ "send_message",
3610
+ "new_session",
3611
+ "resolve_action",
3612
+ "change_model",
3613
+ "set_mode",
3614
+ "set_thought_level"
3615
+ ];
3495
3616
  }
3496
3617
  });
3497
3618
 
3498
3619
  // ../../oss/packages/daemon-core/src/commands/chat-commands.ts
3620
+ function getCurrentProviderType(h, fallback = "") {
3621
+ return h.currentSession?.providerType || h.currentProviderType || fallback;
3622
+ }
3623
+ function getCurrentManagerKey(h) {
3624
+ return h.currentSession?.cdpManagerKey || h.currentManagerKey || "";
3625
+ }
3499
3626
  function getTargetedCliAdapter(h, args, providerType) {
3500
- return h.getCliAdapter(args?._targetInstance || h.currentIdeType || providerType);
3627
+ return h.getCliAdapter(args?.targetSessionId || providerType || h.currentSession?.providerType || h.currentManagerKey);
3628
+ }
3629
+ function buildRecentSendKey(h, args, provider, text) {
3630
+ const target = args?.targetSessionId || args?.agentType || h.currentSession?.providerType || h.currentProviderType || h.currentManagerKey || "unknown";
3631
+ return `${provider?.category || "unknown"}:${target}:${text.trim()}`;
3632
+ }
3633
+ function isRecentDuplicateSend(key) {
3634
+ const now = Date.now();
3635
+ for (const [candidate, ts3] of recentSendByTarget.entries()) {
3636
+ if (now - ts3 > RECENT_SEND_WINDOW_MS) recentSendByTarget.delete(candidate);
3637
+ }
3638
+ const previous = recentSendByTarget.get(key);
3639
+ if (previous && now - previous <= RECENT_SEND_WINDOW_MS) return true;
3640
+ recentSendByTarget.set(key, now);
3641
+ return false;
3501
3642
  }
3502
3643
  async function handleChatHistory(h, args) {
3503
- const { agentType, offset, limit, instanceId } = args;
3644
+ const { agentType, offset, limit } = args;
3645
+ const instanceId = args?.targetSessionId;
3504
3646
  try {
3505
3647
  const provider = h.getProvider(agentType);
3506
- const agentStr = provider?.type || agentType || h.currentIdeType || "";
3648
+ const agentStr = provider?.type || agentType || getCurrentProviderType(h);
3507
3649
  const result = readChatHistory(agentStr, offset || 0, limit || 30, instanceId);
3508
3650
  return { success: true, ...result, agent: agentStr };
3509
3651
  } catch (e) {
@@ -3547,7 +3689,7 @@ async function handleReadChat(h, args) {
3547
3689
  provider.type || "unknown_extension",
3548
3690
  parsed.messages || [],
3549
3691
  parsed.title,
3550
- args?.instanceId
3692
+ args?.targetSessionId
3551
3693
  );
3552
3694
  return { success: true, ...parsed };
3553
3695
  }
@@ -3557,15 +3699,18 @@ async function handleReadChat(h, args) {
3557
3699
  }
3558
3700
  if (h.agentStream) {
3559
3701
  const cdp2 = h.getCdp();
3560
- if (cdp2 && h.currentIdeType) {
3561
- const streams = await h.agentStream.collectAgentStreams(cdp2, h.currentIdeType);
3562
- const stream = streams.find((s15) => s15.agentType === provider.type);
3702
+ const parentSessionId = h.currentSession?.parentSessionId;
3703
+ if (cdp2 && parentSessionId) {
3704
+ const stream = await h.agentStream.collectActiveSession(cdp2, parentSessionId);
3705
+ if (stream?.agentType !== provider.type) {
3706
+ return { success: true, messages: [], status: "idle" };
3707
+ }
3563
3708
  if (stream) {
3564
3709
  h.historyWriter.appendNewMessages(
3565
3710
  stream.agentType,
3566
3711
  stream.messages || [],
3567
3712
  void 0,
3568
- args?.instanceId
3713
+ args?.targetSessionId
3569
3714
  );
3570
3715
  return { success: true, messages: stream.messages || [], status: stream.status, agentType: stream.agentType };
3571
3716
  }
@@ -3592,10 +3737,10 @@ async function handleReadChat(h, args) {
3592
3737
  if (parsed && typeof parsed === "object") {
3593
3738
  _log(`Webview OK: ${parsed.messages?.length || 0} msgs`);
3594
3739
  h.historyWriter.appendNewMessages(
3595
- provider?.type || h.currentIdeType || "unknown_webview",
3740
+ provider?.type || getCurrentProviderType(h, "unknown_webview"),
3596
3741
  parsed.messages || [],
3597
3742
  parsed.title,
3598
- args?.instanceId
3743
+ args?.targetSessionId
3599
3744
  );
3600
3745
  return { success: true, ...parsed };
3601
3746
  }
@@ -3619,10 +3764,10 @@ async function handleReadChat(h, args) {
3619
3764
  if (parsed && typeof parsed === "object" && parsed.messages?.length > 0) {
3620
3765
  _log(`OK: ${parsed.messages?.length} msgs`);
3621
3766
  h.historyWriter.appendNewMessages(
3622
- provider?.type || h.currentIdeType || "unknown_ide",
3767
+ provider?.type || getCurrentProviderType(h, "unknown_ide"),
3623
3768
  parsed.messages || [],
3624
3769
  parsed.title,
3625
- args?.instanceId
3770
+ args?.targetSessionId
3626
3771
  );
3627
3772
  return { success: true, ...parsed };
3628
3773
  }
@@ -3637,16 +3782,21 @@ async function handleSendChat(h, args) {
3637
3782
  if (!text) return { success: false, error: "text required" };
3638
3783
  const _log = (msg) => LOG.debug("Command", `[send_chat] ${msg}`);
3639
3784
  const provider = h.getProvider(args?.agentType);
3785
+ const dedupeKey = buildRecentSendKey(h, args, provider, text);
3640
3786
  const _logSendSuccess = (method, targetAgent) => {
3641
3787
  h.historyWriter.appendNewMessages(
3642
- targetAgent || provider?.type || h.currentIdeType || "unknown_agent",
3788
+ targetAgent || provider?.type || getCurrentProviderType(h, "unknown_agent"),
3643
3789
  [{ role: "user", content: text, receivedAt: Date.now() }],
3644
3790
  void 0,
3645
3791
  // title
3646
- args?.instanceId
3792
+ args?.targetSessionId
3647
3793
  );
3648
3794
  return { success: true, sent: true, method, targetAgent };
3649
3795
  };
3796
+ if (isRecentDuplicateSend(dedupeKey)) {
3797
+ _log(`Suppressed duplicate send for ${dedupeKey}`);
3798
+ return { success: true, sent: false, deduplicated: true };
3799
+ }
3650
3800
  if (provider?.category === "cli" || provider?.category === "acp") {
3651
3801
  const adapter = getTargetedCliAdapter(h, args, provider.type);
3652
3802
  if (adapter) {
@@ -3682,8 +3832,9 @@ async function handleSendChat(h, args) {
3682
3832
  } catch (e) {
3683
3833
  _log(`Extension script error: ${e.message}`);
3684
3834
  }
3685
- if (h.agentStream && h.getCdp() && h.currentIdeType) {
3686
- const ok = await h.agentStream.sendToAgent(h.getCdp(), h.currentIdeType, provider.type, text, h.currentIdeType);
3835
+ const extensionSessionId = h.currentSession?.sessionId;
3836
+ if (h.agentStream && h.getCdp() && extensionSessionId) {
3837
+ const ok = await h.agentStream.sendToSession(h.getCdp(), extensionSessionId, text);
3687
3838
  if (ok) {
3688
3839
  _log(`AgentStreamManager sent OK`);
3689
3840
  return _logSendSuccess("agent-stream");
@@ -3693,45 +3844,11 @@ async function handleSendChat(h, args) {
3693
3844
  }
3694
3845
  const targetCdp = h.getCdp();
3695
3846
  if (!targetCdp?.isConnected) {
3696
- _log(`No CDP for ${h.currentIdeType}`);
3697
- return { success: false, error: `CDP for ${h.currentIdeType || "unknown"} not connected` };
3698
- }
3699
- _log(`Targeting IDE: ${h.currentIdeType}`);
3700
- if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
3701
- try {
3702
- const webviewScript = provider.scripts.webviewSendMessage(text);
3703
- if (webviewScript && targetCdp.evaluateInWebviewFrame) {
3704
- const matchText = provider.webviewMatchText;
3705
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
3706
- const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
3707
- let wvParsed = wvResult;
3708
- if (typeof wvResult === "string") {
3709
- try {
3710
- wvParsed = JSON.parse(wvResult);
3711
- } catch {
3712
- }
3713
- }
3714
- if (wvParsed?.sent) {
3715
- _log(`webviewSendMessage (priority) OK`);
3716
- return _logSendSuccess("webview-script-priority");
3717
- }
3718
- _log(`webviewSendMessage (priority) did not confirm sent, falling through`);
3719
- }
3720
- } catch (e) {
3721
- _log(`webviewSendMessage (priority) failed: ${e.message}, falling through`);
3722
- }
3723
- }
3724
- if (provider?.inputMethod === "cdp-type-and-send" && provider.inputSelector) {
3725
- try {
3726
- const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
3727
- if (sent) {
3728
- _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
3729
- return _logSendSuccess("typeAndSend-provider");
3730
- }
3731
- } catch (e) {
3732
- _log(`typeAndSend(provider) failed: ${e.message}`);
3733
- }
3847
+ const managerKey = getCurrentManagerKey(h);
3848
+ _log(`No CDP for ${managerKey}`);
3849
+ return { success: false, error: `CDP for ${managerKey || "unknown"} not connected` };
3734
3850
  }
3851
+ _log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
3735
3852
  const sendScript = h.getProviderScript("sendMessage", { MESSAGE: text });
3736
3853
  if (sendScript) {
3737
3854
  try {
@@ -3758,7 +3875,30 @@ async function handleSendChat(h, args) {
3758
3875
  _log(`typeAndSend(script.selector) failed: ${e.message}`);
3759
3876
  }
3760
3877
  }
3761
- if (parsed?.needsTypeAndSend && provider?.scripts?.webviewSendMessage) {
3878
+ if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
3879
+ try {
3880
+ const { x, y } = parsed.clickCoords;
3881
+ const sent = await targetCdp.typeAndSendAt(x, y, text);
3882
+ if (sent) {
3883
+ _log(`typeAndSendAt(${x},${y}) success`);
3884
+ return _logSendSuccess("typeAndSendAt-script");
3885
+ }
3886
+ } catch (e) {
3887
+ _log(`typeAndSendAt failed: ${e.message}`);
3888
+ }
3889
+ }
3890
+ if (parsed?.needsTypeAndSend && provider?.inputMethod === "cdp-type-and-send" && provider.inputSelector) {
3891
+ try {
3892
+ const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
3893
+ if (sent) {
3894
+ _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
3895
+ return _logSendSuccess("typeAndSend-provider");
3896
+ }
3897
+ } catch (e) {
3898
+ _log(`typeAndSend(provider) failed: ${e.message}`);
3899
+ }
3900
+ }
3901
+ if (parsed?.needsTypeAndSend && provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
3762
3902
  try {
3763
3903
  const webviewScript = provider.scripts.webviewSendMessage(text);
3764
3904
  if (webviewScript && targetCdp.evaluateInWebviewFrame) {
@@ -3781,20 +3921,44 @@ async function handleSendChat(h, args) {
3781
3921
  _log(`webviewSendMessage failed: ${e.message}`);
3782
3922
  }
3783
3923
  }
3784
- if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
3785
- try {
3786
- const { x, y } = parsed.clickCoords;
3787
- const sent = await targetCdp.typeAndSendAt(x, y, text);
3788
- if (sent) {
3789
- _log(`typeAndSendAt(${x},${y}) success`);
3790
- return _logSendSuccess("typeAndSendAt-script");
3924
+ return { success: false, error: parsed?.error || "Provider sendMessage did not confirm send" };
3925
+ } catch (e) {
3926
+ _log(`sendMessage script failed: ${e.message}`);
3927
+ return { success: false, error: `Provider sendMessage failed: ${e.message}` };
3928
+ }
3929
+ }
3930
+ if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
3931
+ try {
3932
+ const webviewScript = provider.scripts.webviewSendMessage(text);
3933
+ if (webviewScript && targetCdp.evaluateInWebviewFrame) {
3934
+ const matchText = provider.webviewMatchText;
3935
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
3936
+ const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
3937
+ let wvParsed = wvResult;
3938
+ if (typeof wvResult === "string") {
3939
+ try {
3940
+ wvParsed = JSON.parse(wvResult);
3941
+ } catch {
3791
3942
  }
3792
- } catch (e) {
3793
- _log(`typeAndSendAt failed: ${e.message}`);
3943
+ }
3944
+ if (wvParsed?.sent) {
3945
+ _log(`webviewSendMessage OK`);
3946
+ return _logSendSuccess("webview-script");
3794
3947
  }
3795
3948
  }
3796
3949
  } catch (e) {
3797
- _log(`sendMessage script failed: ${e.message}`);
3950
+ _log(`webviewSendMessage failed: ${e.message}`);
3951
+ }
3952
+ }
3953
+ if (provider?.inputMethod === "cdp-type-and-send" && provider.inputSelector) {
3954
+ try {
3955
+ const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
3956
+ if (sent) {
3957
+ _log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
3958
+ return _logSendSuccess("typeAndSend-provider");
3959
+ }
3960
+ } catch (e) {
3961
+ _log(`typeAndSend(provider) failed: ${e.message}`);
3798
3962
  }
3799
3963
  }
3800
3964
  _log("All methods failed");
@@ -3802,9 +3966,9 @@ async function handleSendChat(h, args) {
3802
3966
  }
3803
3967
  async function handleListChats(h, args) {
3804
3968
  const provider = h.getProvider(args?.agentType);
3805
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
3969
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
3806
3970
  try {
3807
- const chats = await h.agentStream.listAgentChats(h.getCdp(), h.currentIdeType, provider.type);
3971
+ const chats = await h.agentStream.listSessionChats(h.getCdp(), h.currentSession.sessionId);
3808
3972
  LOG.info("Command", `[list_chats] Extension: ${chats.length} chats`);
3809
3973
  return { success: true, chats };
3810
3974
  } catch (e) {
@@ -3863,8 +4027,8 @@ async function handleNewChat(h, args) {
3863
4027
  }
3864
4028
  return { success: false, error: "new_chat not supported by this CLI provider" };
3865
4029
  }
3866
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
3867
- const ok = await h.agentStream.newAgentSession(h.getCdp(), h.currentIdeType, provider.type, h.currentIdeType);
4030
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
4031
+ const ok = await h.agentStream.newSession(h.getCdp(), h.currentSession.sessionId);
3868
4032
  return { success: ok };
3869
4033
  }
3870
4034
  try {
@@ -3888,15 +4052,15 @@ async function handleNewChat(h, args) {
3888
4052
  }
3889
4053
  async function handleSwitchChat(h, args) {
3890
4054
  const provider = h.getProvider(args?.agentType);
3891
- const ideType = h.currentIdeType;
4055
+ const managerKey = getCurrentManagerKey(h);
3892
4056
  const sessionId = args?.sessionId || args?.id || args?.chatId;
3893
4057
  if (!sessionId) return { success: false, error: "sessionId required" };
3894
- LOG.info("Command", `[switch_chat] sessionId=${sessionId}, ideType=${ideType}`);
3895
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
3896
- const ok = await h.agentStream.switchAgentSession(h.getCdp(), h.currentIdeType, provider.type, sessionId);
4058
+ LOG.info("Command", `[switch_chat] sessionId=${sessionId}, manager=${managerKey}`);
4059
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
4060
+ const ok = await h.agentStream.switchConversation(h.getCdp(), h.currentSession.sessionId, sessionId);
3897
4061
  return { success: ok, result: ok ? "switched" : "failed" };
3898
4062
  }
3899
- const cdp = h.getCdp(ideType);
4063
+ const cdp = h.getCdp(managerKey);
3900
4064
  if (!cdp?.isConnected) return { success: false, error: "CDP not connected" };
3901
4065
  try {
3902
4066
  const webviewScript = h.getProviderScript("webviewSwitchSession", { SESSION_ID: JSON.stringify(sessionId) });
@@ -4038,7 +4202,7 @@ async function handleSetMode(h, args) {
4038
4202
  async function handleChangeModel(h, args) {
4039
4203
  const provider = h.getProvider(args?.agentType);
4040
4204
  const model = args?.model;
4041
- LOG.info("Command", `[change_model] model=${model} provider=${provider?.type} category=${provider?.category} ideType=${h.currentIdeType} providerType=${h.currentProviderType}`);
4205
+ LOG.info("Command", `[change_model] model=${model} provider=${provider?.type} category=${provider?.category} manager=${getCurrentManagerKey(h)} providerType=${getCurrentProviderType(h)}`);
4042
4206
  if (provider?.category === "acp") {
4043
4207
  const adapter = getTargetedCliAdapter(h, args, provider.type);
4044
4208
  LOG.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
@@ -4159,14 +4323,8 @@ async function handleResolveAction(h, args) {
4159
4323
  LOG.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
4160
4324
  return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
4161
4325
  }
4162
- if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentIdeType) {
4163
- const ok = await h.agentStream.resolveAgentAction(
4164
- h.getCdp(),
4165
- h.currentIdeType,
4166
- provider.type,
4167
- action,
4168
- h.currentIdeType
4169
- );
4326
+ if (provider?.category === "extension" && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
4327
+ const ok = await h.agentStream.resolveSessionAction(h.getCdp(), h.currentSession.sessionId, action);
4170
4328
  return { success: ok };
4171
4329
  }
4172
4330
  if (provider?.scripts?.webviewResolveAction || provider?.scripts?.webview_resolve_action) {
@@ -4244,11 +4402,14 @@ async function handleResolveAction(h, args) {
4244
4402
  }
4245
4403
  return { success: false, error: "resolveAction script not available for this provider" };
4246
4404
  }
4405
+ var RECENT_SEND_WINDOW_MS, recentSendByTarget;
4247
4406
  var init_chat_commands = __esm({
4248
4407
  "../../oss/packages/daemon-core/src/commands/chat-commands.ts"() {
4249
4408
  "use strict";
4250
4409
  init_chat_history();
4251
4410
  init_logger();
4411
+ RECENT_SEND_WINDOW_MS = 1200;
4412
+ recentSendByTarget = /* @__PURE__ */ new Map();
4252
4413
  }
4253
4414
  });
4254
4415
 
@@ -4537,157 +4698,37 @@ var init_cdp_commands = __esm({
4537
4698
  });
4538
4699
 
4539
4700
  // ../../oss/packages/daemon-core/src/commands/stream-commands.ts
4540
- async function handleAgentStreamSwitch(h, args) {
4541
- if (!h.agentStream || !h.getCdp() || !h.currentIdeType) return { success: false, error: "AgentStream or CDP not available" };
4542
- const agentType = args?.agentType || args?.agent || null;
4543
- await h.agentStream.switchActiveAgent(h.getCdp(), h.currentIdeType, agentType);
4544
- return { success: true, activeAgent: agentType };
4545
- }
4546
- async function handleAgentStreamRead(h, args) {
4547
- if (!h.agentStream || !h.getCdp() || !h.currentIdeType) return { success: false, error: "AgentStream or CDP not available" };
4548
- const streams = await h.agentStream.collectAgentStreams(h.getCdp(), h.currentIdeType);
4549
- return { success: true, streams };
4550
- }
4551
- async function handleAgentStreamSend(h, args) {
4552
- const agentType = args?.agentType || args?.agent;
4553
- const text = args?.text || args?.message;
4554
- if (!text) return { success: false, error: "text required" };
4555
- if (agentType && h.ctx.adapters) {
4556
- for (const [key, adapter] of h.ctx.adapters.entries()) {
4557
- if (adapter.cliType === agentType || key.includes(agentType)) {
4558
- LOG.info("Command", `[agent_stream_send] Routing to CLI adapter: ${adapter.cliType}`);
4559
- try {
4560
- await adapter.sendMessage(text);
4561
- return { success: true, sent: true, targetAgent: adapter.cliType };
4562
- } catch (e) {
4563
- LOG.info("Command", `[agent_stream_send] CLI adapter failed: ${e.message}`);
4564
- return { success: false, error: `CLI send failed: ${e.message}` };
4565
- }
4566
- }
4567
- }
4568
- }
4569
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4570
- const resolvedAgent = agentType || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4571
- if (!resolvedAgent) return { success: false, error: "agentType required" };
4572
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4573
- const ok = await h.agentStream.sendToAgent(h.getCdp(), h.currentIdeType, resolvedAgent, text, h.currentIdeType);
4574
- return { success: ok };
4575
- }
4576
- async function handleAgentStreamResolve(h, args) {
4577
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4578
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4579
- const action = args?.action || "approve";
4580
- if (!agentType) return { success: false, error: "agentType required" };
4581
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4582
- const ok = await h.agentStream.resolveAgentAction(h.getCdp(), h.currentIdeType, agentType, action, h.currentIdeType);
4583
- return { success: ok };
4584
- }
4585
- async function handleAgentStreamNew(h, args) {
4586
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4587
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4588
- if (!agentType) return { success: false, error: "agentType required" };
4589
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4590
- const ok = await h.agentStream.newAgentSession(h.getCdp(), h.currentIdeType, agentType, h.currentIdeType);
4591
- return { success: ok };
4592
- }
4593
- async function handleAgentStreamListChats(h, args) {
4594
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4595
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4596
- if (!agentType) return { success: false, error: "agentType required" };
4597
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4598
- const chats = await h.agentStream.listAgentChats(h.getCdp(), h.currentIdeType, agentType);
4599
- return { success: true, chats };
4600
- }
4601
- async function handleAgentStreamSwitchSession(h, args) {
4602
- if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4603
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4604
- const sessionId = args?.sessionId || args?.id;
4605
- if (!agentType || !sessionId) return { success: false, error: "agentType and sessionId required" };
4606
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4607
- const ok = await h.agentStream.switchAgentSession(h.getCdp(), h.currentIdeType, agentType, sessionId);
4608
- return { success: ok };
4609
- }
4610
- async function handleAgentStreamFocus(h, args) {
4701
+ async function handleFocusSession(h, args) {
4611
4702
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4612
- const agentType = args?.agentType || args?.agent || (h.currentIdeType ? h.agentStream.getActiveAgentType(h.currentIdeType) : null);
4613
- if (!agentType) return { success: false, error: "agentType required" };
4614
- await h.agentStream.ensureAgentPanelOpen(agentType, h.currentIdeType);
4615
- if (!h.currentIdeType) return { success: false, error: "ideType required" };
4616
- const ok = await h.agentStream.focusAgentEditor(h.getCdp(), h.currentIdeType, agentType);
4703
+ const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
4704
+ if (!sessionId) return { success: false, error: "targetSessionId required" };
4705
+ const ok = await h.agentStream.focusSession(h.getCdp(), sessionId);
4617
4706
  return { success: ok };
4618
4707
  }
4619
4708
  function handlePtyInput(h, args) {
4620
- const { cliType, data } = args || {};
4709
+ const { cliType, data, targetSessionId } = args || {};
4621
4710
  if (!data) return { success: false, error: "data required" };
4622
- if (h.ctx.adapters) {
4623
- const targetCli = cliType || "";
4624
- if (!targetCli && h.ctx.adapters.size > 0) {
4625
- const first = h.ctx.adapters.values().next().value;
4626
- if (first && typeof first.writeRaw === "function") {
4627
- first.writeRaw(data);
4628
- return { success: true };
4629
- }
4630
- }
4631
- const directAdapter = h.ctx.adapters.get(targetCli);
4632
- if (directAdapter && typeof directAdapter.writeRaw === "function") {
4633
- directAdapter.writeRaw(data);
4634
- return { success: true };
4635
- }
4636
- for (const [, adapter] of h.ctx.adapters) {
4637
- if (adapter.cliType === targetCli && typeof adapter.writeRaw === "function") {
4638
- adapter.writeRaw(data);
4639
- return { success: true };
4640
- }
4641
- }
4642
- for (const [key, adapter] of h.ctx.adapters) {
4643
- if ((key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.writeRaw === "function") {
4644
- adapter.writeRaw(data);
4645
- return { success: true };
4646
- }
4647
- }
4711
+ const adapter = h.getCliAdapter(targetSessionId || cliType);
4712
+ if (!adapter || typeof adapter.writeRaw !== "function") {
4713
+ return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
4648
4714
  }
4649
- return { success: false, error: `CLI adapter not found: ${cliType}` };
4715
+ adapter.writeRaw(data);
4716
+ return { success: true };
4650
4717
  }
4651
4718
  function handlePtyResize(h, args) {
4652
- const { cliType, cols, rows, force } = args || {};
4719
+ const { cliType, cols, rows, force, targetSessionId } = args || {};
4653
4720
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
4654
- if (h.ctx.adapters) {
4655
- const targetCli = cliType || "";
4656
- if (!targetCli && h.ctx.adapters.size > 0) {
4657
- const first = h.ctx.adapters.values().next().value;
4658
- if (first && typeof first.resize === "function") {
4659
- if (force) {
4660
- first.resize(cols - 1, rows);
4661
- setTimeout(() => first.resize(cols, rows), 50);
4662
- } else {
4663
- first.resize(cols, rows);
4664
- }
4665
- return { success: true };
4666
- }
4667
- }
4668
- const directAdapter = h.ctx.adapters.get(targetCli);
4669
- if (directAdapter && typeof directAdapter.resize === "function") {
4670
- if (force) {
4671
- directAdapter.resize(cols - 1, rows);
4672
- setTimeout(() => directAdapter.resize(cols, rows), 50);
4673
- } else {
4674
- directAdapter.resize(cols, rows);
4675
- }
4676
- return { success: true };
4677
- }
4678
- for (const [key, adapter] of h.ctx.adapters) {
4679
- if ((adapter.cliType === targetCli || key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.resize === "function") {
4680
- if (force) {
4681
- adapter.resize(cols - 1, rows);
4682
- setTimeout(() => adapter.resize(cols, rows), 50);
4683
- } else {
4684
- adapter.resize(cols, rows);
4685
- }
4686
- return { success: true };
4687
- }
4688
- }
4721
+ const adapter = h.getCliAdapter(targetSessionId || cliType);
4722
+ if (!adapter || typeof adapter.resize !== "function") {
4723
+ return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
4724
+ }
4725
+ if (force) {
4726
+ adapter.resize(cols - 1, rows);
4727
+ setTimeout(() => adapter.resize(cols, rows), 50);
4728
+ } else {
4729
+ adapter.resize(cols, rows);
4689
4730
  }
4690
- return { success: false, error: `CLI adapter not found: ${cliType}` };
4731
+ return { success: true };
4691
4732
  }
4692
4733
  function handleGetProviderSettings(h, args) {
4693
4734
  const loader = h.ctx.providerLoader;
@@ -4723,7 +4764,7 @@ function handleSetProviderSetting(h, args) {
4723
4764
  }
4724
4765
  async function handleExtensionScript(h, args, scriptName) {
4725
4766
  const { agentType, ideType } = args || {};
4726
- LOG.info("Command", `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} _currentIdeType=${h.currentIdeType}`);
4767
+ LOG.info("Command", `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} session=${h.currentSession?.sessionId || ""}`);
4727
4768
  if (!agentType) return { success: false, error: "agentType is required" };
4728
4769
  const loader = h.ctx.providerLoader;
4729
4770
  if (!loader) return { success: false, error: "ProviderLoader not initialized" };
@@ -4744,21 +4785,22 @@ async function handleExtensionScript(h, args, scriptName) {
4744
4785
  }
4745
4786
  const scriptCode = scriptFn(normalizedArgs);
4746
4787
  if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
4747
- const cdpKey = provider.category === "ide" ? h.currentIdeType || agentType : h.currentIdeType || ideType;
4788
+ const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || agentType : h.currentSession?.cdpManagerKey || h.currentManagerKey || ideType;
4748
4789
  LOG.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
4749
4790
  const cdp = h.getCdp(cdpKey);
4750
4791
  if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
4751
4792
  try {
4752
4793
  let result;
4753
4794
  if (provider.category === "extension") {
4754
- const sessions = cdp.getAgentSessions();
4755
- let targetSessionId = null;
4756
- for (const [sessionId, target] of sessions) {
4757
- if (target.agentType === agentType) {
4758
- targetSessionId = sessionId;
4759
- break;
4760
- }
4761
- }
4795
+ const runtimeSessionId = h.currentSession?.sessionId || args?.targetSessionId;
4796
+ if (!runtimeSessionId) return { success: false, error: `No target session found for ${agentType}` };
4797
+ const parentSessionId = h.currentSession?.parentSessionId;
4798
+ if (parentSessionId) {
4799
+ await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
4800
+ await h.agentStream?.syncActiveSession(cdp, parentSessionId);
4801
+ }
4802
+ const managed = runtimeSessionId ? h.agentStream?.getManagedSession(runtimeSessionId) : null;
4803
+ const targetSessionId = managed?.cdpSessionId || null;
4762
4804
  const IDE_LEVEL_SCRIPTS = ["listModes", "setMode", "listModels", "setModel"];
4763
4805
  if (IDE_LEVEL_SCRIPTS.includes(scriptName)) {
4764
4806
  if (targetSessionId) {
@@ -4829,7 +4871,7 @@ function handleGetIdeExtensions(h, args) {
4829
4871
  enabled: config2.ideSettings?.[ide]?.extensions?.[p.type]?.enabled === true
4830
4872
  }));
4831
4873
  }
4832
- return { success: true, ides: result };
4874
+ return { success: true, ideExtensions: result };
4833
4875
  }
4834
4876
  function handleSetIdeExtension(h, args) {
4835
4877
  const { ideType, extensionType, enabled } = args || {};
@@ -4968,10 +5010,8 @@ var init_handler = __esm({
4968
5010
  _agentStream = null;
4969
5011
  domHandlers;
4970
5012
  _historyWriter;
4971
- /** Current IDE type extracted from command args (per-request) */
4972
- _currentIdeType;
4973
- /** Current provider type — agentType priority, ideType use */
4974
- _currentProviderType;
5013
+ /** Current request route context */
5014
+ _currentRoute = {};
4975
5015
  constructor(ctx) {
4976
5016
  this._ctx = ctx;
4977
5017
  this.domHandlers = new CdpDomHandlers((ideType) => this.getCdp(ideType));
@@ -4987,20 +5027,25 @@ var init_handler = __esm({
4987
5027
  get historyWriter() {
4988
5028
  return this._historyWriter;
4989
5029
  }
5030
+ get currentManagerKey() {
5031
+ return this._currentRoute.managerKey;
5032
+ }
4990
5033
  get currentIdeType() {
4991
- return this._currentIdeType;
5034
+ return this._currentRoute.managerKey;
4992
5035
  }
4993
5036
  get currentProviderType() {
4994
- return this._currentProviderType;
5037
+ return this._currentRoute.providerType;
5038
+ }
5039
+ get currentSession() {
5040
+ return this._currentRoute.session;
4995
5041
  }
4996
- /** Get CDP manager for a specific ideType or managerKey.
4997
- * Supports exact match, multi-window prefix match, and instanceIdMap UUID lookup.
4998
- * Returns null if no match — never falls back to another IDE. */
5042
+ /** Get CDP manager for a specific session or manager key. */
4999
5043
  getCdp(ideType) {
5000
- const key = ideType || this._currentIdeType;
5001
- if (!key) return null;
5002
- const resolved = this._ctx.instanceIdMap?.get(key) || key;
5003
- const m = findCdpManager(this._ctx.cdpManagers, resolved);
5044
+ const requested = ideType || this._currentRoute.session?.sessionId || this._currentRoute.managerKey;
5045
+ if (!requested) return null;
5046
+ const session = this._ctx.sessionRegistry?.get(requested);
5047
+ const managerKey = session?.cdpManagerKey || requested;
5048
+ const m = findCdpManager(this._ctx.cdpManagers, managerKey);
5004
5049
  if (m?.isConnected) return m;
5005
5050
  return null;
5006
5051
  }
@@ -5008,7 +5053,7 @@ var init_handler = __esm({
5008
5053
  * Get provider module — _currentProviderType (agentType priority) use.
5009
5054
  */
5010
5055
  getProvider(overrideType) {
5011
- const key = overrideType || this._currentProviderType || this._currentIdeType;
5056
+ const key = overrideType || this._currentRoute.providerType || this._currentRoute.session?.providerType || this._currentRoute.managerKey;
5012
5057
  if (!key || !this._ctx.providerLoader) return void 0;
5013
5058
  const result = this._ctx.providerLoader.resolve(key);
5014
5059
  if (result) return result;
@@ -5041,14 +5086,22 @@ var init_handler = __esm({
5041
5086
  const cdp = this.getCdp();
5042
5087
  if (!cdp?.isConnected) return null;
5043
5088
  if (provider?.category === "extension") {
5044
- let sessionId = this.getExtensionSessionId(provider, this._currentIdeType);
5045
- if (!sessionId && this._agentStream && this._currentIdeType) {
5046
- await this._agentStream.switchActiveAgent(cdp, this._currentIdeType, provider.type);
5047
- await this._agentStream.syncAgentSessions(cdp, this._currentIdeType);
5048
- sessionId = this.getExtensionSessionId(provider, this._currentIdeType);
5089
+ let sessionId = this._currentRoute.session?.sessionId || null;
5090
+ if (!sessionId && this._currentRoute.session?.parentSessionId) {
5091
+ sessionId = this._agentStream?.resolveSessionForAgent(this._currentRoute.session.parentSessionId, provider.type) || null;
5092
+ }
5093
+ if (sessionId && this._agentStream) {
5094
+ const target = this._ctx.sessionRegistry?.get(sessionId);
5095
+ if (target?.parentSessionId) {
5096
+ await this._agentStream.setActiveSession(cdp, target.parentSessionId, sessionId);
5097
+ await this._agentStream.syncActiveSession(cdp, target.parentSessionId);
5098
+ }
5049
5099
  }
5050
5100
  if (!sessionId) return null;
5051
- const result2 = await cdp.evaluateInSessionFrame(sessionId, script, timeout);
5101
+ const managed = this._agentStream?.getManagedSession(sessionId);
5102
+ const cdpSessionId = managed?.cdpSessionId;
5103
+ if (!cdpSessionId) return null;
5104
+ const result2 = await cdp.evaluateInSessionFrame(cdpSessionId, script, timeout);
5052
5105
  return { result: result2, category: "extension" };
5053
5106
  }
5054
5107
  const result = await cdp.evaluate(script, timeout);
@@ -5056,57 +5109,37 @@ var init_handler = __esm({
5056
5109
  }
5057
5110
  /** CLI adapter search */
5058
5111
  getCliAdapter(type) {
5059
- const target = type || this._currentIdeType;
5112
+ const target = type || this._currentRoute.session?.sessionId || this._currentRoute.providerType || this._currentRoute.managerKey;
5060
5113
  if (!target || !this._ctx.adapters) return null;
5061
- let normalizedTarget = target;
5062
- const colonIdx = normalizedTarget.lastIndexOf(":");
5063
- if (colonIdx >= 0) normalizedTarget = normalizedTarget.substring(colonIdx + 1);
5064
- const direct = this._ctx.adapters.get(normalizedTarget);
5065
- if (direct) return direct;
5066
- for (const [key, adapter] of this._ctx.adapters.entries()) {
5067
- if (adapter.cliType === target || adapter.cliType === normalizedTarget || key === normalizedTarget || key.startsWith(target) || key.startsWith(normalizedTarget)) {
5068
- return adapter;
5069
- }
5114
+ const session = this._ctx.sessionRegistry?.get(target);
5115
+ if (session?.adapterKey) {
5116
+ return this._ctx.adapters.get(session.adapterKey) || null;
5070
5117
  }
5071
- return null;
5118
+ return this._ctx.adapters.get(target) || null;
5072
5119
  }
5073
5120
  // ─── Private helpers ──────────────────────────────
5074
- getExtensionSessionId(provider, scopeKey) {
5075
- if (provider.category !== "extension" || !this._agentStream || !scopeKey) return null;
5076
- const managed = this._agentStream.getManagedAgent(provider.type, scopeKey);
5077
- return managed?.sessionId || null;
5078
- }
5079
- resolveManagerKeyFromInstanceId(instanceId) {
5080
- const mapped = this._ctx.instanceIdMap?.get(instanceId);
5081
- if (mapped) return mapped;
5082
- const entries = this._ctx.instanceManager?.instances?.entries?.();
5083
- if (!entries) return void 0;
5084
- for (const [instanceKey, instance] of entries) {
5085
- if (typeof instanceKey !== "string" || !instanceKey.startsWith("ide:")) continue;
5086
- if (typeof instance?.getInstanceId === "function" && instance.getInstanceId() === instanceId) {
5087
- const managerKey = instanceKey.slice(4);
5088
- this._ctx.instanceIdMap?.set(instanceId, managerKey);
5089
- return managerKey;
5090
- }
5091
- if (typeof instance?.getExtensionInstances === "function") {
5092
- for (const ext of instance.getExtensionInstances() || []) {
5093
- if (typeof ext?.getInstanceId === "function" && ext.getInstanceId() === instanceId) {
5094
- const managerKey = instanceKey.slice(4);
5095
- this._ctx.instanceIdMap?.set(instanceId, managerKey);
5096
- return managerKey;
5097
- }
5098
- }
5099
- }
5100
- }
5101
- return void 0;
5102
- }
5103
- /** Extract ideType from _targetInstance or explicit ideType */
5121
+ inferProviderType(key) {
5122
+ if (!key) return void 0;
5123
+ const session = this._ctx.sessionRegistry?.get(key);
5124
+ if (session?.providerType) return session.providerType;
5125
+ return key.split("_")[0];
5126
+ }
5127
+ resolveRoute(args) {
5128
+ const session = this._ctx.sessionRegistry?.get(args?.targetSessionId);
5129
+ const managerKey = this.extractIdeType(args);
5130
+ const providerType = args?.agentType || args?.providerType || session?.providerType || this.inferProviderType(managerKey);
5131
+ return { session, managerKey, providerType };
5132
+ }
5133
+ /** Extract CDP scope key from target session or explicit ideType */
5104
5134
  extractIdeType(args) {
5135
+ if (args?.targetSessionId) {
5136
+ const target = this._ctx.sessionRegistry?.get(args.targetSessionId);
5137
+ if (target?.cdpManagerKey) return target.cdpManagerKey;
5138
+ if (this._ctx.cdpManagers.has(args.targetSessionId)) return args.targetSessionId;
5139
+ }
5105
5140
  if (args?.ideType) {
5106
- const mappedKey = this.resolveManagerKeyFromInstanceId(args.ideType);
5107
- if (mappedKey) {
5108
- return mappedKey;
5109
- }
5141
+ const target = this._ctx.sessionRegistry?.get(args.ideType);
5142
+ if (target?.cdpManagerKey) return target.cdpManagerKey;
5110
5143
  if (this._ctx.cdpManagers.has(args.ideType)) {
5111
5144
  return args.ideType;
5112
5145
  }
@@ -5117,34 +5150,6 @@ var init_handler = __esm({
5117
5150
  }
5118
5151
  }
5119
5152
  }
5120
- if (args?._targetInstance) {
5121
- let raw = args._targetInstance;
5122
- const ideMatch = raw.match(/:ide:(.+)$/);
5123
- const cliMatch = raw.match(/:cli:(.+)$/);
5124
- const acpMatch = raw.match(/:acp:(.+)$/);
5125
- if (ideMatch) raw = ideMatch[1];
5126
- else if (cliMatch) raw = cliMatch[1];
5127
- else if (acpMatch) raw = acpMatch[1];
5128
- const mappedKey = this.resolveManagerKeyFromInstanceId(raw);
5129
- if (mappedKey) {
5130
- return mappedKey;
5131
- }
5132
- if (this._ctx.cdpManagers.has(raw)) {
5133
- return raw;
5134
- }
5135
- const found = findCdpManager(this._ctx.cdpManagers, raw);
5136
- if (found) {
5137
- for (const [k, m] of this._ctx.cdpManagers.entries()) {
5138
- if (m === found) return k;
5139
- }
5140
- }
5141
- const lastUnderscore = raw.lastIndexOf("_");
5142
- if (lastUnderscore > 0) {
5143
- const stripped = raw.substring(0, lastUnderscore);
5144
- if (this._ctx.cdpManagers.has(stripped)) return stripped;
5145
- }
5146
- return raw;
5147
- }
5148
5153
  return void 0;
5149
5154
  }
5150
5155
  setAgentStreamManager(manager) {
@@ -5152,12 +5157,11 @@ var init_handler = __esm({
5152
5157
  }
5153
5158
  // ─── Command Dispatcher ──────────────────────────
5154
5159
  async handle(cmd, args) {
5155
- this._currentIdeType = this.extractIdeType(args);
5156
- this._currentProviderType = args?.agentType || args?.providerType || this._currentIdeType;
5157
- if (!this._currentIdeType && !this._currentProviderType) {
5160
+ this._currentRoute = this.resolveRoute(args);
5161
+ if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
5158
5162
  const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
5159
5163
  if (cdpCommands.includes(cmd)) {
5160
- return { success: false, error: "No ideType specified \u2014 cannot route command" };
5164
+ return { success: false, error: "No targetSessionId specified \u2014 cannot route command" };
5161
5165
  }
5162
5166
  }
5163
5167
  try {
@@ -5248,22 +5252,8 @@ var init_handler = __esm({
5248
5252
  case "refresh_scripts":
5249
5253
  return this.handleRefreshScripts(args);
5250
5254
  // ─── Stream commands (stream-commands.ts) ───────────
5251
- case "agent_stream_switch":
5252
- return handleAgentStreamSwitch(this, args);
5253
- case "agent_stream_read":
5254
- return handleAgentStreamRead(this, args);
5255
- case "agent_stream_send":
5256
- return handleAgentStreamSend(this, args);
5257
- case "agent_stream_resolve":
5258
- return handleAgentStreamResolve(this, args);
5259
- case "agent_stream_new":
5260
- return handleAgentStreamNew(this, args);
5261
- case "agent_stream_list_chats":
5262
- return handleAgentStreamListChats(this, args);
5263
- case "agent_stream_switch_session":
5264
- return handleAgentStreamSwitchSession(this, args);
5265
- case "agent_stream_focus":
5266
- return handleAgentStreamFocus(this, args);
5255
+ case "focus_session":
5256
+ return handleFocusSession(this, args);
5267
5257
  // ─── PTY Raw I/O (stream-commands.ts) ─────────
5268
5258
  case "pty_input":
5269
5259
  return handlePtyInput(this, args);
@@ -8689,8 +8679,7 @@ var init_router = __esm({
8689
8679
  "new_chat",
8690
8680
  "switch_chat",
8691
8681
  "set_mode",
8692
- "change_model",
8693
- "agent_stream_send"
8682
+ "change_model"
8694
8683
  ];
8695
8684
  DaemonCommandRouter = class {
8696
8685
  deps;
@@ -8928,6 +8917,7 @@ var init_router = __esm({
8928
8917
  } catch {
8929
8918
  }
8930
8919
  this.deps.cdpManagers.delete(key);
8920
+ this.deps.sessionRegistry.unregisterByManagerKey(key);
8931
8921
  LOG.info("StopIDE", `CDP disconnected: ${key}`);
8932
8922
  }
8933
8923
  }
@@ -8940,14 +8930,6 @@ var init_router = __esm({
8940
8930
  for (const instanceKey of keysToRemove) {
8941
8931
  const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
8942
8932
  if (ideInstance) {
8943
- if (ideInstance.getInstanceId) {
8944
- this.deps.instanceIdMap.delete(ideInstance.getInstanceId());
8945
- }
8946
- if (ideInstance.getExtensionInstances) {
8947
- for (const ext of ideInstance.getExtensionInstances()) {
8948
- if (ext.getInstanceId) this.deps.instanceIdMap.delete(ext.getInstanceId());
8949
- }
8950
- }
8951
8933
  this.deps.instanceManager.removeInstance(instanceKey);
8952
8934
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
8953
8935
  }
@@ -8956,14 +8938,6 @@ var init_router = __esm({
8956
8938
  const instanceKey = `ide:${ideType}`;
8957
8939
  const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
8958
8940
  if (ideInstance) {
8959
- if (ideInstance.getInstanceId) {
8960
- this.deps.instanceIdMap.delete(ideInstance.getInstanceId());
8961
- }
8962
- if (ideInstance.getExtensionInstances) {
8963
- for (const ext of ideInstance.getExtensionInstances()) {
8964
- if (ext.getInstanceId) this.deps.instanceIdMap.delete(ext.getInstanceId());
8965
- }
8966
- }
8967
8941
  this.deps.instanceManager.removeInstance(instanceKey);
8968
8942
  LOG.info("StopIDE", `Instance removed: ${instanceKey}`);
8969
8943
  }
@@ -9012,15 +8986,9 @@ function buildStatusSnapshot(options) {
9012
8986
  const cfg = loadConfig();
9013
8987
  const wsState = getWorkspaceState(cfg);
9014
8988
  const memSnap = getHostMemorySnapshot();
9015
- const { managedIdes, managedClis, managedAcps } = buildAllManagedEntries(
8989
+ const sessions = buildSessionEntries(
9016
8990
  options.allStates,
9017
- options.cdpManagers,
9018
- {
9019
- detectedIdes: options.detectedIdes.map((ide) => ({
9020
- id: ide.id,
9021
- installed: ide.installed !== false
9022
- }))
9023
- }
8991
+ options.cdpManagers
9024
8992
  );
9025
8993
  return {
9026
8994
  instanceId: options.instanceId,
@@ -9042,9 +9010,7 @@ function buildStatusSnapshot(options) {
9042
9010
  timestamp: options.timestamp ?? Date.now(),
9043
9011
  detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
9044
9012
  ...options.p2p ? { p2p: options.p2p } : {},
9045
- managedIdes,
9046
- managedClis,
9047
- managedAcps,
9013
+ sessions,
9048
9014
  workspaces: wsState.workspaces,
9049
9015
  defaultWorkspaceId: wsState.defaultWorkspaceId,
9050
9016
  defaultWorkspacePath: wsState.defaultWorkspacePath,
@@ -9175,7 +9141,7 @@ var init_reporter = __esm({
9175
9141
  LOG.info("StatusReport", `\u2192${target} ${baseSummary}`);
9176
9142
  }
9177
9143
  }
9178
- const { managedIdes, managedClis, managedAcps } = buildAllManagedEntries(
9144
+ const sessions = buildSessionEntries(
9179
9145
  allStates,
9180
9146
  this.deps.cdpManagers
9181
9147
  );
@@ -9206,23 +9172,20 @@ var init_reporter = __esm({
9206
9172
  if (opts?.p2pOnly) return;
9207
9173
  const wsPayload = {
9208
9174
  daemonMode: true,
9209
- // managedIdes: server only saves id, type, cdpConnected
9210
- managedIdes: managedIdes.map((ide) => ({
9211
- ideType: ide.ideType,
9212
- instanceId: ide.instanceId,
9213
- cdpConnected: ide.cdpConnected
9214
- })),
9215
- // managedClis: server only saves id, type, name
9216
- managedClis: managedClis.map((c) => ({
9217
- id: c.id,
9218
- cliType: c.cliType,
9219
- cliName: c.cliName
9220
- })),
9221
- // managedAcps: server only saves id, type, name
9222
- managedAcps: managedAcps?.map((a) => ({
9223
- id: a.id,
9224
- acpType: a.acpType,
9225
- acpName: a.acpName
9175
+ sessions: sessions.map((session) => ({
9176
+ id: session.id,
9177
+ parentId: session.parentId,
9178
+ providerType: session.providerType,
9179
+ providerName: session.providerName,
9180
+ kind: session.kind,
9181
+ transport: session.transport,
9182
+ status: session.status,
9183
+ workspace: session.workspace,
9184
+ title: session.title,
9185
+ cdpConnected: session.cdpConnected,
9186
+ currentModel: session.currentModel,
9187
+ currentPlan: session.currentPlan,
9188
+ currentAutoApprove: session.currentAutoApprove
9226
9189
  })),
9227
9190
  p2p: payload.p2p,
9228
9191
  timestamp: now
@@ -36203,6 +36166,9 @@ var init_acp_provider_instance = __esm({
36203
36166
  );
36204
36167
  }
36205
36168
  }
36169
+ getInstanceId() {
36170
+ return this.instanceId;
36171
+ }
36206
36172
  // ─── ACP Config Options & Modes ─────────────────────
36207
36173
  parseConfigOptions(raw) {
36208
36174
  if (!Array.isArray(raw)) return;
@@ -36999,6 +36965,7 @@ var init_cli_manager = __esm({
36999
36965
  const normalizedType = this.providerLoader.resolveAlias(cliType);
37000
36966
  const provider = this.providerLoader.getByAlias(cliType);
37001
36967
  const key = crypto4.randomUUID();
36968
+ const sessionRegistry = this.deps.getSessionRegistry?.() || null;
37002
36969
  if (provider && provider.category === "acp") {
37003
36970
  const instanceManager2 = this.deps.getInstanceManager();
37004
36971
  if (!instanceManager2) throw new Error("InstanceManager not available");
@@ -37022,6 +36989,16 @@ ${installInfo}`
37022
36989
  await instanceManager2.addInstance(key, acpInstance, {
37023
36990
  settings: this.providerLoader.getSettings(normalizedType)
37024
36991
  });
36992
+ const sessionId = acpInstance.getInstanceId();
36993
+ sessionRegistry?.register({
36994
+ sessionId,
36995
+ parentSessionId: null,
36996
+ providerType: normalizedType,
36997
+ providerCategory: "acp",
36998
+ transport: "acp",
36999
+ adapterKey: key,
37000
+ instanceKey: key
37001
+ });
37025
37002
  this.adapters.set(key, {
37026
37003
  cliType: normalizedType,
37027
37004
  workingDir: resolvedDir,
@@ -37079,9 +37056,18 @@ ${installInfo}`
37079
37056
  serverConn: this.deps.getServerConn(),
37080
37057
  settings: {},
37081
37058
  onPtyData: (data) => {
37082
- this.deps.getP2p()?.broadcastPtyOutput(key, data);
37059
+ this.deps.getP2p()?.broadcastPtyOutput(cliInstance.instanceId, data);
37083
37060
  }
37084
37061
  });
37062
+ sessionRegistry?.register({
37063
+ sessionId: cliInstance.instanceId,
37064
+ parentSessionId: null,
37065
+ providerType: normalizedType,
37066
+ providerCategory: "cli",
37067
+ transport: "pty",
37068
+ adapterKey: key,
37069
+ instanceKey: key
37070
+ });
37085
37071
  } catch (spawnErr) {
37086
37072
  LOG.error("CLI", `[${cliType}] Spawn failed: ${spawnErr?.message}`);
37087
37073
  instanceManager.removeInstance(key);
@@ -37103,6 +37089,7 @@ ${installInfo}`
37103
37089
  if (this.adapters.has(key)) {
37104
37090
  this.adapters.delete(key);
37105
37091
  this.deps.removeAgentTracking(key);
37092
+ sessionRegistry?.unregisterByInstanceKey(key);
37106
37093
  instanceManager.removeInstance(key);
37107
37094
  LOG.info("CLI", `\u{1F9F9} Auto-cleaned ${status.status} CLI: ${cliType}`);
37108
37095
  this.deps.onStatusChange();
@@ -37163,12 +37150,14 @@ ${installInfo}`
37163
37150
  }
37164
37151
  this.adapters.delete(key);
37165
37152
  this.deps.removeAgentTracking(key);
37153
+ this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
37166
37154
  this.deps.getInstanceManager()?.removeInstance(key);
37167
37155
  LOG.info("CLI", `\u{1F6D1} Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
37168
37156
  this.deps.onStatusChange();
37169
37157
  } else {
37170
37158
  const im = this.deps.getInstanceManager();
37171
37159
  if (im) {
37160
+ this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
37172
37161
  im.removeInstance(key);
37173
37162
  this.deps.removeAgentTracking(key);
37174
37163
  LOG.warn("CLI", `\u{1F9F9} Force-removed orphan entry: ${key}`);
@@ -37183,7 +37172,7 @@ ${installInfo}`
37183
37172
  // ─── Adapter search ─────────────────────────────
37184
37173
  /**
37185
37174
  * Search for CLI adapter. Priority order:
37186
- * 0. instanceKey (UUID direct match) — extracted from _targetInstance / composite ID
37175
+ * 0. sessionId (UUID direct match)
37187
37176
  * 1. agentType + dir (iteration match)
37188
37177
  * 2. agentType fuzzy match (⚠ returns first match when multiple sessions exist)
37189
37178
  */
@@ -37251,7 +37240,7 @@ ${installInfo}`
37251
37240
  const cliType = args?.cliType;
37252
37241
  const dir = args?.dir || "";
37253
37242
  if (!cliType) throw new Error("cliType required");
37254
- const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
37243
+ const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
37255
37244
  if (found) {
37256
37245
  await this.stopSession(found.key);
37257
37246
  } else {
@@ -37283,7 +37272,7 @@ ${installInfo}`
37283
37272
  }
37284
37273
  const dir = rdir.path;
37285
37274
  if (!cliType) throw new Error("cliType required");
37286
- const found = this.findAdapter(cliType, { instanceKey: args?._targetInstance, dir });
37275
+ const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
37287
37276
  if (found) await this.stopSession(found.key);
37288
37277
  await this.startSession(cliType, dir);
37289
37278
  this.persistRecentDir(cliType, dir);
@@ -37295,7 +37284,7 @@ ${installInfo}`
37295
37284
  if (!agentType || !action) throw new Error("agentType and action required");
37296
37285
  const found = this.findAdapter(agentType, {
37297
37286
  dir: args?.dir,
37298
- instanceKey: args?._targetInstance
37287
+ instanceKey: args?.targetSessionId
37299
37288
  });
37300
37289
  if (!found) throw new Error(`CLI agent not running: ${agentType}`);
37301
37290
  const { adapter, key } = found;
@@ -37460,14 +37449,8 @@ var init_manager2 = __esm({
37460
37449
  init_provider_adapter();
37461
37450
  init_logger();
37462
37451
  DaemonAgentStreamManager = class {
37463
- allAdapters = [];
37464
- managedByScope = /* @__PURE__ */ new Map();
37465
- enabled = true;
37466
- logFn;
37467
- lastDiscoveryTimeByScope = /* @__PURE__ */ new Map();
37468
- discoveryIntervalMsByScope = /* @__PURE__ */ new Map();
37469
- activeAgentTypeByScope = /* @__PURE__ */ new Map();
37470
- constructor(logFn, providerLoader) {
37452
+ constructor(logFn, providerLoader, sessionRegistry) {
37453
+ this.sessionRegistry = sessionRegistry;
37471
37454
  this.logFn = logFn || LOG.forComponent("AgentStream").asLogFn();
37472
37455
  if (providerLoader) {
37473
37456
  const allExtProviders = providerLoader.getByCategory("extension");
@@ -37475,257 +37458,278 @@ var init_manager2 = __esm({
37475
37458
  const resolved = providerLoader.resolve(p.type);
37476
37459
  if (!resolved) continue;
37477
37460
  const adapter = new ProviderStreamAdapter(resolved);
37478
- this.allAdapters.push(adapter);
37461
+ this.adaptersByType.set(p.type, adapter);
37479
37462
  this.logFn(`[AgentStream] Adapter created: ${p.type} (${p.name}) scripts=${Object.keys(resolved.scripts || {}).join(",") || "none"}`);
37480
37463
  }
37481
37464
  }
37482
37465
  }
37466
+ adaptersByType = /* @__PURE__ */ new Map();
37467
+ managedBySessionId = /* @__PURE__ */ new Map();
37468
+ enabled = true;
37469
+ logFn;
37470
+ lastDiscoveryTimeByParent = /* @__PURE__ */ new Map();
37471
+ discoveryIntervalMsByParent = /* @__PURE__ */ new Map();
37472
+ activeSessionIdByParent = /* @__PURE__ */ new Map();
37483
37473
  setEnabled(enabled) {
37484
37474
  this.enabled = enabled;
37485
37475
  }
37486
37476
  get isEnabled() {
37487
37477
  return this.enabled;
37488
37478
  }
37489
- getActiveAgentType(scopeKey) {
37490
- return this.activeAgentTypeByScope.get(scopeKey) || null;
37479
+ getActiveSessionId(parentSessionId) {
37480
+ return this.activeSessionIdByParent.get(parentSessionId) || null;
37491
37481
  }
37492
- getManagedScope(scopeKey) {
37493
- let managed = this.managedByScope.get(scopeKey);
37494
- if (!managed) {
37495
- managed = /* @__PURE__ */ new Map();
37496
- this.managedByScope.set(scopeKey, managed);
37497
- }
37498
- return managed;
37482
+ getSessionTarget(sessionId) {
37483
+ return this.sessionRegistry?.get(sessionId);
37499
37484
  }
37500
- resetScope(scopeKey) {
37501
- this.managedByScope.delete(scopeKey);
37502
- this.activeAgentTypeByScope.delete(scopeKey);
37503
- this.lastDiscoveryTimeByScope.delete(scopeKey);
37504
- this.discoveryIntervalMsByScope.delete(scopeKey);
37485
+ resetParentSession(parentSessionId) {
37486
+ const activeSessionId = this.activeSessionIdByParent.get(parentSessionId);
37487
+ if (activeSessionId) this.managedBySessionId.delete(activeSessionId);
37488
+ for (const child of this.sessionRegistry?.listChildren(parentSessionId) || []) {
37489
+ this.managedBySessionId.delete(child.sessionId);
37490
+ }
37491
+ this.activeSessionIdByParent.delete(parentSessionId);
37492
+ this.lastDiscoveryTimeByParent.delete(parentSessionId);
37493
+ this.discoveryIntervalMsByParent.delete(parentSessionId);
37505
37494
  }
37506
37495
  /** Panel focus based on provider.js focusPanel or extensionId (currently no-op) */
37507
- async ensureAgentPanelOpen(agentType, targetIdeType) {
37508
- }
37509
- async switchActiveAgent(cdp, scopeKey, agentType) {
37510
- const managed = this.getManagedScope(scopeKey);
37511
- const previousAgentType = this.getActiveAgentType(scopeKey);
37512
- if (previousAgentType === agentType) return;
37513
- if (previousAgentType) {
37514
- const prev = managed.get(previousAgentType);
37496
+ async ensureSessionPanelOpen(_sessionId) {
37497
+ }
37498
+ async setActiveSession(cdp, parentSessionId, sessionId) {
37499
+ const previousSessionId = this.getActiveSessionId(parentSessionId);
37500
+ if (previousSessionId === sessionId) return;
37501
+ if (previousSessionId) {
37502
+ const prev = this.managedBySessionId.get(previousSessionId);
37515
37503
  if (prev) {
37516
37504
  try {
37517
- await cdp.detachAgent(prev.sessionId);
37505
+ await cdp.detachAgent(prev.cdpSessionId);
37518
37506
  } catch {
37519
37507
  }
37520
- managed.delete(previousAgentType);
37521
- this.logFn(`[AgentStream] Deactivated: ${prev.adapter.agentName} (${scopeKey})`);
37522
- }
37523
- }
37524
- this.activeAgentTypeByScope.set(scopeKey, agentType);
37525
- this.lastDiscoveryTimeByScope.set(scopeKey, 0);
37526
- if (!agentType && managed.size === 0) {
37527
- this.managedByScope.delete(scopeKey);
37528
- }
37529
- this.logFn(`[AgentStream] Active agent (${scopeKey}): ${agentType || "none"}`);
37508
+ this.managedBySessionId.delete(previousSessionId);
37509
+ this.logFn(`[AgentStream] Deactivated: ${prev.adapter.agentName} (${parentSessionId})`);
37510
+ }
37511
+ }
37512
+ this.activeSessionIdByParent.set(parentSessionId, sessionId);
37513
+ this.lastDiscoveryTimeByParent.set(parentSessionId, 0);
37514
+ this.logFn(`[AgentStream] Active session (${parentSessionId}): ${sessionId || "none"}`);
37515
+ }
37516
+ resolveSessionIdForTarget(parentSessionId, agentType) {
37517
+ const child = (this.sessionRegistry?.listChildren(parentSessionId) || []).find((entry) => entry.providerCategory === "extension" && entry.providerType === agentType);
37518
+ return child?.sessionId || null;
37519
+ }
37520
+ async connectManagedSession(cdp, parentSessionId, runtimeSessionId) {
37521
+ const target = this.getSessionTarget(runtimeSessionId);
37522
+ if (!target || target.providerCategory !== "extension") return null;
37523
+ const adapter = this.adaptersByType.get(target.providerType);
37524
+ if (!adapter) return null;
37525
+ const targets = await cdp.discoverAgentWebviews();
37526
+ const activeTarget = targets.find((entry) => entry.agentType === target.providerType);
37527
+ if (!activeTarget) return null;
37528
+ const cdpSessionId = await cdp.attachToAgent(activeTarget);
37529
+ if (!cdpSessionId) return null;
37530
+ const managed = {
37531
+ adapter,
37532
+ runtimeSessionId,
37533
+ parentSessionId,
37534
+ cdpSessionId,
37535
+ target: activeTarget,
37536
+ lastState: null,
37537
+ lastError: null,
37538
+ lastHiddenCheckTime: 0
37539
+ };
37540
+ this.managedBySessionId.set(runtimeSessionId, managed);
37541
+ this.logFn(`[AgentStream] Connected: ${adapter.agentName} (${parentSessionId})`);
37542
+ return managed;
37530
37543
  }
37531
37544
  /** Agent webview discovery + session connection */
37532
- async syncAgentSessions(cdp, scopeKey) {
37533
- const activeAgentType = this.getActiveAgentType(scopeKey);
37534
- if (!this.enabled || !activeAgentType) return;
37545
+ async syncActiveSession(cdp, parentSessionId) {
37546
+ const activeSessionId = this.getActiveSessionId(parentSessionId);
37547
+ if (!this.enabled || !activeSessionId) return;
37535
37548
  const now = Date.now();
37536
- const managed = this.getManagedScope(scopeKey);
37537
- const lastDiscoveryTime = this.lastDiscoveryTimeByScope.get(scopeKey) || 0;
37538
- const discoveryIntervalMs = this.discoveryIntervalMsByScope.get(scopeKey) || 1e4;
37539
- if (managed.has(activeAgentType) && now - lastDiscoveryTime < discoveryIntervalMs) {
37549
+ const managed = this.managedBySessionId.get(activeSessionId);
37550
+ const lastDiscoveryTime = this.lastDiscoveryTimeByParent.get(parentSessionId) || 0;
37551
+ const discoveryIntervalMs = this.discoveryIntervalMsByParent.get(parentSessionId) || 1e4;
37552
+ if (managed && now - lastDiscoveryTime < discoveryIntervalMs) {
37540
37553
  return;
37541
37554
  }
37542
- this.lastDiscoveryTimeByScope.set(scopeKey, now);
37555
+ this.lastDiscoveryTimeByParent.set(parentSessionId, now);
37543
37556
  try {
37544
- const targets = await cdp.discoverAgentWebviews();
37545
- const activeTarget = targets.find((t) => t.agentType === activeAgentType);
37546
- if (activeTarget && !managed.has(activeAgentType)) {
37547
- const adapter = this.allAdapters.find((a) => a.agentType === activeAgentType);
37548
- if (adapter) {
37549
- const sessionId = await cdp.attachToAgent(activeTarget);
37550
- if (sessionId) {
37551
- managed.set(activeAgentType, {
37552
- adapter,
37553
- sessionId,
37554
- target: activeTarget,
37555
- lastState: null,
37556
- lastError: null,
37557
- lastHiddenCheckTime: 0
37558
- });
37559
- this.logFn(`[AgentStream] Connected: ${adapter.agentName} (${scopeKey})`);
37560
- }
37561
- }
37557
+ if (!managed) {
37558
+ await this.connectManagedSession(cdp, parentSessionId, activeSessionId);
37562
37559
  }
37563
- for (const [type, agent] of managed) {
37564
- if (type !== activeAgentType) {
37565
- await cdp.detachAgent(agent.sessionId);
37566
- managed.delete(type);
37567
- }
37568
- }
37569
- this.discoveryIntervalMsByScope.set(scopeKey, managed.has(activeAgentType) ? 3e4 : 1e4);
37560
+ this.discoveryIntervalMsByParent.set(parentSessionId, this.managedBySessionId.has(activeSessionId) ? 3e4 : 1e4);
37570
37561
  } catch (e) {
37571
- this.logFn(`[AgentStream] sync error (${scopeKey}): ${e.message}`);
37562
+ this.logFn(`[AgentStream] sync error (${parentSessionId}): ${e.message}`);
37572
37563
  }
37573
37564
  }
37574
- /** Collect active agent status */
37575
- async collectAgentStreams(cdp, scopeKey) {
37576
- if (!this.enabled) return [];
37577
- const results = [];
37578
- const activeAgentType = this.getActiveAgentType(scopeKey);
37579
- const managed = this.managedByScope.get(scopeKey);
37580
- if (activeAgentType && managed?.has(activeAgentType)) {
37581
- const agent = managed.get(activeAgentType);
37582
- const type = activeAgentType;
37583
- const isHidden = agent.lastState?.status === "panel_hidden";
37584
- const hiddenCacheFresh = isHidden && Date.now() - agent.lastHiddenCheckTime < 3e4;
37585
- if (hiddenCacheFresh) {
37586
- results.push(agent.lastState);
37587
- } else {
37565
+ /** Collect active extension session state */
37566
+ async collectActiveSession(cdp, parentSessionId) {
37567
+ if (!this.enabled) return null;
37568
+ const activeSessionId = this.getActiveSessionId(parentSessionId);
37569
+ if (!activeSessionId) return null;
37570
+ let agent = this.managedBySessionId.get(activeSessionId);
37571
+ if (!agent) {
37572
+ agent = await this.connectManagedSession(cdp, parentSessionId, activeSessionId) || void 0;
37573
+ }
37574
+ if (!agent) return null;
37575
+ const type = agent.adapter.agentType;
37576
+ const isHidden = agent.lastState?.status === "panel_hidden";
37577
+ const hiddenCacheFresh = isHidden && Date.now() - agent.lastHiddenCheckTime < 3e4;
37578
+ if (hiddenCacheFresh) return agent.lastState;
37579
+ try {
37580
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37581
+ const state = await agent.adapter.readChat(evaluate);
37582
+ 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") : ""}`);
37583
+ agent.lastState = state;
37584
+ agent.lastError = null;
37585
+ if (state.status === "panel_hidden") {
37586
+ agent.lastHiddenCheckTime = Date.now();
37587
+ }
37588
+ return state;
37589
+ } catch (e) {
37590
+ const errorMsg = e?.message || String(e);
37591
+ this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
37592
+ agent.lastError = errorMsg;
37593
+ if (errorMsg.includes("timeout") || errorMsg.includes("not connected") || errorMsg.includes("Session")) {
37588
37594
  try {
37589
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37590
- const state = await agent.adapter.readChat(evaluate);
37591
- 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") : ""}`);
37592
- agent.lastState = state;
37593
- agent.lastError = null;
37594
- if (state.status === "panel_hidden") {
37595
- agent.lastHiddenCheckTime = Date.now();
37596
- }
37597
- results.push(state);
37598
- } catch (e) {
37599
- const errorMsg = e?.message || String(e);
37600
- this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
37601
- agent.lastError = errorMsg;
37602
- results.push({
37603
- agentType: type,
37604
- agentName: agent.adapter.agentName,
37605
- extensionId: agent.adapter.extensionId,
37606
- status: "disconnected",
37607
- messages: agent.lastState?.messages || [],
37608
- inputContent: ""
37609
- });
37610
- if (errorMsg.includes("timeout") || errorMsg.includes("not connected") || errorMsg.includes("Session")) {
37611
- try {
37612
- await cdp.detachAgent(agent.sessionId);
37613
- } catch {
37614
- }
37615
- managed.delete(type);
37616
- this.lastDiscoveryTimeByScope.set(scopeKey, 0);
37617
- }
37595
+ await cdp.detachAgent(agent.cdpSessionId);
37596
+ } catch {
37618
37597
  }
37598
+ this.managedBySessionId.delete(activeSessionId);
37599
+ this.lastDiscoveryTimeByParent.set(parentSessionId, 0);
37619
37600
  }
37601
+ return {
37602
+ agentType: type,
37603
+ agentName: agent.adapter.agentName,
37604
+ extensionId: agent.adapter.extensionId,
37605
+ status: "disconnected",
37606
+ messages: agent.lastState?.messages || [],
37607
+ inputContent: ""
37608
+ };
37620
37609
  }
37621
- return results;
37622
37610
  }
37623
- async sendToAgent(cdp, scopeKey, agentType, text, targetIdeType) {
37624
- await this.ensureAgentPanelOpen(agentType, targetIdeType);
37625
- const agent = this.getManagedAgent(agentType, scopeKey);
37611
+ async sendToSession(cdp, sessionId, text) {
37612
+ await this.ensureSessionPanelOpen(sessionId);
37613
+ const target = this.getSessionTarget(sessionId);
37614
+ if (!target?.parentSessionId) return false;
37615
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37616
+ await this.syncActiveSession(cdp, target.parentSessionId);
37617
+ const agent = this.managedBySessionId.get(sessionId);
37626
37618
  if (!agent) return false;
37627
37619
  try {
37628
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37620
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37629
37621
  await agent.adapter.sendMessage(evaluate, text);
37630
37622
  return true;
37631
37623
  } catch (e) {
37632
- this.logFn(`[AgentStream] sendToAgent(${agentType}) error: ${e.message}`);
37624
+ this.logFn(`[AgentStream] sendToSession(${sessionId}) error: ${e.message}`);
37633
37625
  return false;
37634
37626
  }
37635
37627
  }
37636
- async resolveAgentAction(cdp, scopeKey, agentType, action, targetIdeType) {
37637
- await this.ensureAgentPanelOpen(agentType, targetIdeType);
37638
- const agent = this.getManagedAgent(agentType, scopeKey);
37628
+ async resolveSessionAction(cdp, sessionId, action) {
37629
+ await this.ensureSessionPanelOpen(sessionId);
37630
+ const target = this.getSessionTarget(sessionId);
37631
+ if (!target?.parentSessionId) return false;
37632
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37633
+ await this.syncActiveSession(cdp, target.parentSessionId);
37634
+ const agent = this.managedBySessionId.get(sessionId);
37639
37635
  if (!agent) return false;
37640
37636
  try {
37641
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37637
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37642
37638
  return await agent.adapter.resolveAction(evaluate, action);
37643
37639
  } catch (e) {
37644
- this.logFn(`[AgentStream] resolveAction(${agentType}) error: ${e.message}`);
37640
+ this.logFn(`[AgentStream] resolveAction(${sessionId}) error: ${e.message}`);
37645
37641
  return false;
37646
37642
  }
37647
37643
  }
37648
- async newAgentSession(cdp, scopeKey, agentType, targetIdeType) {
37649
- await this.ensureAgentPanelOpen(agentType, targetIdeType);
37650
- const agent = this.getManagedAgent(agentType, scopeKey);
37644
+ async newSession(cdp, sessionId) {
37645
+ await this.ensureSessionPanelOpen(sessionId);
37646
+ const target = this.getSessionTarget(sessionId);
37647
+ if (!target?.parentSessionId) return false;
37648
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37649
+ await this.syncActiveSession(cdp, target.parentSessionId);
37650
+ const agent = this.managedBySessionId.get(sessionId);
37651
37651
  if (!agent) return false;
37652
37652
  try {
37653
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37653
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37654
37654
  await agent.adapter.newSession(evaluate);
37655
37655
  return true;
37656
37656
  } catch (e) {
37657
- this.logFn(`[AgentStream] newSession(${agentType}) error: ${e.message}`);
37657
+ this.logFn(`[AgentStream] newSession(${sessionId}) error: ${e.message}`);
37658
37658
  return false;
37659
37659
  }
37660
37660
  }
37661
- async listAgentChats(cdp, scopeKey, agentType) {
37662
- let agent = this.getManagedAgent(agentType, scopeKey);
37663
- if (!agent) {
37664
- this.logFn(`[AgentStream] listChats: ${agentType} not managed in ${scopeKey}, trying on-demand activation`);
37665
- await this.switchActiveAgent(cdp, scopeKey, agentType);
37666
- await this.syncAgentSessions(cdp, scopeKey);
37667
- agent = this.getManagedAgent(agentType, scopeKey);
37668
- }
37661
+ async listSessionChats(cdp, sessionId) {
37662
+ const target = this.getSessionTarget(sessionId);
37663
+ if (!target?.parentSessionId) return [];
37664
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37665
+ await this.syncActiveSession(cdp, target.parentSessionId);
37666
+ const agent = this.managedBySessionId.get(sessionId);
37669
37667
  if (!agent || typeof agent.adapter.listChats !== "function") return [];
37670
37668
  try {
37671
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37669
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37672
37670
  return await agent.adapter.listChats(evaluate);
37673
37671
  } catch (e) {
37674
- this.logFn(`[AgentStream] listChats(${agentType}) error: ${e.message}`);
37672
+ this.logFn(`[AgentStream] listChats(${sessionId}) error: ${e.message}`);
37675
37673
  return [];
37676
37674
  }
37677
37675
  }
37678
- async switchAgentSession(cdp, scopeKey, agentType, sessionId) {
37679
- let agent = this.getManagedAgent(agentType, scopeKey);
37680
- if (!agent) {
37681
- this.logFn(`[AgentStream] switchSession: ${agentType} not managed in ${scopeKey}, trying on-demand activation`);
37682
- await this.switchActiveAgent(cdp, scopeKey, agentType);
37683
- await this.syncAgentSessions(cdp, scopeKey);
37684
- agent = this.getManagedAgent(agentType, scopeKey);
37685
- }
37676
+ async switchConversation(cdp, sessionId, conversationId) {
37677
+ const target = this.getSessionTarget(sessionId);
37678
+ if (!target?.parentSessionId) return false;
37679
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37680
+ await this.syncActiveSession(cdp, target.parentSessionId);
37681
+ const agent = this.managedBySessionId.get(sessionId);
37686
37682
  if (!agent || typeof agent.adapter.switchSession !== "function") return false;
37687
37683
  try {
37688
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37689
- return await agent.adapter.switchSession(evaluate, sessionId);
37684
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37685
+ return await agent.adapter.switchSession(evaluate, conversationId);
37690
37686
  } catch (e) {
37691
- this.logFn(`[AgentStream] switchSession(${agentType}) error: ${e.message}`);
37687
+ this.logFn(`[AgentStream] switchSession(${sessionId}) error: ${e.message}`);
37692
37688
  return false;
37693
37689
  }
37694
37690
  }
37695
- async focusAgentEditor(cdp, scopeKey, agentType) {
37696
- const agent = this.getManagedAgent(agentType, scopeKey);
37691
+ async focusSession(cdp, sessionId) {
37692
+ const target = this.getSessionTarget(sessionId);
37693
+ if (!target?.parentSessionId) return false;
37694
+ await this.setActiveSession(cdp, target.parentSessionId, sessionId);
37695
+ await this.syncActiveSession(cdp, target.parentSessionId);
37696
+ const agent = this.managedBySessionId.get(sessionId);
37697
37697
  if (!agent || typeof agent.adapter.focusEditor !== "function") return false;
37698
37698
  try {
37699
- const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.sessionId, expr, timeout);
37699
+ const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37700
37700
  await agent.adapter.focusEditor(evaluate);
37701
37701
  return true;
37702
37702
  } catch (e) {
37703
- this.logFn(`[AgentStream] focusEditor(${agentType}) error: ${e.message}`);
37703
+ this.logFn(`[AgentStream] focusEditor(${sessionId}) error: ${e.message}`);
37704
37704
  return false;
37705
37705
  }
37706
37706
  }
37707
- getConnectedAgents(scopeKey) {
37708
- if (scopeKey) return Array.from((this.managedByScope.get(scopeKey) || /* @__PURE__ */ new Map()).keys());
37709
- return Array.from(this.managedByScope.values()).flatMap((scope) => Array.from(scope.keys()));
37707
+ getConnectedSessions(parentSessionId) {
37708
+ if (parentSessionId) {
37709
+ return [...this.managedBySessionId.values()].filter((entry) => entry.parentSessionId === parentSessionId).map((entry) => entry.runtimeSessionId);
37710
+ }
37711
+ return [...this.managedBySessionId.keys()];
37710
37712
  }
37711
- getManagedAgent(agentType, scopeKey) {
37712
- return this.managedByScope.get(scopeKey)?.get(agentType);
37713
+ getManagedSession(sessionId) {
37714
+ return this.managedBySessionId.get(sessionId);
37713
37715
  }
37714
37716
  async dispose(cdpManagers) {
37715
- for (const [scopeKey, managed] of this.managedByScope) {
37716
- const cdp = cdpManagers.get(scopeKey);
37717
+ for (const managed of this.managedBySessionId.values()) {
37718
+ const managerKey = this.getSessionTarget(managed.runtimeSessionId)?.cdpManagerKey;
37719
+ const cdp = managerKey ? cdpManagers.get(managerKey) : null;
37717
37720
  if (!cdp) continue;
37718
- for (const [, agent] of managed) {
37719
- try {
37720
- await cdp.detachAgent(agent.sessionId);
37721
- } catch {
37722
- }
37721
+ try {
37722
+ await cdp.detachAgent(managed.cdpSessionId);
37723
+ } catch {
37723
37724
  }
37724
37725
  }
37725
- this.managedByScope.clear();
37726
- this.activeAgentTypeByScope.clear();
37727
- this.lastDiscoveryTimeByScope.clear();
37728
- this.discoveryIntervalMsByScope.clear();
37726
+ this.managedBySessionId.clear();
37727
+ this.activeSessionIdByParent.clear();
37728
+ this.lastDiscoveryTimeByParent.clear();
37729
+ this.discoveryIntervalMsByParent.clear();
37730
+ }
37731
+ resolveSessionForAgent(parentSessionId, agentType) {
37732
+ return this.resolveSessionIdForTarget(parentSessionId, agentType);
37729
37733
  }
37730
37734
  };
37731
37735
  }
@@ -37756,8 +37760,8 @@ var init_poller = __esm({
37756
37760
  return null;
37757
37761
  }
37758
37762
  /** Reset active IDE tracking (e.g., when IDE is stopped) */
37759
- resetActiveIde(ideType) {
37760
- this.deps.agentStreamManager.resetScope(ideType);
37763
+ resetActiveIde(parentSessionId) {
37764
+ this.deps.agentStreamManager.resetParentSession(parentSessionId);
37761
37765
  }
37762
37766
  /** Start polling (idempotent — ignored if already started) */
37763
37767
  start(intervalMs = 5e3) {
@@ -37779,12 +37783,14 @@ var init_poller = __esm({
37779
37783
  agentStreamManager,
37780
37784
  providerLoader,
37781
37785
  instanceManager,
37782
- cdpManagers
37786
+ cdpManagers,
37787
+ sessionRegistry
37783
37788
  } = this.deps;
37784
37789
  if (!agentStreamManager || cdpManagers.size === 0) return;
37785
37790
  for (const [ideType, cdp] of cdpManagers) {
37786
37791
  registerExtensionProviders(providerLoader, cdp, ideType);
37787
37792
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
37793
+ const parentSessionId = ideInstance?.getInstanceId?.();
37788
37794
  if (ideInstance?.getExtensionTypes && ideInstance?.addExtension && ideInstance?.removeExtension) {
37789
37795
  const currentExtTypes = new Set(ideInstance.getExtensionTypes());
37790
37796
  const enabledExtTypes = new Set(
@@ -37792,6 +37798,10 @@ var init_poller = __esm({
37792
37798
  );
37793
37799
  for (const extType of currentExtTypes) {
37794
37800
  if (!enabledExtTypes.has(extType)) {
37801
+ const extInstance = ideInstance.getExtension?.(extType);
37802
+ if (extInstance?.getInstanceId) {
37803
+ sessionRegistry.unregister(extInstance.getInstanceId());
37804
+ }
37795
37805
  ideInstance.removeExtension(extType);
37796
37806
  LOG.info("AgentStream", `Extension removed: ${extType} (disabled for ${ideType})`);
37797
37807
  }
@@ -37802,46 +37812,61 @@ var init_poller = __esm({
37802
37812
  if (extProvider) {
37803
37813
  const extSettings = providerLoader.getSettings(extType);
37804
37814
  ideInstance.addExtension(extProvider, extSettings);
37815
+ const extInstance = ideInstance.getExtension?.(extType);
37816
+ if (parentSessionId && extInstance?.getInstanceId) {
37817
+ sessionRegistry.register({
37818
+ sessionId: extInstance.getInstanceId(),
37819
+ parentSessionId,
37820
+ providerType: extType,
37821
+ providerCategory: "extension",
37822
+ transport: "cdp-webview",
37823
+ cdpManagerKey: ideType,
37824
+ instanceKey: `ide:${ideType}`
37825
+ });
37826
+ }
37805
37827
  LOG.info("AgentStream", `Extension added: ${extType} (enabled for ${ideType})`);
37806
37828
  }
37807
37829
  }
37808
37830
  }
37809
37831
  }
37810
- const activeType = agentStreamManager.getActiveAgentType(ideType);
37811
- if (activeType) {
37812
- const enabledExtTypes = new Set(
37813
- providerLoader.getEnabledExtensionProviders(ideType).map((p) => p.type)
37814
- );
37815
- if (!enabledExtTypes.has(activeType)) {
37816
- LOG.info("AgentStream", `Active agent ${activeType} was disabled for ${ideType} \u2014 detaching`);
37817
- await agentStreamManager.switchActiveAgent(cdp, ideType, null);
37832
+ const activeSessionId = parentSessionId ? agentStreamManager.getActiveSessionId(parentSessionId) : null;
37833
+ if (activeSessionId) {
37834
+ const activeTarget = sessionRegistry.get(activeSessionId);
37835
+ const enabledExtTypes = new Set(providerLoader.getEnabledExtensionProviders(ideType).map((p) => p.type));
37836
+ if (!activeTarget || !enabledExtTypes.has(activeTarget.providerType)) {
37837
+ LOG.info("AgentStream", `Active agent ${activeTarget?.providerType || activeSessionId} was disabled for ${ideType} \u2014 detaching`);
37838
+ await agentStreamManager.setActiveSession(cdp, parentSessionId, null);
37818
37839
  this.deps.onStreamsUpdated?.(ideType, []);
37819
37840
  }
37820
37841
  }
37821
37842
  if (!cdp.isConnected) {
37822
- if (activeType) {
37823
- agentStreamManager.resetScope(ideType);
37843
+ if (parentSessionId && activeSessionId) {
37844
+ agentStreamManager.resetParentSession(parentSessionId);
37824
37845
  this.deps.onStreamsUpdated?.(ideType, []);
37825
37846
  }
37826
37847
  continue;
37827
37848
  }
37828
- let resolvedActiveType = activeType;
37829
- if (!resolvedActiveType) {
37849
+ let resolvedActiveSessionId = activeSessionId;
37850
+ if (!resolvedActiveSessionId && parentSessionId) {
37830
37851
  try {
37831
37852
  const discovered = await cdp.discoverAgentWebviews();
37832
- if (discovered.length > 0) {
37833
- resolvedActiveType = discovered[0].agentType;
37834
- await agentStreamManager.switchActiveAgent(cdp, ideType, resolvedActiveType);
37835
- LOG.info("AgentStream", `Auto-activated: ${resolvedActiveType} (${ideType})`);
37853
+ for (const target of discovered) {
37854
+ const sessionId = agentStreamManager.resolveSessionForAgent(parentSessionId, target.agentType);
37855
+ if (sessionId) {
37856
+ resolvedActiveSessionId = sessionId;
37857
+ await agentStreamManager.setActiveSession(cdp, parentSessionId, sessionId);
37858
+ LOG.info("AgentStream", `Auto-activated: ${target.agentType} (${ideType})`);
37859
+ break;
37860
+ }
37836
37861
  }
37837
37862
  } catch {
37838
37863
  }
37839
37864
  }
37840
- if (!resolvedActiveType) continue;
37865
+ if (!resolvedActiveSessionId || !parentSessionId) continue;
37841
37866
  try {
37842
- await agentStreamManager.syncAgentSessions(cdp, ideType);
37843
- const streams = await agentStreamManager.collectAgentStreams(cdp, ideType);
37844
- this.deps.onStreamsUpdated?.(ideType, streams);
37867
+ await agentStreamManager.syncActiveSession(cdp, parentSessionId);
37868
+ const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
37869
+ this.deps.onStreamsUpdated?.(ideType, stream ? [stream] : []);
37845
37870
  } catch {
37846
37871
  }
37847
37872
  }
@@ -37952,6 +37977,7 @@ var init_provider_instance_manager = __esm({
37952
37977
  ...event,
37953
37978
  providerType: instance.type,
37954
37979
  instanceId: state.instanceId,
37980
+ targetSessionId: state.instanceId,
37955
37981
  providerCategory: state.category
37956
37982
  });
37957
37983
  }
@@ -41784,6 +41810,69 @@ var init_installer = __esm({
41784
41810
  }
41785
41811
  });
41786
41812
 
41813
+ // ../../oss/packages/daemon-core/src/sessions/registry.ts
41814
+ var SessionRegistry;
41815
+ var init_registry = __esm({
41816
+ "../../oss/packages/daemon-core/src/sessions/registry.ts"() {
41817
+ "use strict";
41818
+ SessionRegistry = class {
41819
+ bySessionId = /* @__PURE__ */ new Map();
41820
+ byManagerKey = /* @__PURE__ */ new Map();
41821
+ byInstanceKey = /* @__PURE__ */ new Map();
41822
+ byParentSessionId = /* @__PURE__ */ new Map();
41823
+ register(target) {
41824
+ this.unregister(target.sessionId);
41825
+ this.bySessionId.set(target.sessionId, target);
41826
+ if (target.cdpManagerKey) this.addIndex(this.byManagerKey, target.cdpManagerKey, target.sessionId);
41827
+ if (target.instanceKey) this.addIndex(this.byInstanceKey, target.instanceKey, target.sessionId);
41828
+ if (target.parentSessionId) this.addIndex(this.byParentSessionId, target.parentSessionId, target.sessionId);
41829
+ }
41830
+ get(sessionId) {
41831
+ if (!sessionId) return void 0;
41832
+ return this.bySessionId.get(sessionId);
41833
+ }
41834
+ unregister(sessionId) {
41835
+ if (!sessionId) return;
41836
+ const target = this.bySessionId.get(sessionId);
41837
+ if (!target) return;
41838
+ this.bySessionId.delete(sessionId);
41839
+ if (target.cdpManagerKey) this.removeIndex(this.byManagerKey, target.cdpManagerKey, sessionId);
41840
+ if (target.instanceKey) this.removeIndex(this.byInstanceKey, target.instanceKey, sessionId);
41841
+ if (target.parentSessionId) this.removeIndex(this.byParentSessionId, target.parentSessionId, sessionId);
41842
+ }
41843
+ unregisterByManagerKey(managerKey) {
41844
+ for (const sessionId of [...this.byManagerKey.get(managerKey) || []]) {
41845
+ this.unregister(sessionId);
41846
+ }
41847
+ }
41848
+ unregisterByInstanceKey(instanceKey) {
41849
+ for (const sessionId of [...this.byInstanceKey.get(instanceKey) || []]) {
41850
+ this.unregister(sessionId);
41851
+ }
41852
+ }
41853
+ listChildren(parentSessionId) {
41854
+ const ids = this.byParentSessionId.get(parentSessionId);
41855
+ if (!ids) return [];
41856
+ return [...ids].map((id) => this.bySessionId.get(id)).filter(Boolean);
41857
+ }
41858
+ addIndex(index, key, sessionId) {
41859
+ let set2 = index.get(key);
41860
+ if (!set2) {
41861
+ set2 = /* @__PURE__ */ new Set();
41862
+ index.set(key, set2);
41863
+ }
41864
+ set2.add(sessionId);
41865
+ }
41866
+ removeIndex(index, key, sessionId) {
41867
+ const set2 = index.get(key);
41868
+ if (!set2) return;
41869
+ set2.delete(sessionId);
41870
+ if (set2.size === 0) index.delete(key);
41871
+ }
41872
+ };
41873
+ }
41874
+ });
41875
+
41787
41876
  // ../../oss/packages/daemon-core/src/boot/daemon-lifecycle.ts
41788
41877
  async function initDaemonComponents(config2) {
41789
41878
  installGlobalInterceptor();
@@ -41821,11 +41910,14 @@ async function initDaemonComponents(config2) {
41821
41910
  });
41822
41911
  const instanceManager = new ProviderInstanceManager();
41823
41912
  const cdpManagers = /* @__PURE__ */ new Map();
41824
- const instanceIdMap = /* @__PURE__ */ new Map();
41913
+ const sessionRegistry = new SessionRegistry();
41825
41914
  const detectedIdesRef = { value: [] };
41915
+ let agentStreamManager = null;
41916
+ let poller = null;
41826
41917
  const cliManager = new DaemonCliManager({
41827
41918
  ...config2.cliManagerDeps,
41828
- getInstanceManager: () => instanceManager
41919
+ getInstanceManager: () => instanceManager,
41920
+ getSessionRegistry: () => sessionRegistry
41829
41921
  }, providerLoader);
41830
41922
  LOG.info("Init", "Detecting IDEs...");
41831
41923
  detectedIdesRef.value = await detectIDEs();
@@ -41835,7 +41927,7 @@ async function initDaemonComponents(config2) {
41835
41927
  providerLoader,
41836
41928
  instanceManager,
41837
41929
  cdpManagers,
41838
- instanceIdMap
41930
+ sessionRegistry
41839
41931
  };
41840
41932
  const cdpInitializer = new DaemonCdpInitializer({
41841
41933
  providerLoader,
@@ -41844,6 +41936,19 @@ async function initDaemonComponents(config2) {
41844
41936
  onConnected: async (ideType, manager, managerKey) => {
41845
41937
  await setupIdeInstance(cdpSetupContext, { ideType, manager, managerKey });
41846
41938
  await config2.onCdpManagerSetup?.(ideType, manager, managerKey);
41939
+ },
41940
+ onDisconnected: async (_ideType, _manager, managerKey) => {
41941
+ sessionRegistry.unregisterByManagerKey(managerKey);
41942
+ const instanceKey = `ide:${managerKey}`;
41943
+ const ideInstance = instanceManager.getInstance(instanceKey);
41944
+ if (ideInstance) {
41945
+ instanceManager.removeInstance(instanceKey);
41946
+ LOG.info("CDP", `Instance removed after disconnect: ${instanceKey}`);
41947
+ }
41948
+ if (ideInstance?.getInstanceId) {
41949
+ agentStreamManager?.resetParentSession(ideInstance.getInstanceId());
41950
+ }
41951
+ config2.onStatusChange?.();
41847
41952
  }
41848
41953
  });
41849
41954
  await cdpInitializer.connectAll(detectedIdesRef.value);
@@ -41855,14 +41960,14 @@ async function initDaemonComponents(config2) {
41855
41960
  adapters: cliManager.adapters,
41856
41961
  providerLoader,
41857
41962
  instanceManager,
41858
- instanceIdMap
41963
+ sessionRegistry
41859
41964
  });
41860
- const agentStreamManager = new DaemonAgentStreamManager(
41965
+ agentStreamManager = new DaemonAgentStreamManager(
41861
41966
  LOG.forComponent("AgentStream").asLogFn(),
41862
- providerLoader
41967
+ providerLoader,
41968
+ sessionRegistry
41863
41969
  );
41864
41970
  commandHandler.setAgentStreamManager(agentStreamManager);
41865
- let poller;
41866
41971
  const router = new DaemonCommandRouter({
41867
41972
  commandHandler,
41868
41973
  cliManager,
@@ -41870,7 +41975,7 @@ async function initDaemonComponents(config2) {
41870
41975
  providerLoader,
41871
41976
  instanceManager,
41872
41977
  detectedIdes: detectedIdesRef,
41873
- instanceIdMap,
41978
+ sessionRegistry,
41874
41979
  onCdpManagerCreated: async (ideType, manager) => {
41875
41980
  await setupIdeInstance(cdpSetupContext, { ideType, manager });
41876
41981
  await config2.onCdpManagerSetup?.(ideType, manager, ideType);
@@ -41885,6 +41990,7 @@ async function initDaemonComponents(config2) {
41885
41990
  providerLoader,
41886
41991
  instanceManager,
41887
41992
  cdpManagers,
41993
+ sessionRegistry,
41888
41994
  onStreamsUpdated: config2.onStreamsUpdated
41889
41995
  });
41890
41996
  poller.start();
@@ -41899,7 +42005,7 @@ async function initDaemonComponents(config2) {
41899
42005
  poller,
41900
42006
  cdpInitializer,
41901
42007
  cdpManagers,
41902
- instanceIdMap,
42008
+ sessionRegistry,
41903
42009
  detectedIdes: detectedIdesRef
41904
42010
  };
41905
42011
  }
@@ -41964,6 +42070,7 @@ var init_daemon_lifecycle = __esm({
41964
42070
  init_provider_instance_manager();
41965
42071
  init_dev_server();
41966
42072
  init_ide_detector();
42073
+ init_registry();
41967
42074
  init_logger();
41968
42075
  init_config();
41969
42076
  }
@@ -41994,10 +42101,7 @@ __export(src_exports, {
41994
42101
  ProviderLoader: () => ProviderLoader,
41995
42102
  VersionArchive: () => VersionArchive,
41996
42103
  addCliHistory: () => addCliHistory,
41997
- buildAllManagedEntries: () => buildAllManagedEntries,
41998
- buildManagedAcps: () => buildManagedAcps,
41999
- buildManagedClis: () => buildManagedClis,
42000
- buildManagedIdes: () => buildManagedIdes,
42104
+ buildSessionEntries: () => buildSessionEntries,
42001
42105
  buildStatusSnapshot: () => buildStatusSnapshot,
42002
42106
  connectCdpManager: () => connectCdpManager,
42003
42107
  detectAllVersions: () => detectAllVersions,
@@ -43391,7 +43495,7 @@ var init_adhdev_daemon = __esm({
43391
43495
  fs12 = __toESM(require("fs"));
43392
43496
  path14 = __toESM(require("path"));
43393
43497
  import_chalk2 = __toESM(require("chalk"));
43394
- pkgVersion = "0.6.79";
43498
+ pkgVersion = "0.7.0";
43395
43499
  if (pkgVersion === "unknown") {
43396
43500
  try {
43397
43501
  const possiblePaths = [
@@ -43669,7 +43773,7 @@ ${err?.stack || ""}`);
43669
43773
  });
43670
43774
  }
43671
43775
  async handleCommand(msg, cmd, args) {
43672
- LOG.info("Command", `${cmd}${args?._targetInstance ? ` \u2192 ${args._targetType}:${args._targetInstance.split("_")[0]}` : ""}`);
43776
+ LOG.info("Command", `${cmd}${args?.targetSessionId ? ` \u2192 session:${String(args.targetSessionId).split("_")[0]}` : ""}`);
43673
43777
  const cmdStart = Date.now();
43674
43778
  const source = msg.ipcWs ? "ext" : "ws";
43675
43779
  try {
@@ -43785,24 +43889,13 @@ ${err?.stack || ""}`);
43785
43889
  // ─── CDP helpers ─────────────────────────────
43786
43890
  /** Return CDP manager for specific IDE.
43787
43891
  * Lookup order:
43788
- * 1. instanceIdMap (UUID managerKey) for multi-window UUID instance IDs
43789
- * 2. Exact match on cdpManagers (key = "cursor", "antigravity")
43790
- * 3. Prefix match (multi-window: "antigravity_WorkspaceName")
43892
+ * 1. Exact match on cdpManagers (full manager key)
43893
+ * 2. Prefix match on cdpManagers (ideType_workspace)
43791
43894
  */
43792
43895
  getCdpFor(ideType) {
43793
43896
  if (!this.components) return null;
43794
43897
  const key = ideType.toLowerCase();
43795
- const mappedKey = this.components.instanceIdMap.get(ideType) || this.components.instanceIdMap.get(key);
43796
- if (mappedKey) {
43797
- const mapped = this.components.cdpManagers.get(mappedKey);
43798
- if (mapped?.isConnected) return mapped;
43799
- }
43800
- const exact = this.components.cdpManagers.get(key);
43801
- if (exact) return exact;
43802
- for (const [k, m] of this.components.cdpManagers.entries()) {
43803
- if (k.startsWith(key + "_") && m.isConnected) return m;
43804
- }
43805
- return null;
43898
+ return findCdpManager(this.components.cdpManagers, key);
43806
43899
  }
43807
43900
  };
43808
43901
  }