adhdev 0.5.2 → 0.5.3

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.
@@ -16514,7 +16514,7 @@ var require_dist = __commonJS({
16514
16514
  DaemonStatusReporter: () => DaemonStatusReporter2,
16515
16515
  DevServer: () => DevServer2,
16516
16516
  IdeProviderInstance: () => IdeProviderInstance,
16517
- LOG: () => LOG4,
16517
+ LOG: () => LOG5,
16518
16518
  ProviderCliAdapter: () => ProviderCliAdapter,
16519
16519
  ProviderInstanceManager: () => ProviderInstanceManager,
16520
16520
  ProviderLoader: () => ProviderLoader3,
@@ -16818,7 +16818,7 @@ var require_dist = __commonJS({
16818
16818
  origConsoleLog(line);
16819
16819
  }
16820
16820
  }
16821
- var LOG4 = {
16821
+ var LOG5 = {
16822
16822
  debug: (category, msg) => daemonLog(category, msg, "debug"),
16823
16823
  info: (category, msg) => daemonLog(category, msg, "info"),
16824
16824
  warn: (category, msg) => daemonLog(category, msg, "warn"),
@@ -16932,7 +16932,7 @@ var require_dist = __commonJS({
16932
16932
  this._targetId = targetId || null;
16933
16933
  this._targetFilter = targetFilter || {};
16934
16934
  this.logFn = logFn || ((msg) => {
16935
- LOG4.info("CDP", msg);
16935
+ LOG5.info("CDP", msg);
16936
16936
  });
16937
16937
  }
16938
16938
  /** Set target filter (can be updated after construction) */
@@ -17705,7 +17705,7 @@ var require_dist = __commonJS({
17705
17705
  } catch {
17706
17706
  }
17707
17707
  const result = await this.sendInternal("Page.captureScreenshot", {
17708
- format: "jpeg",
17708
+ format: "webp",
17709
17709
  quality,
17710
17710
  ...clip ? { clip } : {},
17711
17711
  optimizeForSpeed: true,
@@ -18402,14 +18402,14 @@ var require_dist = __commonJS({
18402
18402
  try {
18403
18403
  await ext.onTick();
18404
18404
  } catch (e) {
18405
- LOG4.warn("IdeInstance", `[IdeInstance:${this.type}] Extension ${id} tick error: ${e?.message}`);
18405
+ LOG5.warn("IdeInstance", `[IdeInstance:${this.type}] Extension ${id} tick error: ${e?.message}`);
18406
18406
  }
18407
18407
  }
18408
18408
  this.tickErrorCount = 0;
18409
18409
  } catch (e) {
18410
18410
  this.tickErrorCount++;
18411
18411
  if (this.tickErrorCount <= 3 || this.tickErrorCount % 10 === 0) {
18412
- LOG4.warn("IdeInstance", `[IdeInstance:${this.type}] onTick error (${this.tickErrorCount}): ${e?.message || e}`);
18412
+ LOG5.warn("IdeInstance", `[IdeInstance:${this.type}] onTick error (${this.tickErrorCount}): ${e?.message || e}`);
18413
18413
  }
18414
18414
  } finally {
18415
18415
  this.tickBusy = false;
@@ -18486,7 +18486,7 @@ var require_dist = __commonJS({
18486
18486
  });
18487
18487
  ext.onEvent("extension_connected", { ideType: this.type });
18488
18488
  this.extensions.set(provider2.type, ext);
18489
- LOG4.info("IdeInstance", `[IdeInstance:${this.type}] Extension added: ${provider2.type}`);
18489
+ LOG5.info("IdeInstance", `[IdeInstance:${this.type}] Extension added: ${provider2.type}`);
18490
18490
  }
18491
18491
  /** Extension Instance remove */
18492
18492
  removeExtension(type) {
@@ -18596,7 +18596,7 @@ var require_dist = __commonJS({
18596
18596
  const msg = e?.message || String(e);
18597
18597
  if (msg.includes("Timeout") || msg.includes("timeout") || msg.includes("Target closed")) {
18598
18598
  } else {
18599
- LOG4.warn("IdeInstance", `[IdeInstance:${this.type}] readChat internal error: ${msg}`);
18599
+ LOG5.warn("IdeInstance", `[IdeInstance:${this.type}] readChat internal error: ${msg}`);
18600
18600
  }
18601
18601
  }
18602
18602
  }
@@ -18791,7 +18791,7 @@ var require_dist = __commonJS({
18791
18791
  // ── Internal ────────────────────────────
18792
18792
  getLogFn(ideType) {
18793
18793
  if (this.opts.logFn) return this.opts.logFn(ideType);
18794
- return (msg) => LOG4.info(`CDP:${ideType}`, msg);
18794
+ return (msg) => LOG5.info(`CDP:${ideType}`, msg);
18795
18795
  }
18796
18796
  /**
18797
18797
  * Single-window connection (standalone mode).
@@ -18810,7 +18810,7 @@ var require_dist = __commonJS({
18810
18810
  if (!manager) return;
18811
18811
  registerExtensionProviders(this.ctx.providerLoader, manager, ide);
18812
18812
  this.ctx.cdpManagers.set(ide, manager);
18813
- LOG4.info("CDP", `Connected: ${ide} (port ${port})`);
18813
+ LOG5.info("CDP", `Connected: ${ide} (port ${port})`);
18814
18814
  await setupIdeInstance(this.ctx, { ideType: ide, manager });
18815
18815
  this.opts.onConnected?.(ide, ide, manager);
18816
18816
  }
@@ -18843,7 +18843,7 @@ var require_dist = __commonJS({
18843
18843
  );
18844
18844
  if (!manager) continue;
18845
18845
  this.ctx.cdpManagers.set(managerKey, manager);
18846
- LOG4.info("CDP", `Connected: ${managerKey} (port ${port}, page "${target.title}")`);
18846
+ LOG5.info("CDP", `Connected: ${managerKey} (port ${port}, page "${target.title}")`);
18847
18847
  await setupIdeInstance(this.ctx, {
18848
18848
  ideType: ide,
18849
18849
  manager,
@@ -18885,9 +18885,9 @@ var require_dist = __commonJS({
18885
18885
  await this.connectIdePort(port, ide);
18886
18886
  }
18887
18887
  if (cdpManagers.size > 0) {
18888
- LOG4.info("CDP", `${cdpManagers.size} IDE(s) connected: ${[...cdpManagers.entries()].map(([k, m]) => `${k}:${m.getPort()}`).join(", ")}`);
18888
+ LOG5.info("CDP", `${cdpManagers.size} IDE(s) connected: ${[...cdpManagers.entries()].map(([k, m]) => `${k}:${m.getPort()}`).join(", ")}`);
18889
18889
  } else {
18890
- LOG4.warn("CDP", `No IDEs connected \u2014 tried: ${filtered.map((p) => `${p.ide}:${p.port}`).join(", ")}`);
18890
+ LOG5.warn("CDP", `No IDEs connected \u2014 tried: ${filtered.map((p) => `${p.ide}:${p.port}`).join(", ")}`);
18891
18891
  }
18892
18892
  }
18893
18893
  // ─── Per-port connection (multi-window aware) ───
@@ -18903,7 +18903,7 @@ var require_dist = __commonJS({
18903
18903
  const provider2 = providerLoader.getMeta(ide);
18904
18904
  const manager = new DaemonCdpManager2(
18905
18905
  port,
18906
- LOG4.forComponent(`CDP:${ide}`).asLogFn(),
18906
+ LOG5.forComponent(`CDP:${ide}`).asLogFn(),
18907
18907
  void 0,
18908
18908
  provider2?.targetFilter
18909
18909
  );
@@ -18911,7 +18911,7 @@ var require_dist = __commonJS({
18911
18911
  if (connected) {
18912
18912
  registerExtensionProviders(providerLoader, manager, ide);
18913
18913
  cdpManagers.set(ide, manager);
18914
- LOG4.info("CDP", `Connected: ${ide} (port ${port})`);
18914
+ LOG5.info("CDP", `Connected: ${ide} (port ${port})`);
18915
18915
  await this.config.onConnected?.(ide, manager, ide);
18916
18916
  }
18917
18917
  return;
@@ -18929,7 +18929,7 @@ var require_dist = __commonJS({
18929
18929
  const provider2 = providerLoader.getMeta(ide);
18930
18930
  const manager = new DaemonCdpManager2(
18931
18931
  port,
18932
- LOG4.forComponent(`CDP:${managerKey}`).asLogFn(),
18932
+ LOG5.forComponent(`CDP:${managerKey}`).asLogFn(),
18933
18933
  target.id,
18934
18934
  provider2?.targetFilter
18935
18935
  );
@@ -18937,7 +18937,7 @@ var require_dist = __commonJS({
18937
18937
  if (connected) {
18938
18938
  registerExtensionProviders(providerLoader, manager, ide);
18939
18939
  cdpManagers.set(managerKey, manager);
18940
- LOG4.info("CDP", `Connected: ${managerKey} (port ${port}${targets.length > 1 ? `, page "${target.title}"` : ""})`);
18940
+ LOG5.info("CDP", `Connected: ${managerKey} (port ${port}${targets.length > 1 ? `, page "${target.title}"` : ""})`);
18941
18941
  await this.config.onConnected?.(ide, manager, managerKey);
18942
18942
  }
18943
18943
  }
@@ -18987,1475 +18987,1438 @@ var require_dist = __commonJS({
18987
18987
  }
18988
18988
  }
18989
18989
  };
18990
- var fs32 = __toESM2(require("fs"));
18991
- var path32 = __toESM2(require("path"));
18992
- var os4 = __toESM2(require("os"));
18993
18990
  init_config();
18994
- var DaemonCommandHandler = class {
18995
- ctx;
18996
- agentStream = null;
18997
- domHandlers;
18998
- /** Get CDP manager for a specific ideType.
18999
- * Returns null if no match never falls back to another IDE.
19000
- */
19001
- getCdp(ideType) {
19002
- const key = ideType || this._currentIdeType;
19003
- if (!key) {
19004
- return null;
19005
- }
19006
- const m = this.ctx.cdpManagers.get(key.toLowerCase());
19007
- if (m?.isConnected) return m;
19008
- return null;
19009
- }
19010
- /** Current IDE type extracted from command args (per-request) */
19011
- _currentIdeType;
19012
- /** Current provider type — agentType priority, ideType use */
19013
- _currentProviderType;
19014
- historyWriter;
19015
- /** Extract ideType from _targetInstance
19016
- * UUID-based: query directly from instanceIdMap
19017
- * Legacy: composite ID parsing ('doId:ide:uuid' → uuid → map lookup)
19018
- */
19019
- extractIdeType(args) {
19020
- if (args?._targetInstance) {
19021
- let raw = args._targetInstance;
19022
- const ideMatch = raw.match(/:ide:(.+)$/);
19023
- const cliMatch = raw.match(/:cli:(.+)$/);
19024
- const acpMatch = raw.match(/:acp:(.+)$/);
19025
- if (ideMatch) raw = ideMatch[1];
19026
- else if (cliMatch) raw = cliMatch[1];
19027
- else if (acpMatch) raw = acpMatch[1];
19028
- if (this.ctx.instanceIdMap?.has(raw)) {
19029
- return this.ctx.instanceIdMap.get(raw);
19030
- }
19031
- const lastUnderscore = raw.lastIndexOf("_");
19032
- if (lastUnderscore > 0) return raw.substring(0, lastUnderscore);
19033
- return raw;
19034
- }
19035
- return void 0;
19036
- }
19037
- constructor(ctx) {
19038
- this.ctx = ctx;
19039
- this.domHandlers = new CdpDomHandlers((ideType) => this.getCdp(ideType));
19040
- this.historyWriter = new ChatHistoryWriter();
19041
- }
19042
- /**
19043
- * Get provider module — _currentProviderType (agentType priority) use.
19044
- * Extension: agentType='cline' → provider.type='cline' (category=extension)
19045
- * CLI: ideType='gemini-cli' → provider.type='gemini-cli' (category=cli)
19046
- * IDE: ideType='cursor' → provider.type='cursor' (category=ide)
19047
- */
19048
- getProvider(overrideType) {
19049
- const key = overrideType || this._currentProviderType || this._currentIdeType;
19050
- if (!key || !this.ctx.providerLoader) return void 0;
19051
- const result = this.ctx.providerLoader.resolve(key);
19052
- if (result) return result;
19053
- const baseType = key.split("_")[0];
19054
- if (baseType !== key) return this.ctx.providerLoader.resolve(baseType);
19055
- return void 0;
19056
- }
19057
- /** Get a provider script by name from ProviderLoader.
19058
- * Returns the script string or null. */
19059
- getProviderScript(scriptName, params, ideType) {
19060
- const provider2 = this.getProvider(ideType);
19061
- if (provider2?.scripts) {
19062
- const fn = provider2.scripts[scriptName];
19063
- if (typeof fn === "function") {
19064
- const firstVal = params ? Object.values(params)[0] : void 0;
19065
- const script = firstVal ? fn(firstVal) : fn();
19066
- if (script) return script;
19067
- }
19068
- }
19069
- return null;
19070
- }
19071
- // ─── Category dispatch engine ───────────────────
19072
- /**
19073
- * Look up Extension provider webview session ID from AgentStreamManager.
19074
- * provider.type (e.g. 'cline') → ManagedAgent sessionId
19075
- */
19076
- getExtensionSessionId(provider2) {
19077
- if (provider2.category !== "extension" || !this.agentStream) return null;
19078
- const managed = this.agentStream.getManagedAgent(provider2.type);
19079
- return managed?.sessionId || null;
19080
- }
19081
- /**
19082
- * per-category CDP script execute:
19083
- * IDE → cdp.evaluate(script) (main window)
19084
- * Extension → cdp.evaluateInSession(sessionId, script) (webview)
19085
- * CLI → null (separate handling needed)
19086
- */
19087
- async evaluateProviderScript(scriptName, params, timeout = 3e4) {
19088
- const provider2 = this.getProvider();
19089
- const script = this.getProviderScript(scriptName, params);
19090
- if (!script) return null;
19091
- const cdp2 = this.getCdp();
19092
- if (!cdp2?.isConnected) return null;
19093
- if (provider2?.category === "extension") {
19094
- let sessionId = this.getExtensionSessionId(provider2);
19095
- if (!sessionId && this.agentStream) {
19096
- await this.agentStream.switchActiveAgent(cdp2, provider2.type);
19097
- await this.agentStream.syncAgentSessions(cdp2);
19098
- sessionId = this.getExtensionSessionId(provider2);
19099
- }
19100
- if (!sessionId) return null;
19101
- const result2 = await cdp2.evaluateInSession(sessionId, script, timeout);
19102
- return { result: result2, category: "extension" };
19103
- }
19104
- const result = await cdp2.evaluate(script, timeout);
19105
- return { result, category: provider2?.category || "ide" };
19106
- }
19107
- /**
19108
- * CLI adapter search: provider.type or agentTypeas match
19109
- */
19110
- getCliAdapter(type) {
19111
- const target = type || this._currentIdeType;
19112
- if (!target || !this.ctx.adapters) return null;
19113
- for (const [key, adapter] of this.ctx.adapters.entries()) {
19114
- if (adapter.cliType === target || key.startsWith(target)) {
19115
- return adapter;
19116
- }
19117
- }
19118
- return null;
19119
- }
19120
- setAgentStreamManager(manager) {
19121
- this.agentStream = manager;
18991
+ async function handleChatHistory(h, args) {
18992
+ const { agentType, offset, limit, instanceId } = args;
18993
+ try {
18994
+ const provider2 = h.getProvider(agentType);
18995
+ const agentStr = provider2?.type || agentType || h.currentIdeType || "";
18996
+ const result = readChatHistory2(agentStr, offset || 0, limit || 30, instanceId);
18997
+ return { success: true, ...result, agent: agentStr };
18998
+ } catch (e) {
18999
+ return { success: false, error: e.message };
19122
19000
  }
19123
- async handle(cmd, args) {
19124
- this._currentIdeType = this.extractIdeType(args);
19125
- this._currentProviderType = args?.agentType || args?.providerType || this._currentIdeType;
19126
- if (!this._currentIdeType && !this._currentProviderType) {
19127
- const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
19128
- if (cdpCommands.includes(cmd)) {
19129
- return { success: false, error: "No ideType specified \u2014 cannot route command" };
19130
- }
19131
- }
19132
- switch (cmd) {
19133
- // ─── CDP directly handle ───────────────────
19134
- case "read_chat":
19135
- return this.handleReadChat(args);
19136
- case "chat_history":
19137
- return this.handleChatHistory(args);
19138
- case "send_chat":
19139
- return this.handleSendChat(args);
19140
- case "list_chats":
19141
- return this.handleListChats(args);
19142
- case "new_chat":
19143
- return this.handleNewChat(args);
19144
- case "switch_chat":
19145
- return this.handleSwitchChat(args);
19146
- case "set_mode":
19147
- return this.handleSetMode(args);
19148
- case "change_model":
19149
- return this.handleChangeModel(args);
19150
- case "set_thought_level":
19151
- return this.handleSetThoughtLevel(args);
19152
- case "resolve_action":
19153
- return this.handleResolveAction(args);
19154
- case "cdp_eval":
19155
- return this.handleCdpEval(args);
19156
- case "cdp_screenshot":
19157
- case "screenshot":
19158
- return this.handleScreenshot(args);
19159
- case "cdp_command_exec":
19160
- return this.handleCdpCommand(args);
19161
- case "cdp_batch":
19162
- return this.handleCdpBatch(args);
19163
- case "cdp_remote_action":
19164
- return this.handleCdpRemoteAction(args);
19165
- case "cdp_discover_agents":
19166
- return this.handleDiscoverAgents(args);
19167
- case "cdp_dom_dump":
19168
- return this.domHandlers.handleDomDump(args);
19169
- case "cdp_dom_query":
19170
- return this.domHandlers.handleDomQuery(args);
19171
- case "cdp_dom_debug":
19172
- return this.domHandlers.handleDomDebug(args);
19173
- // ─── file directly handle ──────────────────
19174
- case "file_read":
19175
- return this.handleFileRead(args);
19176
- case "file_write":
19177
- return this.handleFileWrite(args);
19178
- case "file_list":
19179
- return this.handleFileList(args);
19180
- case "file_list_browse":
19181
- return this.handleFileListBrowse(args);
19182
- // ─── vscode API → Extension delegate ────
19183
- case "vscode_command_exec":
19184
- case "execute_vscode_command": {
19185
- const resolvedCmd = args?.commandId || args?.command;
19186
- if (resolvedCmd === "adhdev.captureCdpScreenshot") {
19187
- return this.handleScreenshot(args);
19188
- }
19189
- return this.delegateToExtension(resolvedCmd || cmd, args?.args);
19001
+ }
19002
+ async function handleReadChat(h, args) {
19003
+ const provider2 = h.getProvider();
19004
+ const _log = (msg) => LOG5.debug("Command", `[read_chat] ${msg}`);
19005
+ if (provider2?.category === "cli" || provider2?.category === "acp") {
19006
+ const adapter = h.getCliAdapter(provider2.type);
19007
+ if (adapter) {
19008
+ _log(`${provider2.category} adapter: ${adapter.cliType}`);
19009
+ const status = adapter.getStatus?.();
19010
+ if (status) {
19011
+ return { success: true, messages: status.messages || [], status: status.status, activeModal: status.activeModal };
19190
19012
  }
19191
- case "get_open_editors":
19192
- return this.delegateToExtension("adhdev.getOpenEditors", [args]);
19193
- case "open_tab":
19194
- return this.delegateToExtension("vscode.open", [args?.uri || args?.path]);
19195
- case "close_tab":
19196
- return this.delegateToExtension("workbench.action.closeActiveEditor", []);
19197
- case "open_folder":
19198
- return this.delegateToExtension("vscode.openFolder", [args?.path]);
19199
- case "open_folder_picker":
19200
- return this.delegateToExtension("workbench.action.files.openFolder", []);
19201
- case "open_recent":
19202
- return this.delegateToExtension("workbench.action.openRecent", []);
19203
- case "get_commands":
19204
- return this.delegateToExtension("adhdev.getCommands", []);
19205
- case "get_recent_workspaces":
19206
- return this.handleGetRecentWorkspaces(args);
19207
- // ─── script manage ───────────────────
19208
- case "refresh_scripts":
19209
- return this.handleRefreshScripts(args);
19210
- // ─── Agent Stream commands ───────────────
19211
- case "agent_stream_switch":
19212
- return this.handleAgentStreamSwitch(args);
19213
- case "agent_stream_read":
19214
- return this.handleAgentStreamRead(args);
19215
- case "agent_stream_send":
19216
- return this.handleAgentStreamSend(args);
19217
- case "agent_stream_resolve":
19218
- return this.handleAgentStreamResolve(args);
19219
- case "agent_stream_new":
19220
- return this.handleAgentStreamNew(args);
19221
- case "agent_stream_list_chats":
19222
- return this.handleAgentStreamListChats(args);
19223
- case "agent_stream_switch_session":
19224
- return this.handleAgentStreamSwitchSession(args);
19225
- case "agent_stream_focus":
19226
- return this.handleAgentStreamFocus(args);
19227
- // ─── PTY Raw I/O (terminal view) ─────────
19228
- case "pty_input":
19229
- return this.handlePtyInput(args);
19230
- case "pty_resize":
19231
- return this.handlePtyResize(args);
19232
- // ─── Provider Settings ──────────────
19233
- case "get_provider_settings":
19234
- return this.handleGetProviderSettings(args);
19235
- case "set_provider_setting":
19236
- return this.handleSetProviderSetting(args);
19237
- // ─── IDE Extension Settings (per-IDE on/off) ──────────────
19238
- case "get_ide_extensions":
19239
- return this.handleGetIdeExtensions(args);
19240
- case "set_ide_extension":
19241
- return this.handleSetIdeExtension(args);
19242
- // ─── Extension Model / Mode Control ──────────────
19243
- case "list_extension_models":
19244
- return await this.handleExtensionScript(args, "listModels");
19245
- case "set_extension_model":
19246
- return await this.handleExtensionScript(args, "setModel");
19247
- case "list_extension_modes":
19248
- return await this.handleExtensionScript(args, "listModes");
19249
- case "set_extension_mode":
19250
- return await this.handleExtensionScript(args, "setMode");
19251
- default:
19252
- return { success: false, error: `Unknown command: ${cmd}` };
19253
19013
  }
19014
+ return { success: false, error: `${provider2.category} adapter not found` };
19254
19015
  }
19255
- // ─── CDP-based chat commands ──────────────────────
19256
- async handleChatHistory(args) {
19257
- const { agentType, offset, limit, instanceId } = args;
19016
+ if (provider2?.category === "extension") {
19258
19017
  try {
19259
- const provider2 = this.getProvider(agentType);
19260
- const agentStr = provider2?.type || agentType || this._currentIdeType || "";
19261
- const result = readChatHistory2(agentStr, offset || 0, limit || 30, instanceId);
19262
- return { success: true, ...result, agent: agentStr };
19263
- } catch (e) {
19264
- return { success: false, error: e.message };
19265
- }
19266
- }
19267
- async handleReadChat(args) {
19268
- const provider2 = this.getProvider();
19269
- const _log = (msg) => LOG4.debug("Command", `[read_chat] ${msg}`);
19270
- if (provider2?.category === "cli" || provider2?.category === "acp") {
19271
- const adapter = this.getCliAdapter(provider2.type);
19272
- if (adapter) {
19273
- _log(`${provider2.category} adapter: ${adapter.cliType}`);
19274
- const status = adapter.getStatus?.();
19275
- if (status) {
19276
- return { success: true, messages: status.messages || [], status: status.status, activeModal: status.activeModal };
19277
- }
19278
- }
19279
- return { success: false, error: `${provider2.category} adapter not found` };
19280
- }
19281
- if (provider2?.category === "extension") {
19282
- try {
19283
- const evalResult = await this.evaluateProviderScript("readChat", void 0, 5e4);
19284
- if (evalResult?.result) {
19285
- let parsed = evalResult.result;
19286
- if (typeof parsed === "string") {
19287
- try {
19288
- parsed = JSON.parse(parsed);
19289
- } catch {
19290
- }
19291
- }
19292
- if (parsed && typeof parsed === "object") {
19293
- _log(`Extension OK: ${parsed.messages?.length || 0} msgs`);
19294
- this.historyWriter.appendNewMessages(
19295
- provider2.type || "unknown_extension",
19296
- parsed.messages || [],
19297
- parsed.title,
19298
- args?.instanceId
19299
- );
19300
- return { success: true, ...parsed };
19018
+ const evalResult = await h.evaluateProviderScript("readChat", void 0, 5e4);
19019
+ if (evalResult?.result) {
19020
+ let parsed = evalResult.result;
19021
+ if (typeof parsed === "string") {
19022
+ try {
19023
+ parsed = JSON.parse(parsed);
19024
+ } catch {
19301
19025
  }
19302
19026
  }
19303
- } catch (e) {
19304
- _log(`Extension error: ${e.message}`);
19305
- }
19306
- if (this.agentStream) {
19307
- const cdp22 = this.getCdp();
19308
- if (cdp22) {
19309
- const streams = await this.agentStream.collectAgentStreams(cdp22);
19310
- const stream = streams.find((s) => s.agentType === provider2.type);
19311
- if (stream) {
19312
- this.historyWriter.appendNewMessages(
19313
- stream.agentType,
19314
- stream.messages || [],
19315
- void 0,
19316
- args?.instanceId
19317
- );
19318
- return { success: true, messages: stream.messages || [], status: stream.status, agentType: stream.agentType };
19319
- }
19027
+ if (parsed && typeof parsed === "object") {
19028
+ _log(`Extension OK: ${parsed.messages?.length || 0} msgs`);
19029
+ h.historyWriter.appendNewMessages(
19030
+ provider2.type || "unknown_extension",
19031
+ parsed.messages || [],
19032
+ parsed.title,
19033
+ args?.instanceId
19034
+ );
19035
+ return { success: true, ...parsed };
19320
19036
  }
19321
19037
  }
19322
- return { success: true, messages: [], status: "idle" };
19323
- }
19324
- const cdp2 = this.getCdp();
19325
- if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
19326
- const webviewScript = this.getProviderScript("webviewReadChat") || this.getProviderScript("webview_read_chat");
19327
- if (webviewScript) {
19328
- try {
19329
- const matchText = provider2?.webviewMatchText;
19330
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19331
- const raw = await cdp2.evaluateInWebviewFrame(webviewScript, matchFn);
19332
- if (raw) {
19333
- let parsed = raw;
19334
- if (typeof parsed === "string") {
19335
- try {
19336
- parsed = JSON.parse(parsed);
19337
- } catch {
19338
- }
19339
- }
19340
- if (parsed && typeof parsed === "object") {
19341
- _log(`Webview OK: ${parsed.messages?.length || 0} msgs`);
19342
- this.historyWriter.appendNewMessages(
19343
- provider2?.type || this._currentIdeType || "unknown_webview",
19344
- parsed.messages || [],
19345
- parsed.title,
19346
- args?.instanceId
19347
- );
19348
- return { success: true, ...parsed };
19349
- }
19038
+ } catch (e) {
19039
+ _log(`Extension error: ${e.message}`);
19040
+ }
19041
+ if (h.agentStream) {
19042
+ const cdp22 = h.getCdp();
19043
+ if (cdp22) {
19044
+ const streams = await h.agentStream.collectAgentStreams(cdp22);
19045
+ const stream = streams.find((s) => s.agentType === provider2.type);
19046
+ if (stream) {
19047
+ h.historyWriter.appendNewMessages(
19048
+ stream.agentType,
19049
+ stream.messages || [],
19050
+ void 0,
19051
+ args?.instanceId
19052
+ );
19053
+ return { success: true, messages: stream.messages || [], status: stream.status, agentType: stream.agentType };
19350
19054
  }
19351
- } catch (e) {
19352
- _log(`Webview readChat error: ${e.message}`);
19353
19055
  }
19354
- return { success: true, messages: [], status: "idle" };
19355
19056
  }
19356
- const script = this.getProviderScript("readChat") || this.getProviderScript("read_chat");
19357
- if (script) {
19358
- try {
19359
- const result = await cdp2.evaluate(script, 5e4);
19360
- let parsed = result;
19057
+ return { success: true, messages: [], status: "idle" };
19058
+ }
19059
+ const cdp2 = h.getCdp();
19060
+ if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
19061
+ const webviewScript = h.getProviderScript("webviewReadChat") || h.getProviderScript("webview_read_chat");
19062
+ if (webviewScript) {
19063
+ try {
19064
+ const matchText = provider2?.webviewMatchText;
19065
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19066
+ const raw = await cdp2.evaluateInWebviewFrame(webviewScript, matchFn);
19067
+ if (raw) {
19068
+ let parsed = raw;
19361
19069
  if (typeof parsed === "string") {
19362
19070
  try {
19363
19071
  parsed = JSON.parse(parsed);
19364
19072
  } catch {
19365
19073
  }
19366
19074
  }
19367
- if (parsed && typeof parsed === "object" && parsed.messages?.length > 0) {
19368
- _log(`OK: ${parsed.messages?.length} msgs`);
19369
- this.historyWriter.appendNewMessages(
19370
- provider2?.type || this._currentIdeType || "unknown_ide",
19075
+ if (parsed && typeof parsed === "object") {
19076
+ _log(`Webview OK: ${parsed.messages?.length || 0} msgs`);
19077
+ h.historyWriter.appendNewMessages(
19078
+ provider2?.type || h.currentIdeType || "unknown_webview",
19371
19079
  parsed.messages || [],
19372
19080
  parsed.title,
19373
19081
  args?.instanceId
19374
19082
  );
19375
19083
  return { success: true, ...parsed };
19376
19084
  }
19377
- } catch (e) {
19378
- LOG4.info("Command", `[read_chat] Script error: ${e.message}`);
19379
19085
  }
19086
+ } catch (e) {
19087
+ _log(`Webview readChat error: ${e.message}`);
19380
19088
  }
19381
19089
  return { success: true, messages: [], status: "idle" };
19382
19090
  }
19383
- async handleSendChat(args) {
19384
- const text = args?.text || args?.message;
19385
- if (!text) return { success: false, error: "text required" };
19386
- const _log = (msg) => LOG4.debug("Command", `[send_chat] ${msg}`);
19387
- const provider2 = this.getProvider();
19388
- if (provider2?.category === "cli" || provider2?.category === "acp") {
19389
- const adapter = this.getCliAdapter(provider2.type);
19390
- if (adapter) {
19391
- _log(`${provider2.category} adapter: ${adapter.cliType}`);
19091
+ const script = h.getProviderScript("readChat") || h.getProviderScript("read_chat");
19092
+ if (script) {
19093
+ try {
19094
+ const result = await cdp2.evaluate(script, 5e4);
19095
+ let parsed = result;
19096
+ if (typeof parsed === "string") {
19392
19097
  try {
19393
- await adapter.sendMessage(text);
19394
- return { success: true, sent: true, method: `${provider2.category}-adapter`, targetAgent: adapter.cliType };
19395
- } catch (e) {
19396
- return { success: false, error: `${provider2.category} send failed: ${e.message}` };
19397
- }
19398
- }
19399
- }
19400
- if (provider2?.category === "extension") {
19401
- _log(`Extension: ${provider2.type}`);
19402
- try {
19403
- const evalResult = await this.evaluateProviderScript("sendMessage", { MESSAGE: text }, 3e4);
19404
- if (evalResult?.result) {
19405
- let parsed = evalResult.result;
19406
- if (typeof parsed === "string") {
19407
- try {
19408
- parsed = JSON.parse(parsed);
19409
- } catch {
19410
- }
19411
- }
19412
- if (parsed?.sent) {
19413
- _log(`Extension script sent OK`);
19414
- return { success: true, sent: true, method: "extension-script" };
19415
- }
19416
- if (parsed?.needsTypeAndSend) {
19417
- _log(`Extension needsTypeAndSend \u2192 AgentStreamManager`);
19418
- }
19419
- }
19420
- } catch (e) {
19421
- _log(`Extension script error: ${e.message}`);
19422
- }
19423
- if (this.agentStream && this.getCdp()) {
19424
- const ok = await this.agentStream.sendToAgent(this.getCdp(), provider2.type, text, this._currentIdeType);
19425
- if (ok) {
19426
- _log(`AgentStreamManager sent OK`);
19427
- return { success: true, sent: true, method: "agent-stream" };
19428
- }
19429
- }
19430
- return { success: false, error: `Extension '${provider2.type}' send failed` };
19431
- }
19432
- const targetCdp = this.getCdp();
19433
- if (!targetCdp?.isConnected) {
19434
- _log(`No CDP for ${this._currentIdeType}`);
19435
- return { success: false, error: `CDP for ${this._currentIdeType || "unknown"} not connected` };
19436
- }
19437
- _log(`Targeting IDE: ${this._currentIdeType}`);
19438
- if (provider2?.webviewMatchText && provider2?.scripts?.webviewSendMessage) {
19439
- try {
19440
- const webviewScript = provider2.scripts.webviewSendMessage(text);
19441
- if (webviewScript && targetCdp.evaluateInWebviewFrame) {
19442
- const matchText = provider2.webviewMatchText;
19443
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19444
- const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
19445
- let wvParsed = wvResult;
19446
- if (typeof wvResult === "string") {
19447
- try {
19448
- wvParsed = JSON.parse(wvResult);
19449
- } catch {
19450
- }
19451
- }
19452
- if (wvParsed?.sent) {
19453
- _log(`webviewSendMessage (priority) OK`);
19454
- return { success: true, sent: true, method: "webview-script-priority" };
19455
- }
19456
- _log(`webviewSendMessage (priority) did not confirm sent, falling through`);
19457
- }
19458
- } catch (e) {
19459
- _log(`webviewSendMessage (priority) failed: ${e.message}, falling through`);
19460
- }
19461
- }
19462
- if (provider2?.inputMethod === "cdp-type-and-send" && provider2.inputSelector) {
19463
- try {
19464
- const sent = await targetCdp.typeAndSend(provider2.inputSelector, text);
19465
- if (sent) {
19466
- _log(`typeAndSend(provider.inputSelector=${provider2.inputSelector}) success`);
19467
- return { success: true, sent: true, method: "typeAndSend-provider" };
19468
- }
19469
- } catch (e) {
19470
- _log(`typeAndSend(provider) failed: ${e.message}`);
19471
- }
19472
- }
19473
- const sendScript = this.getProviderScript("sendMessage", { MESSAGE: text });
19474
- if (sendScript) {
19475
- try {
19476
- const result = await targetCdp.evaluate(sendScript, 3e4);
19477
- let parsed = result;
19478
- if (typeof result === "string") {
19479
- try {
19480
- parsed = JSON.parse(result);
19481
- } catch {
19482
- }
19483
- }
19484
- if (parsed?.sent) {
19485
- _log(`sendMessage script OK`);
19486
- return { success: true, sent: true, method: "script" };
19487
- }
19488
- if (parsed?.needsTypeAndSend && parsed?.selector) {
19489
- try {
19490
- const sent = await targetCdp.typeAndSend(parsed.selector, text);
19491
- if (sent) {
19492
- _log(`typeAndSend(script.selector=${parsed.selector}) success`);
19493
- return { success: true, sent: true, method: "typeAndSend-script" };
19494
- }
19495
- } catch (e) {
19496
- _log(`typeAndSend(script.selector) failed: ${e.message}`);
19497
- }
19498
- }
19499
- if (parsed?.needsTypeAndSend && provider2?.scripts?.webviewSendMessage) {
19500
- try {
19501
- const webviewScript = provider2.scripts.webviewSendMessage(text);
19502
- if (webviewScript && targetCdp.evaluateInWebviewFrame) {
19503
- const matchText = provider2.webviewMatchText;
19504
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19505
- const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
19506
- let wvParsed = wvResult;
19507
- if (typeof wvResult === "string") {
19508
- try {
19509
- wvParsed = JSON.parse(wvResult);
19510
- } catch {
19511
- }
19512
- }
19513
- if (wvParsed?.sent) {
19514
- _log(`webviewSendMessage OK`);
19515
- return { success: true, sent: true, method: "webview-script" };
19516
- }
19517
- }
19518
- } catch (e) {
19519
- _log(`webviewSendMessage failed: ${e.message}`);
19520
- }
19521
- }
19522
- if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
19523
- try {
19524
- const { x, y } = parsed.clickCoords;
19525
- const sent = await targetCdp.typeAndSendAt(x, y, text);
19526
- if (sent) {
19527
- _log(`typeAndSendAt(${x},${y}) success`);
19528
- return { success: true, sent: true, method: "typeAndSendAt-script" };
19529
- }
19530
- } catch (e) {
19531
- _log(`typeAndSendAt failed: ${e.message}`);
19532
- }
19098
+ parsed = JSON.parse(parsed);
19099
+ } catch {
19533
19100
  }
19534
- } catch (e) {
19535
- _log(`sendMessage script failed: ${e.message}`);
19536
19101
  }
19102
+ if (parsed && typeof parsed === "object" && parsed.messages?.length > 0) {
19103
+ _log(`OK: ${parsed.messages?.length} msgs`);
19104
+ h.historyWriter.appendNewMessages(
19105
+ provider2?.type || h.currentIdeType || "unknown_ide",
19106
+ parsed.messages || [],
19107
+ parsed.title,
19108
+ args?.instanceId
19109
+ );
19110
+ return { success: true, ...parsed };
19111
+ }
19112
+ } catch (e) {
19113
+ LOG5.info("Command", `[read_chat] Script error: ${e.message}`);
19537
19114
  }
19538
- _log("All methods failed");
19539
- return { success: false, error: "No provider method could send the message" };
19540
19115
  }
19541
- async handleListChats(args) {
19542
- const provider2 = this.getProvider();
19543
- if (provider2?.category === "extension" && this.agentStream && this.getCdp()) {
19116
+ return { success: true, messages: [], status: "idle" };
19117
+ }
19118
+ async function handleSendChat(h, args) {
19119
+ const text = args?.text || args?.message;
19120
+ if (!text) return { success: false, error: "text required" };
19121
+ const _log = (msg) => LOG5.debug("Command", `[send_chat] ${msg}`);
19122
+ const provider2 = h.getProvider();
19123
+ if (provider2?.category === "cli" || provider2?.category === "acp") {
19124
+ const adapter = h.getCliAdapter(provider2.type);
19125
+ if (adapter) {
19126
+ _log(`${provider2.category} adapter: ${adapter.cliType}`);
19544
19127
  try {
19545
- const chats = await this.agentStream.listAgentChats(this.getCdp(), provider2.type);
19546
- LOG4.info("Command", `[list_chats] Extension: ${chats.length} chats`);
19547
- return { success: true, chats };
19128
+ await adapter.sendMessage(text);
19129
+ return { success: true, sent: true, method: `${provider2.category}-adapter`, targetAgent: adapter.cliType };
19548
19130
  } catch (e) {
19549
- LOG4.info("Command", `[list_chats] Extension error: ${e.message}`);
19131
+ return { success: false, error: `${provider2.category} send failed: ${e.message}` };
19550
19132
  }
19551
19133
  }
19134
+ }
19135
+ if (provider2?.category === "extension") {
19136
+ _log(`Extension: ${provider2.type}`);
19552
19137
  try {
19553
- const webviewScript = this.getProviderScript("webviewListSessions") || this.getProviderScript("webview_list_sessions");
19554
- if (webviewScript) {
19555
- const matchText = provider2?.webviewMatchText;
19556
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19557
- const raw = await this.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
19558
- let parsed = raw;
19138
+ const evalResult = await h.evaluateProviderScript("sendMessage", { MESSAGE: text }, 3e4);
19139
+ if (evalResult?.result) {
19140
+ let parsed = evalResult.result;
19559
19141
  if (typeof parsed === "string") {
19560
19142
  try {
19561
19143
  parsed = JSON.parse(parsed);
19562
19144
  } catch {
19563
19145
  }
19564
19146
  }
19565
- if (parsed?.sessions) {
19566
- LOG4.info("Command", `[list_chats] Webview OK: ${parsed.sessions.length} chats`);
19567
- return { success: true, chats: parsed.sessions };
19147
+ if (parsed?.sent) {
19148
+ _log(`Extension script sent OK`);
19149
+ return { success: true, sent: true, method: "extension-script" };
19150
+ }
19151
+ if (parsed?.needsTypeAndSend) {
19152
+ _log(`Extension needsTypeAndSend \u2192 AgentStreamManager`);
19568
19153
  }
19569
19154
  }
19570
19155
  } catch (e) {
19571
- LOG4.info("Command", `[list_chats] Webview error: ${e.message}`);
19156
+ _log(`Extension script error: ${e.message}`);
19157
+ }
19158
+ if (h.agentStream && h.getCdp()) {
19159
+ const ok = await h.agentStream.sendToAgent(h.getCdp(), provider2.type, text, h.currentIdeType);
19160
+ if (ok) {
19161
+ _log(`AgentStreamManager sent OK`);
19162
+ return { success: true, sent: true, method: "agent-stream" };
19163
+ }
19572
19164
  }
19165
+ return { success: false, error: `Extension '${provider2.type}' send failed` };
19166
+ }
19167
+ const targetCdp = h.getCdp();
19168
+ if (!targetCdp?.isConnected) {
19169
+ _log(`No CDP for ${h.currentIdeType}`);
19170
+ return { success: false, error: `CDP for ${h.currentIdeType || "unknown"} not connected` };
19171
+ }
19172
+ _log(`Targeting IDE: ${h.currentIdeType}`);
19173
+ if (provider2?.webviewMatchText && provider2?.scripts?.webviewSendMessage) {
19573
19174
  try {
19574
- const evalResult = await this.evaluateProviderScript("listSessions");
19575
- if (evalResult) {
19576
- let parsed = evalResult.result;
19577
- if (typeof parsed === "string") {
19175
+ const webviewScript = provider2.scripts.webviewSendMessage(text);
19176
+ if (webviewScript && targetCdp.evaluateInWebviewFrame) {
19177
+ const matchText = provider2.webviewMatchText;
19178
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19179
+ const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
19180
+ let wvParsed = wvResult;
19181
+ if (typeof wvResult === "string") {
19578
19182
  try {
19579
- parsed = JSON.parse(parsed);
19183
+ wvParsed = JSON.parse(wvResult);
19580
19184
  } catch {
19581
19185
  }
19582
19186
  }
19583
- if (Array.isArray(parsed)) {
19584
- LOG4.info("Command", `[list_chats] OK: ${parsed.length} chats`);
19585
- return { success: true, chats: parsed };
19187
+ if (wvParsed?.sent) {
19188
+ _log(`webviewSendMessage (priority) OK`);
19189
+ return { success: true, sent: true, method: "webview-script-priority" };
19586
19190
  }
19191
+ _log(`webviewSendMessage (priority) did not confirm sent, falling through`);
19587
19192
  }
19588
19193
  } catch (e) {
19589
- LOG4.info("Command", `[list_chats] error: ${e.message}`);
19194
+ _log(`webviewSendMessage (priority) failed: ${e.message}, falling through`);
19590
19195
  }
19591
- return { success: false, error: "listSessions script not available for this provider" };
19592
19196
  }
19593
- async handleNewChat(args) {
19594
- const provider2 = this.getProvider();
19595
- if (provider2?.category === "extension" && this.agentStream && this.getCdp()) {
19596
- const ok = await this.agentStream.newAgentSession(this.getCdp(), provider2.type, this._currentIdeType);
19597
- return { success: ok };
19598
- }
19197
+ if (provider2?.inputMethod === "cdp-type-and-send" && provider2.inputSelector) {
19599
19198
  try {
19600
- const webviewScript = this.getProviderScript("webviewNewSession") || this.getProviderScript("webview_new_session");
19601
- if (webviewScript) {
19602
- const matchText = provider2?.webviewMatchText;
19603
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19604
- const raw = await this.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
19605
- if (raw) return { success: true, result: raw };
19199
+ const sent = await targetCdp.typeAndSend(provider2.inputSelector, text);
19200
+ if (sent) {
19201
+ _log(`typeAndSend(provider.inputSelector=${provider2.inputSelector}) success`);
19202
+ return { success: true, sent: true, method: "typeAndSend-provider" };
19606
19203
  }
19607
19204
  } catch (e) {
19608
- return { success: false, error: `webviewNewSession failed: ${e.message}` };
19609
- }
19610
- try {
19611
- const evalResult = await this.evaluateProviderScript("newSession");
19612
- if (evalResult) return { success: true };
19613
- } catch (e) {
19614
- return { success: false, error: `newSession failed: ${e.message}` };
19205
+ _log(`typeAndSend(provider) failed: ${e.message}`);
19615
19206
  }
19616
- return { success: false, error: "newSession script not available for this provider" };
19617
19207
  }
19618
- async handleSwitchChat(args) {
19619
- const provider2 = this.getProvider();
19620
- const ideType = this._currentIdeType;
19621
- const sessionId = args?.sessionId || args?.id || args?.chatId;
19622
- if (!sessionId) return { success: false, error: "sessionId required" };
19623
- LOG4.info("Command", `[switch_chat] sessionId=${sessionId}, ideType=${ideType}`);
19624
- if (provider2?.category === "extension" && this.agentStream && this.getCdp()) {
19625
- const ok = await this.agentStream.switchAgentSession(this.getCdp(), provider2.type, sessionId);
19626
- return { success: ok, result: ok ? "switched" : "failed" };
19627
- }
19628
- const cdp2 = this.getCdp(ideType);
19629
- if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
19630
- try {
19631
- const webviewScript = this.getProviderScript("webviewSwitchSession", { SESSION_ID: JSON.stringify(sessionId) });
19632
- if (webviewScript) {
19633
- const matchText = provider2?.webviewMatchText;
19634
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19635
- const raw = await cdp2.evaluateInWebviewFrame?.(webviewScript, matchFn);
19636
- if (raw) return { success: true, result: raw };
19637
- }
19638
- } catch (e) {
19639
- return { success: false, error: `webviewSwitchSession failed: ${e.message}` };
19640
- }
19641
- const script = this.getProviderScript("switchSession", { SESSION_ID: JSON.stringify(sessionId) }) || this.getProviderScript("switch_session", { SESSION_ID: JSON.stringify(sessionId) });
19642
- if (!script) return { success: false, error: "switch_session script not available" };
19208
+ const sendScript = h.getProviderScript("sendMessage", { MESSAGE: text });
19209
+ if (sendScript) {
19643
19210
  try {
19644
- const raw = await cdp2.evaluate(script, 15e3);
19645
- LOG4.info("Command", `[switch_chat] result: ${raw}`);
19646
- let parsed = null;
19647
- try {
19648
- parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
19649
- } catch {
19650
- }
19651
- if (parsed?.action === "click" && parsed.clickX && parsed.clickY) {
19652
- const x = Math.round(parsed.clickX);
19653
- const y = Math.round(parsed.clickY);
19654
- LOG4.info("Command", `[switch_chat] CDP click at (${x}, ${y}) for "${parsed.title}"`);
19655
- await cdp2.send("Input.dispatchMouseEvent", {
19656
- type: "mousePressed",
19657
- x,
19658
- y,
19659
- button: "left",
19660
- clickCount: 1
19661
- });
19662
- await cdp2.send("Input.dispatchMouseEvent", {
19663
- type: "mouseReleased",
19664
- x,
19665
- y,
19666
- button: "left",
19667
- clickCount: 1
19668
- });
19669
- await new Promise((r) => setTimeout(r, 2e3));
19670
- const wsResult = await cdp2.evaluate(`
19671
- (() => {
19672
- const inp = Array.from(document.querySelectorAll('input[type="text"]'))
19673
- .find(i => i.offsetWidth > 0 && (i.placeholder || '').includes('Select where'));
19674
- if (!inp) return null;
19675
- const rows = inp.closest('[class*="quickInput"]')?.querySelectorAll('[class*="cursor-pointer"]');
19676
- if (rows && rows.length > 0) {
19677
- const r = rows[0].getBoundingClientRect();
19678
- return JSON.stringify({ x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) });
19679
- }
19680
- return null;
19681
- })()
19682
- `, 5e3);
19683
- if (wsResult) {
19684
- try {
19685
- const ws = JSON.parse(wsResult);
19686
- await cdp2.send("Input.dispatchMouseEvent", {
19687
- type: "mousePressed",
19688
- x: ws.x,
19689
- y: ws.y,
19690
- button: "left",
19691
- clickCount: 1
19692
- });
19693
- await cdp2.send("Input.dispatchMouseEvent", {
19694
- type: "mouseReleased",
19695
- x: ws.x,
19696
- y: ws.y,
19697
- button: "left",
19698
- clickCount: 1
19699
- });
19700
- } catch {
19701
- }
19211
+ const result = await targetCdp.evaluate(sendScript, 3e4);
19212
+ let parsed = result;
19213
+ if (typeof result === "string") {
19214
+ try {
19215
+ parsed = JSON.parse(result);
19216
+ } catch {
19702
19217
  }
19703
- return { success: true, result: "switched" };
19704
19218
  }
19705
- if (parsed?.error) {
19706
- return { success: false, error: parsed.error };
19219
+ if (parsed?.sent) {
19220
+ _log(`sendMessage script OK`);
19221
+ return { success: true, sent: true, method: "script" };
19707
19222
  }
19708
- return { success: true, result: raw };
19709
- } catch (e) {
19710
- LOG4.error("Command", `[switch_chat] error: ${e.message}`);
19711
- return { success: false, error: e.message };
19712
- }
19713
- }
19714
- async handleSetMode(args) {
19715
- const provider2 = this.getProvider();
19716
- const mode = args?.mode || "agent";
19717
- if (provider2?.category === "acp") {
19718
- const adapter = this.getCliAdapter(provider2.type);
19719
- if (adapter) {
19720
- const acpInstance = adapter._acpInstance;
19721
- if (acpInstance && typeof acpInstance.onEvent === "function") {
19722
- acpInstance.onEvent("set_mode", { mode });
19723
- return { success: true, mode };
19223
+ if (parsed?.needsTypeAndSend && parsed?.selector) {
19224
+ try {
19225
+ const sent = await targetCdp.typeAndSend(parsed.selector, text);
19226
+ if (sent) {
19227
+ _log(`typeAndSend(script.selector=${parsed.selector}) success`);
19228
+ return { success: true, sent: true, method: "typeAndSend-script" };
19229
+ }
19230
+ } catch (e) {
19231
+ _log(`typeAndSend(script.selector) failed: ${e.message}`);
19724
19232
  }
19725
19233
  }
19726
- return { success: false, error: "ACP adapter not found" };
19727
- }
19728
- const webviewScript = this.getProviderScript("webviewSetMode", { MODE: JSON.stringify(mode) });
19729
- if (webviewScript) {
19730
- const cdp2 = this.getCdp();
19731
- if (cdp2?.isConnected) {
19234
+ if (parsed?.needsTypeAndSend && provider2?.scripts?.webviewSendMessage) {
19732
19235
  try {
19733
- const matchText = provider2?.webviewMatchText;
19734
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19735
- const raw = await cdp2.evaluateInWebviewFrame?.(webviewScript, matchFn);
19736
- let result = raw;
19737
- if (typeof raw === "string") {
19738
- try {
19739
- result = JSON.parse(raw);
19740
- } catch {
19236
+ const webviewScript = provider2.scripts.webviewSendMessage(text);
19237
+ if (webviewScript && targetCdp.evaluateInWebviewFrame) {
19238
+ const matchText = provider2.webviewMatchText;
19239
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19240
+ const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
19241
+ let wvParsed = wvResult;
19242
+ if (typeof wvResult === "string") {
19243
+ try {
19244
+ wvParsed = JSON.parse(wvResult);
19245
+ } catch {
19246
+ }
19247
+ }
19248
+ if (wvParsed?.sent) {
19249
+ _log(`webviewSendMessage OK`);
19250
+ return { success: true, sent: true, method: "webview-script" };
19741
19251
  }
19742
19252
  }
19743
- if (result?.success) return { success: true, mode, method: "webview-script" };
19744
19253
  } catch (e) {
19745
- LOG4.info("Command", `[set_mode] webview script error: ${e.message}`);
19254
+ _log(`webviewSendMessage failed: ${e.message}`);
19746
19255
  }
19747
19256
  }
19748
- }
19749
- const mainScript = this.getProviderScript("setMode", { MODE: JSON.stringify(mode) });
19750
- if (mainScript) {
19751
- try {
19752
- const evalResult = await this.evaluateProviderScript("setMode", { MODE: JSON.stringify(mode) }, 15e3);
19753
- if (evalResult?.result) {
19754
- let parsed = evalResult.result;
19755
- if (typeof parsed === "string") {
19756
- try {
19757
- parsed = JSON.parse(parsed);
19758
- } catch {
19759
- }
19257
+ if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
19258
+ try {
19259
+ const { x, y } = parsed.clickCoords;
19260
+ const sent = await targetCdp.typeAndSendAt(x, y, text);
19261
+ if (sent) {
19262
+ _log(`typeAndSendAt(${x},${y}) success`);
19263
+ return { success: true, sent: true, method: "typeAndSendAt-script" };
19760
19264
  }
19761
- if (parsed?.success) return { success: true, mode, method: "script" };
19265
+ } catch (e) {
19266
+ _log(`typeAndSendAt failed: ${e.message}`);
19762
19267
  }
19763
- } catch (e) {
19764
- LOG4.info("Command", `[set_mode] script error: ${e.message}`);
19765
19268
  }
19269
+ } catch (e) {
19270
+ _log(`sendMessage script failed: ${e.message}`);
19766
19271
  }
19767
- return this.delegateToExtension(`composerMode.${mode}`, []);
19768
19272
  }
19769
- async handleChangeModel(args) {
19770
- const provider2 = this.getProvider();
19771
- const model = args?.model;
19772
- LOG4.info("Command", `[change_model] model=${model} provider=${provider2?.type} category=${provider2?.category} ideType=${this._currentIdeType} providerType=${this._currentProviderType}`);
19773
- if (provider2?.category === "acp") {
19774
- const adapter = this.getCliAdapter(provider2.type);
19775
- LOG4.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
19776
- if (adapter) {
19777
- const acpInstance = adapter._acpInstance;
19778
- if (acpInstance && typeof acpInstance.onEvent === "function") {
19779
- acpInstance.onEvent("change_model", { model });
19780
- LOG4.info("Command", `[change_model] Dispatched change_model event to ACP instance`);
19781
- return { success: true, model };
19782
- }
19783
- }
19784
- return { success: false, error: "ACP adapter not found" };
19785
- }
19786
- const webviewScript = this.getProviderScript("webviewSetModel", { MODEL: JSON.stringify(model) });
19273
+ _log("All methods failed");
19274
+ return { success: false, error: "No provider method could send the message" };
19275
+ }
19276
+ async function handleListChats(h, args) {
19277
+ const provider2 = h.getProvider();
19278
+ if (provider2?.category === "extension" && h.agentStream && h.getCdp()) {
19279
+ try {
19280
+ const chats = await h.agentStream.listAgentChats(h.getCdp(), provider2.type);
19281
+ LOG5.info("Command", `[list_chats] Extension: ${chats.length} chats`);
19282
+ return { success: true, chats };
19283
+ } catch (e) {
19284
+ LOG5.info("Command", `[list_chats] Extension error: ${e.message}`);
19285
+ }
19286
+ }
19287
+ try {
19288
+ const webviewScript = h.getProviderScript("webviewListSessions") || h.getProviderScript("webview_list_sessions");
19787
19289
  if (webviewScript) {
19788
- const cdp2 = this.getCdp();
19789
- if (cdp2?.isConnected) {
19290
+ const matchText = provider2?.webviewMatchText;
19291
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19292
+ const raw = await h.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
19293
+ let parsed = raw;
19294
+ if (typeof parsed === "string") {
19790
19295
  try {
19791
- const matchText = provider2?.webviewMatchText;
19792
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19793
- const raw = await cdp2.evaluateInWebviewFrame?.(webviewScript, matchFn);
19794
- let result = raw;
19795
- if (typeof raw === "string") {
19796
- try {
19797
- result = JSON.parse(raw);
19798
- } catch {
19799
- }
19800
- }
19801
- if (result?.success) return { success: true, model, method: "webview-script" };
19802
- } catch (e) {
19803
- LOG4.info("Command", `[change_model] webview script error: ${e.message}`);
19296
+ parsed = JSON.parse(parsed);
19297
+ } catch {
19804
19298
  }
19805
19299
  }
19300
+ if (parsed?.sessions) {
19301
+ LOG5.info("Command", `[list_chats] Webview OK: ${parsed.sessions.length} chats`);
19302
+ return { success: true, chats: parsed.sessions };
19303
+ }
19806
19304
  }
19807
- const mainScript = this.getProviderScript("setModel", { MODEL: JSON.stringify(model) });
19808
- if (mainScript) {
19809
- try {
19810
- const evalResult = await this.evaluateProviderScript("setModel", { MODEL: JSON.stringify(model) }, 15e3);
19811
- if (evalResult?.result) {
19812
- let parsed = evalResult.result;
19813
- if (typeof parsed === "string") {
19814
- try {
19815
- parsed = JSON.parse(parsed);
19816
- } catch {
19817
- }
19818
- }
19819
- if (parsed?.success) return { success: true, model, method: "script" };
19305
+ } catch (e) {
19306
+ LOG5.info("Command", `[list_chats] Webview error: ${e.message}`);
19307
+ }
19308
+ try {
19309
+ const evalResult = await h.evaluateProviderScript("listSessions");
19310
+ if (evalResult) {
19311
+ let parsed = evalResult.result;
19312
+ if (typeof parsed === "string") {
19313
+ try {
19314
+ parsed = JSON.parse(parsed);
19315
+ } catch {
19820
19316
  }
19821
- } catch (e) {
19822
- LOG4.info("Command", `[change_model] script error: ${e.message}`);
19317
+ }
19318
+ if (Array.isArray(parsed)) {
19319
+ LOG5.info("Command", `[list_chats] OK: ${parsed.length} chats`);
19320
+ return { success: true, chats: parsed };
19823
19321
  }
19824
19322
  }
19825
- const settingsKey = provider2?.vscodeCommands?.changeModel;
19826
- if (settingsKey) {
19827
- return this.delegateToExtension("workbench.action.openSettings", [settingsKey]);
19323
+ } catch (e) {
19324
+ LOG5.info("Command", `[list_chats] error: ${e.message}`);
19325
+ }
19326
+ return { success: false, error: "listSessions script not available for this provider" };
19327
+ }
19328
+ async function handleNewChat(h, args) {
19329
+ const provider2 = h.getProvider();
19330
+ if (provider2?.category === "extension" && h.agentStream && h.getCdp()) {
19331
+ const ok = await h.agentStream.newAgentSession(h.getCdp(), provider2.type, h.currentIdeType);
19332
+ return { success: ok };
19333
+ }
19334
+ try {
19335
+ const webviewScript = h.getProviderScript("webviewNewSession") || h.getProviderScript("webview_new_session");
19336
+ if (webviewScript) {
19337
+ const matchText = provider2?.webviewMatchText;
19338
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19339
+ const raw = await h.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
19340
+ if (raw) return { success: true, result: raw };
19828
19341
  }
19829
- return { success: false, error: "changeModel not supported by this IDE provider" };
19342
+ } catch (e) {
19343
+ return { success: false, error: `webviewNewSession failed: ${e.message}` };
19830
19344
  }
19831
- /** set_thought_level — ACP configOption change */
19832
- async handleSetThoughtLevel(args) {
19833
- const configId = args?.configId;
19834
- const value = args?.value;
19835
- if (!configId || !value) return { success: false, error: "configId and value required" };
19836
- const provider2 = this.getProvider();
19837
- if (!provider2 || provider2.category !== "acp") {
19838
- return { success: false, error: "set_thought_level only for ACP providers" };
19345
+ try {
19346
+ const evalResult = await h.evaluateProviderScript("newSession");
19347
+ if (evalResult) return { success: true };
19348
+ } catch (e) {
19349
+ return { success: false, error: `newSession failed: ${e.message}` };
19350
+ }
19351
+ return { success: false, error: "newSession script not available for this provider" };
19352
+ }
19353
+ async function handleSwitchChat(h, args) {
19354
+ const provider2 = h.getProvider();
19355
+ const ideType = h.currentIdeType;
19356
+ const sessionId = args?.sessionId || args?.id || args?.chatId;
19357
+ if (!sessionId) return { success: false, error: "sessionId required" };
19358
+ LOG5.info("Command", `[switch_chat] sessionId=${sessionId}, ideType=${ideType}`);
19359
+ if (provider2?.category === "extension" && h.agentStream && h.getCdp()) {
19360
+ const ok = await h.agentStream.switchAgentSession(h.getCdp(), provider2.type, sessionId);
19361
+ return { success: ok, result: ok ? "switched" : "failed" };
19362
+ }
19363
+ const cdp2 = h.getCdp(ideType);
19364
+ if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
19365
+ try {
19366
+ const webviewScript = h.getProviderScript("webviewSwitchSession", { SESSION_ID: JSON.stringify(sessionId) });
19367
+ if (webviewScript) {
19368
+ const matchText = provider2?.webviewMatchText;
19369
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19370
+ const raw = await cdp2.evaluateInWebviewFrame?.(webviewScript, matchFn);
19371
+ if (raw) return { success: true, result: raw };
19839
19372
  }
19840
- const adapter = this.getCliAdapter(provider2.type);
19841
- const acpInstance = adapter?._acpInstance;
19842
- if (!acpInstance) return { success: false, error: "ACP instance not found" };
19373
+ } catch (e) {
19374
+ return { success: false, error: `webviewSwitchSession failed: ${e.message}` };
19375
+ }
19376
+ const script = h.getProviderScript("switchSession", { SESSION_ID: JSON.stringify(sessionId) }) || h.getProviderScript("switch_session", { SESSION_ID: JSON.stringify(sessionId) });
19377
+ if (!script) return { success: false, error: "switch_session script not available" };
19378
+ try {
19379
+ const raw = await cdp2.evaluate(script, 15e3);
19380
+ LOG5.info("Command", `[switch_chat] result: ${raw}`);
19381
+ let parsed = null;
19843
19382
  try {
19844
- await acpInstance.setConfigOption(configId, value);
19845
- LOG4.info("Command", `[set_thought_level] ${configId}=${value} for ${provider2.type}`);
19846
- return { success: true, configId, value };
19847
- } catch (e) {
19848
- return { success: false, error: e?.message };
19383
+ parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
19384
+ } catch {
19385
+ }
19386
+ if (parsed?.action === "click" && parsed.clickX && parsed.clickY) {
19387
+ const x = Math.round(parsed.clickX);
19388
+ const y = Math.round(parsed.clickY);
19389
+ LOG5.info("Command", `[switch_chat] CDP click at (${x}, ${y}) for "${parsed.title}"`);
19390
+ await cdp2.send("Input.dispatchMouseEvent", {
19391
+ type: "mousePressed",
19392
+ x,
19393
+ y,
19394
+ button: "left",
19395
+ clickCount: 1
19396
+ });
19397
+ await cdp2.send("Input.dispatchMouseEvent", {
19398
+ type: "mouseReleased",
19399
+ x,
19400
+ y,
19401
+ button: "left",
19402
+ clickCount: 1
19403
+ });
19404
+ await new Promise((r) => setTimeout(r, 2e3));
19405
+ const wsResult = await cdp2.evaluate(`
19406
+ (() => {
19407
+ const inp = Array.from(document.querySelectorAll('input[type="text"]'))
19408
+ .find(i => i.offsetWidth > 0 && (i.placeholder || '').includes('Select where'));
19409
+ if (!inp) return null;
19410
+ const rows = inp.closest('[class*="quickInput"]')?.querySelectorAll('[class*="cursor-pointer"]');
19411
+ if (rows && rows.length > 0) {
19412
+ const r = rows[0].getBoundingClientRect();
19413
+ return JSON.stringify({ x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) });
19414
+ }
19415
+ return null;
19416
+ })()
19417
+ `, 5e3);
19418
+ if (wsResult) {
19419
+ try {
19420
+ const ws = JSON.parse(wsResult);
19421
+ await cdp2.send("Input.dispatchMouseEvent", {
19422
+ type: "mousePressed",
19423
+ x: ws.x,
19424
+ y: ws.y,
19425
+ button: "left",
19426
+ clickCount: 1
19427
+ });
19428
+ await cdp2.send("Input.dispatchMouseEvent", {
19429
+ type: "mouseReleased",
19430
+ x: ws.x,
19431
+ y: ws.y,
19432
+ button: "left",
19433
+ clickCount: 1
19434
+ });
19435
+ } catch {
19436
+ }
19437
+ }
19438
+ return { success: true, result: "switched" };
19849
19439
  }
19440
+ if (parsed?.error) return { success: false, error: parsed.error };
19441
+ return { success: true, result: raw };
19442
+ } catch (e) {
19443
+ LOG5.error("Command", `[switch_chat] error: ${e.message}`);
19444
+ return { success: false, error: e.message };
19850
19445
  }
19851
- /** resolveAction — unified (common for IDE/Extension) */
19852
- async handleResolveAction(args) {
19853
- const provider2 = this.getProvider();
19854
- const action = args?.action || "approve";
19855
- const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
19856
- LOG4.info("Command", `[resolveAction] action=${action} button="${button}" provider=${provider2?.type}`);
19857
- if (provider2?.category === "extension" && this.agentStream && this.getCdp()) {
19858
- const ok = await this.agentStream.resolveAgentAction(
19859
- this.getCdp(),
19860
- provider2.type,
19861
- action,
19862
- this._currentIdeType
19863
- );
19864
- return { success: ok };
19446
+ }
19447
+ async function handleSetMode(h, args) {
19448
+ const provider2 = h.getProvider();
19449
+ const mode = args?.mode || "agent";
19450
+ if (provider2?.category === "acp") {
19451
+ const adapter = h.getCliAdapter(provider2.type);
19452
+ if (adapter) {
19453
+ const acpInstance = adapter._acpInstance;
19454
+ if (acpInstance && typeof acpInstance.onEvent === "function") {
19455
+ acpInstance.onEvent("set_mode", { mode });
19456
+ return { success: true, mode };
19457
+ }
19865
19458
  }
19866
- if (provider2?.scripts?.webviewResolveAction || provider2?.scripts?.webview_resolve_action) {
19867
- const script = this.getProviderScript("webviewResolveAction", { action, button, buttonText: button }) || this.getProviderScript("webview_resolve_action", { action, button, buttonText: button });
19868
- if (script) {
19869
- const cdp2 = this.getCdp();
19870
- if (cdp2?.isConnected) {
19459
+ return { success: false, error: "ACP adapter not found" };
19460
+ }
19461
+ const webviewScript = h.getProviderScript("webviewSetMode", { MODE: JSON.stringify(mode) });
19462
+ if (webviewScript) {
19463
+ const cdp2 = h.getCdp();
19464
+ if (cdp2?.isConnected) {
19465
+ try {
19466
+ const matchText = provider2?.webviewMatchText;
19467
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19468
+ const raw = await cdp2.evaluateInWebviewFrame?.(webviewScript, matchFn);
19469
+ let result = raw;
19470
+ if (typeof raw === "string") {
19871
19471
  try {
19872
- const matchText = provider2?.webviewMatchText;
19873
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19874
- const raw = await cdp2.evaluateInWebviewFrame?.(script, matchFn);
19875
- let result = raw;
19876
- if (typeof raw === "string") {
19877
- try {
19878
- result = JSON.parse(raw);
19879
- } catch {
19880
- }
19881
- }
19882
- LOG4.info("Command", `[resolveAction] webview script result: ${JSON.stringify(result)}`);
19883
- if (result?.resolved) {
19884
- return { success: true, clicked: result.clicked };
19885
- }
19886
- if (result?.found && result.x != null && result.y != null) {
19887
- LOG4.info("Command", `[resolveAction] Webview coordinate click not fully supported via CDP. Click directly in script.`);
19888
- }
19889
- if (result?.found || result?.resolved) return { success: true };
19890
- } catch (e) {
19891
- return { success: false, error: `webviewResolveAction failed: ${e.message}` };
19472
+ result = JSON.parse(raw);
19473
+ } catch {
19892
19474
  }
19893
19475
  }
19476
+ if (result?.success) return { success: true, mode, method: "webview-script" };
19477
+ } catch (e) {
19478
+ LOG5.info("Command", `[set_mode] webview script error: ${e.message}`);
19894
19479
  }
19895
19480
  }
19896
- if (provider2?.scripts?.resolveAction) {
19897
- const script = provider2.scripts.resolveAction({ action, button, buttonText: button });
19898
- if (script) {
19899
- const cdp2 = this.getCdp();
19900
- if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
19901
- try {
19902
- const raw = await cdp2.evaluate(script, 3e4);
19903
- let result = raw;
19904
- if (typeof raw === "string") {
19905
- try {
19906
- result = JSON.parse(raw);
19907
- } catch {
19908
- }
19909
- }
19910
- LOG4.info("Command", `[resolveAction] script result: ${JSON.stringify(result)}`);
19911
- if (result?.resolved) {
19912
- LOG4.info("Command", `[resolveAction] script-click resolved \u2014 "${result.clicked}"`);
19913
- return { success: true, clicked: result.clicked };
19914
- }
19915
- if (result?.found && result.x != null && result.y != null) {
19916
- const x = result.x;
19917
- const y = result.y;
19918
- await cdp2.send("Input.dispatchMouseEvent", {
19919
- type: "mousePressed",
19920
- x,
19921
- y,
19922
- button: "left",
19923
- clickCount: 1
19924
- });
19925
- await cdp2.send("Input.dispatchMouseEvent", {
19926
- type: "mouseReleased",
19927
- x,
19928
- y,
19929
- button: "left",
19930
- clickCount: 1
19931
- });
19932
- LOG4.info("Command", `[resolveAction] CDP click at (${x}, ${y}) \u2014 "${result.text}"`);
19933
- return { success: true, clicked: result.text };
19481
+ }
19482
+ const mainScript = h.getProviderScript("setMode", { MODE: JSON.stringify(mode) });
19483
+ if (mainScript) {
19484
+ try {
19485
+ const evalResult = await h.evaluateProviderScript("setMode", { MODE: JSON.stringify(mode) }, 15e3);
19486
+ if (evalResult?.result) {
19487
+ let parsed = evalResult.result;
19488
+ if (typeof parsed === "string") {
19489
+ try {
19490
+ parsed = JSON.parse(parsed);
19491
+ } catch {
19934
19492
  }
19935
- return { success: false, error: result?.found === false ? `Button not found: ${button}` : "No coordinates" };
19936
- } catch (e) {
19937
- return { success: false, error: `resolveAction failed: ${e.message}` };
19938
19493
  }
19494
+ if (parsed?.success) return { success: true, mode, method: "script" };
19939
19495
  }
19496
+ } catch (e) {
19497
+ LOG5.info("Command", `[set_mode] script error: ${e.message}`);
19940
19498
  }
19941
- return { success: false, error: "resolveAction script not available for this provider" };
19942
19499
  }
19943
- // ─── CDP direct commands ──────────────────────────
19944
- async handleCdpEval(args) {
19945
- if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19946
- const expression = args?.expression || args?.script;
19947
- if (!expression) return { success: false, error: "expression required" };
19948
- try {
19949
- const result = await this.getCdp().evaluate(expression, 5e4);
19950
- return { success: true, result };
19951
- } catch (e) {
19952
- return { success: false, error: e.message };
19500
+ return { success: false, error: `setMode '${mode}' not supported by this provider` };
19501
+ }
19502
+ async function handleChangeModel(h, args) {
19503
+ const provider2 = h.getProvider();
19504
+ const model = args?.model;
19505
+ LOG5.info("Command", `[change_model] model=${model} provider=${provider2?.type} category=${provider2?.category} ideType=${h.currentIdeType} providerType=${h.currentProviderType}`);
19506
+ if (provider2?.category === "acp") {
19507
+ const adapter = h.getCliAdapter(provider2.type);
19508
+ LOG5.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
19509
+ if (adapter) {
19510
+ const acpInstance = adapter._acpInstance;
19511
+ if (acpInstance && typeof acpInstance.onEvent === "function") {
19512
+ acpInstance.onEvent("change_model", { model });
19513
+ LOG5.info("Command", `[change_model] Dispatched change_model event to ACP instance`);
19514
+ return { success: true, model };
19515
+ }
19953
19516
  }
19517
+ return { success: false, error: "ACP adapter not found" };
19954
19518
  }
19955
- async handleScreenshot(args) {
19956
- if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19957
- try {
19958
- const buf = await this.getCdp().captureScreenshot();
19959
- if (buf) {
19960
- const b64 = buf.toString("base64");
19961
- return { success: true, result: b64, base64: b64, screenshot: b64, format: "jpeg" };
19519
+ const webviewScript = h.getProviderScript("webviewSetModel", { MODEL: JSON.stringify(model) });
19520
+ if (webviewScript) {
19521
+ const cdp2 = h.getCdp();
19522
+ if (cdp2?.isConnected) {
19523
+ try {
19524
+ const matchText = provider2?.webviewMatchText;
19525
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19526
+ const raw = await cdp2.evaluateInWebviewFrame?.(webviewScript, matchFn);
19527
+ let result = raw;
19528
+ if (typeof raw === "string") {
19529
+ try {
19530
+ result = JSON.parse(raw);
19531
+ } catch {
19532
+ }
19533
+ }
19534
+ if (result?.success) return { success: true, model, method: "webview-script" };
19535
+ } catch (e) {
19536
+ LOG5.info("Command", `[change_model] webview script error: ${e.message}`);
19962
19537
  }
19963
- return { success: false, error: "Screenshot failed" };
19964
- } catch (e) {
19965
- return { success: false, error: e.message };
19966
19538
  }
19967
19539
  }
19968
- async handleCdpCommand(args) {
19969
- if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19970
- const method = args?.method;
19971
- const params = args?.params || {};
19972
- if (!method) return { success: false, error: "method required" };
19540
+ const mainScript = h.getProviderScript("setModel", { MODEL: JSON.stringify(model) });
19541
+ if (mainScript) {
19973
19542
  try {
19974
- const result = await this.getCdp().sendCdpCommand(method, params);
19975
- return { success: true, result };
19543
+ const evalResult = await h.evaluateProviderScript("setModel", { MODEL: JSON.stringify(model) }, 15e3);
19544
+ if (evalResult?.result) {
19545
+ let parsed = evalResult.result;
19546
+ if (typeof parsed === "string") {
19547
+ try {
19548
+ parsed = JSON.parse(parsed);
19549
+ } catch {
19550
+ }
19551
+ }
19552
+ if (parsed?.success) return { success: true, model, method: "script" };
19553
+ }
19976
19554
  } catch (e) {
19977
- return { success: false, error: e.message };
19555
+ LOG5.info("Command", `[change_model] script error: ${e.message}`);
19978
19556
  }
19979
19557
  }
19980
- async handleCdpBatch(args) {
19981
- if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19982
- const commands = args?.commands;
19983
- const stopOnError = args?.stopOnError !== false;
19984
- if (!commands?.length) return { success: false, error: "commands array required" };
19985
- const results = [];
19986
- for (const cmd of commands) {
19987
- try {
19988
- const result = await this.getCdp().sendCdpCommand(cmd.method, cmd.params || {});
19989
- results.push({ method: cmd.method, success: true, result });
19990
- } catch (e) {
19991
- results.push({ method: cmd.method, success: false, error: e.message });
19992
- if (stopOnError) break;
19558
+ return { success: false, error: "changeModel not supported by this IDE provider" };
19559
+ }
19560
+ async function handleSetThoughtLevel(h, args) {
19561
+ const configId = args?.configId;
19562
+ const value = args?.value;
19563
+ if (!configId || !value) return { success: false, error: "configId and value required" };
19564
+ const provider2 = h.getProvider();
19565
+ if (!provider2 || provider2.category !== "acp") {
19566
+ return { success: false, error: "set_thought_level only for ACP providers" };
19567
+ }
19568
+ const adapter = h.getCliAdapter(provider2.type);
19569
+ const acpInstance = adapter?._acpInstance;
19570
+ if (!acpInstance) return { success: false, error: "ACP instance not found" };
19571
+ try {
19572
+ await acpInstance.setConfigOption(configId, value);
19573
+ LOG5.info("Command", `[set_thought_level] ${configId}=${value} for ${provider2.type}`);
19574
+ return { success: true, configId, value };
19575
+ } catch (e) {
19576
+ return { success: false, error: e?.message };
19577
+ }
19578
+ }
19579
+ async function handleResolveAction(h, args) {
19580
+ const provider2 = h.getProvider();
19581
+ const action = args?.action || "approve";
19582
+ const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
19583
+ LOG5.info("Command", `[resolveAction] action=${action} button="${button}" provider=${provider2?.type}`);
19584
+ if (provider2?.category === "extension" && h.agentStream && h.getCdp()) {
19585
+ const ok = await h.agentStream.resolveAgentAction(
19586
+ h.getCdp(),
19587
+ provider2.type,
19588
+ action,
19589
+ h.currentIdeType
19590
+ );
19591
+ return { success: ok };
19592
+ }
19593
+ if (provider2?.scripts?.webviewResolveAction || provider2?.scripts?.webview_resolve_action) {
19594
+ const script = h.getProviderScript("webviewResolveAction", { action, button, buttonText: button }) || h.getProviderScript("webview_resolve_action", { action, button, buttonText: button });
19595
+ if (script) {
19596
+ const cdp2 = h.getCdp();
19597
+ if (cdp2?.isConnected) {
19598
+ try {
19599
+ const matchText = provider2?.webviewMatchText;
19600
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
19601
+ const raw = await cdp2.evaluateInWebviewFrame?.(script, matchFn);
19602
+ let result = raw;
19603
+ if (typeof raw === "string") {
19604
+ try {
19605
+ result = JSON.parse(raw);
19606
+ } catch {
19607
+ }
19608
+ }
19609
+ LOG5.info("Command", `[resolveAction] webview script result: ${JSON.stringify(result)}`);
19610
+ if (result?.resolved) return { success: true, clicked: result.clicked };
19611
+ if (result?.found && result.x != null && result.y != null) {
19612
+ LOG5.info("Command", `[resolveAction] Webview coordinate click not fully supported via CDP. Click directly in script.`);
19613
+ }
19614
+ if (result?.found || result?.resolved) return { success: true };
19615
+ } catch (e) {
19616
+ return { success: false, error: `webviewResolveAction failed: ${e.message}` };
19617
+ }
19993
19618
  }
19994
19619
  }
19995
- return { success: true, results };
19996
19620
  }
19997
- async handleCdpRemoteAction(args) {
19998
- if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19999
- const action = args?.action;
20000
- const params = args?.params || args;
20001
- try {
20002
- switch (action) {
20003
- case "input_key": {
20004
- const { key, modifiers } = params;
20005
- await this.getCdp().send("Input.dispatchKeyEvent", {
20006
- type: "keyDown",
20007
- key,
20008
- ...modifiers?.ctrl ? { modifiers: 2 } : {},
20009
- ...modifiers?.shift ? { modifiers: 8 } : {}
20010
- });
20011
- await this.getCdp().send("Input.dispatchKeyEvent", { type: "keyUp", key });
20012
- return { success: true };
20013
- }
20014
- case "input_click": {
20015
- let { x, y, nx, ny, button: btn } = params;
20016
- if ((x === void 0 || y === void 0) && nx !== void 0 && ny !== void 0) {
20017
- const viewport = await this.getCdp().evaluate(
20018
- "JSON.stringify({ w: window.innerWidth, h: window.innerHeight })"
20019
- );
20020
- const { w, h } = JSON.parse(viewport);
20021
- x = Math.round(nx * w);
20022
- y = Math.round(ny * h);
20023
- }
20024
- if (x === void 0 || y === void 0) {
20025
- return { success: false, error: "No coordinates provided (x,y or nx,ny required)" };
19621
+ if (provider2?.scripts?.resolveAction) {
19622
+ const script = provider2.scripts.resolveAction({ action, button, buttonText: button });
19623
+ if (script) {
19624
+ const cdp2 = h.getCdp();
19625
+ if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
19626
+ try {
19627
+ const raw = await cdp2.evaluate(script, 3e4);
19628
+ let result = raw;
19629
+ if (typeof raw === "string") {
19630
+ try {
19631
+ result = JSON.parse(raw);
19632
+ } catch {
20026
19633
  }
20027
- await this.getCdp().send("Input.dispatchMouseEvent", {
19634
+ }
19635
+ LOG5.info("Command", `[resolveAction] script result: ${JSON.stringify(result)}`);
19636
+ if (result?.resolved) {
19637
+ LOG5.info("Command", `[resolveAction] script-click resolved \u2014 "${result.clicked}"`);
19638
+ return { success: true, clicked: result.clicked };
19639
+ }
19640
+ if (result?.found && result.x != null && result.y != null) {
19641
+ const x = result.x;
19642
+ const y = result.y;
19643
+ await cdp2.send("Input.dispatchMouseEvent", {
20028
19644
  type: "mousePressed",
20029
19645
  x,
20030
19646
  y,
20031
- button: btn || "left",
19647
+ button: "left",
20032
19648
  clickCount: 1
20033
19649
  });
20034
- await this.getCdp().send("Input.dispatchMouseEvent", {
19650
+ await cdp2.send("Input.dispatchMouseEvent", {
20035
19651
  type: "mouseReleased",
20036
19652
  x,
20037
19653
  y,
20038
- button: btn || "left",
19654
+ button: "left",
20039
19655
  clickCount: 1
20040
19656
  });
20041
- return { success: true, x, y };
20042
- }
20043
- case "input_type": {
20044
- const { text } = params;
20045
- for (const char of text || "") {
20046
- await this.getCdp().send("Input.dispatchKeyEvent", {
20047
- type: "keyDown",
20048
- text: char,
20049
- key: char
20050
- });
20051
- await this.getCdp().send("Input.dispatchKeyEvent", { type: "keyUp", key: char });
20052
- }
20053
- return { success: true };
20054
- }
20055
- case "page_screenshot":
20056
- return this.handleScreenshot(args);
20057
- case "page_eval":
20058
- return this.handleCdpEval(params);
20059
- case "dom_query": {
20060
- const html = await this.getCdp().querySelector(params?.selector);
20061
- return { success: true, html };
20062
- }
20063
- case "input_wheel": {
20064
- let { x, y, nx, ny, deltaX, deltaY } = params;
20065
- if ((x === void 0 || y === void 0) && nx !== void 0 && ny !== void 0) {
20066
- const viewport = await this.getCdp().evaluate(
20067
- "JSON.stringify({ w: window.innerWidth, h: window.innerHeight })"
20068
- );
20069
- const { w, h } = JSON.parse(viewport);
20070
- x = Math.round(nx * w);
20071
- y = Math.round(ny * h);
20072
- }
20073
- await this.getCdp().send("Input.dispatchMouseEvent", {
20074
- type: "mouseWheel",
20075
- x: x || 0,
20076
- y: y || 0,
20077
- deltaX: deltaX || 0,
20078
- deltaY: deltaY || 0
20079
- });
20080
- return { success: true };
19657
+ LOG5.info("Command", `[resolveAction] CDP click at (${x}, ${y}) \u2014 "${result.text}"`);
19658
+ return { success: true, clicked: result.text };
20081
19659
  }
20082
- default:
20083
- return { success: false, error: `Unknown remote action: ${action}` };
19660
+ return { success: false, error: result?.found === false ? `Button not found: ${button}` : "No coordinates" };
19661
+ } catch (e) {
19662
+ return { success: false, error: `resolveAction failed: ${e.message}` };
20084
19663
  }
20085
- } catch (e) {
20086
- return { success: false, error: e.message };
20087
19664
  }
20088
19665
  }
20089
- async handleDiscoverAgents(args) {
20090
- if (!this.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
20091
- const agents = await this.getCdp().discoverAgentWebviews();
20092
- return { success: true, agents };
19666
+ return { success: false, error: "resolveAction script not available for this provider" };
19667
+ }
19668
+ var fs32 = __toESM2(require("fs"));
19669
+ var path32 = __toESM2(require("path"));
19670
+ var os4 = __toESM2(require("os"));
19671
+ async function handleCdpEval(h, args) {
19672
+ if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19673
+ const expression = args?.expression || args?.script;
19674
+ if (!expression) return { success: false, error: "expression required" };
19675
+ try {
19676
+ const result = await h.getCdp().evaluate(expression, 5e4);
19677
+ return { success: true, result };
19678
+ } catch (e) {
19679
+ return { success: false, error: e.message };
20093
19680
  }
20094
- // ─── file directly handle ─────────────────────────
20095
- async handleFileRead(args) {
20096
- try {
20097
- const filePath = this.resolveSafePath(args?.path);
20098
- const content = fs32.readFileSync(filePath, "utf-8");
20099
- return { success: true, content, path: filePath };
20100
- } catch (e) {
20101
- return { success: false, error: e.message };
19681
+ }
19682
+ async function handleScreenshot(h, args) {
19683
+ if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19684
+ try {
19685
+ const buf = await h.getCdp().captureScreenshot();
19686
+ if (buf) {
19687
+ const b64 = buf.toString("base64");
19688
+ return { success: true, result: b64, base64: b64, screenshot: b64, format: "webp" };
20102
19689
  }
19690
+ return { success: false, error: "Screenshot failed" };
19691
+ } catch (e) {
19692
+ return { success: false, error: e.message };
20103
19693
  }
20104
- async handleFileWrite(args) {
20105
- try {
20106
- const filePath = this.resolveSafePath(args?.path);
20107
- fs32.mkdirSync(path32.dirname(filePath), { recursive: true });
20108
- fs32.writeFileSync(filePath, args?.content || "", "utf-8");
20109
- return { success: true, path: filePath };
20110
- } catch (e) {
20111
- return { success: false, error: e.message };
20112
- }
19694
+ }
19695
+ async function handleCdpCommand(h, args) {
19696
+ if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19697
+ const method = args?.method;
19698
+ const params = args?.params || {};
19699
+ if (!method) return { success: false, error: "method required" };
19700
+ try {
19701
+ const result = await h.getCdp().sendCdpCommand(method, params);
19702
+ return { success: true, result };
19703
+ } catch (e) {
19704
+ return { success: false, error: e.message };
20113
19705
  }
20114
- async handleFileList(args) {
19706
+ }
19707
+ async function handleCdpBatch(h, args) {
19708
+ if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19709
+ const commands = args?.commands;
19710
+ const stopOnError = args?.stopOnError !== false;
19711
+ if (!commands?.length) return { success: false, error: "commands array required" };
19712
+ const results = [];
19713
+ for (const cmd of commands) {
20115
19714
  try {
20116
- const dirPath = this.resolveSafePath(args?.path || ".");
20117
- const entries = fs32.readdirSync(dirPath, { withFileTypes: true });
20118
- const files = entries.map((e) => ({
20119
- name: e.name,
20120
- type: e.isDirectory() ? "directory" : "file",
20121
- size: e.isFile() ? fs32.statSync(path32.join(dirPath, e.name)).size : void 0
20122
- }));
20123
- return { success: true, files, path: dirPath };
19715
+ const result = await h.getCdp().sendCdpCommand(cmd.method, cmd.params || {});
19716
+ results.push({ method: cmd.method, success: true, result });
20124
19717
  } catch (e) {
20125
- return { success: false, error: e.message };
20126
- }
20127
- }
20128
- async handleFileListBrowse(args) {
20129
- return this.handleFileList(args);
20130
- }
20131
- resolveSafePath(requestedPath) {
20132
- const home = os4.homedir();
20133
- let resolved;
20134
- if (requestedPath.startsWith("~")) {
20135
- resolved = path32.join(home, requestedPath.slice(1));
20136
- } else if (path32.isAbsolute(requestedPath)) {
20137
- resolved = requestedPath;
20138
- } else {
20139
- resolved = path32.resolve(requestedPath);
19718
+ results.push({ method: cmd.method, success: false, error: e.message });
19719
+ if (stopOnError) break;
20140
19720
  }
20141
- return resolved;
20142
- }
20143
- // ─── Extension delegate (No longer available — bridge-extension removed) ─────────────
20144
- async delegateToExtension(command, args) {
20145
- return { success: false, error: "Extension not available (bridge-extension removed)" };
20146
19721
  }
20147
- // ─── Misc ───────────────────────────────────
20148
- async handleGetRecentWorkspaces(args) {
20149
- const config2 = loadConfig4();
20150
- const cliRecent = config2.recentCliWorkspaces || [];
20151
- try {
20152
- const storageDir = path32.join(os4.homedir(), "Library", "Application Support");
20153
- const candidates = ["Cursor", "Code", "VSCodium"];
20154
- for (const app of candidates) {
20155
- const stateFile = path32.join(storageDir, app, "User", "globalStorage", "state.vscdb");
20156
- if (fs32.existsSync(stateFile)) {
20157
- const result = await this.delegateToExtension("adhdev.getRecentWorkspaces", []);
20158
- if (result.success && Array.isArray(result.result)) {
20159
- const merged = Array.from(/* @__PURE__ */ new Set([...cliRecent, ...result.result])).slice(0, 20);
20160
- return { success: true, result: merged };
20161
- }
19722
+ return { success: true, results };
19723
+ }
19724
+ async function handleCdpRemoteAction(h, args) {
19725
+ if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19726
+ const action = args?.action;
19727
+ const params = args?.params || args;
19728
+ try {
19729
+ switch (action) {
19730
+ case "input_key": {
19731
+ const { key, modifiers } = params;
19732
+ await h.getCdp().send("Input.dispatchKeyEvent", {
19733
+ type: "keyDown",
19734
+ key,
19735
+ ...modifiers?.ctrl ? { modifiers: 2 } : {},
19736
+ ...modifiers?.shift ? { modifiers: 8 } : {}
19737
+ });
19738
+ await h.getCdp().send("Input.dispatchKeyEvent", { type: "keyUp", key });
19739
+ return { success: true };
19740
+ }
19741
+ case "input_click": {
19742
+ let { x, y, nx, ny, button: btn } = params;
19743
+ if ((x === void 0 || y === void 0) && nx !== void 0 && ny !== void 0) {
19744
+ const viewport = await h.getCdp().evaluate(
19745
+ "JSON.stringify({ w: window.innerWidth, h: window.innerHeight })"
19746
+ );
19747
+ const { w, h: vh } = JSON.parse(viewport);
19748
+ x = Math.round(nx * w);
19749
+ y = Math.round(ny * vh);
19750
+ }
19751
+ if (x === void 0 || y === void 0) {
19752
+ return { success: false, error: "No coordinates provided (x,y or nx,ny required)" };
20162
19753
  }
19754
+ await h.getCdp().send("Input.dispatchMouseEvent", {
19755
+ type: "mousePressed",
19756
+ x,
19757
+ y,
19758
+ button: btn || "left",
19759
+ clickCount: 1
19760
+ });
19761
+ await h.getCdp().send("Input.dispatchMouseEvent", {
19762
+ type: "mouseReleased",
19763
+ x,
19764
+ y,
19765
+ button: btn || "left",
19766
+ clickCount: 1
19767
+ });
19768
+ return { success: true, x, y };
20163
19769
  }
20164
- return { success: true, result: cliRecent };
20165
- } catch {
20166
- return { success: true, result: cliRecent };
20167
- }
20168
- }
20169
- async handleRefreshScripts(_args) {
20170
- if (this.ctx.providerLoader) {
20171
- this.ctx.providerLoader.reload();
20172
- return { success: true };
20173
- }
20174
- return { success: false, error: "ProviderLoader not initialized" };
20175
- }
20176
- // ─── Agent Stream commands ───────────────────────
20177
- async handleAgentStreamSwitch(args) {
20178
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20179
- const agentType = args?.agentType || args?.agent || null;
20180
- await this.agentStream.switchActiveAgent(this.getCdp(), agentType);
20181
- return { success: true, activeAgent: agentType };
20182
- }
20183
- async handleAgentStreamRead(args) {
20184
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20185
- const streams = await this.agentStream.collectAgentStreams(this.getCdp());
20186
- return { success: true, streams };
20187
- }
20188
- async handleAgentStreamSend(args) {
20189
- const agentType = args?.agentType || args?.agent;
20190
- const text = args?.text || args?.message;
20191
- if (!text) return { success: false, error: "text required" };
20192
- if (agentType && this.ctx.adapters) {
20193
- for (const [key, adapter] of this.ctx.adapters.entries()) {
20194
- if (adapter.cliType === agentType || key.includes(agentType)) {
20195
- LOG4.info("Command", `[agent_stream_send] Routing to CLI adapter: ${adapter.cliType}`);
20196
- try {
20197
- await adapter.sendMessage(text);
20198
- return { success: true, sent: true, targetAgent: adapter.cliType };
20199
- } catch (e) {
20200
- LOG4.info("Command", `[agent_stream_send] CLI adapter failed: ${e.message}`);
20201
- return { success: false, error: `CLI send failed: ${e.message}` };
20202
- }
19770
+ case "input_type": {
19771
+ const { text } = params;
19772
+ for (const char of text || "") {
19773
+ await h.getCdp().send("Input.dispatchKeyEvent", {
19774
+ type: "keyDown",
19775
+ text: char,
19776
+ key: char
19777
+ });
19778
+ await h.getCdp().send("Input.dispatchKeyEvent", { type: "keyUp", key: char });
20203
19779
  }
19780
+ return { success: true };
19781
+ }
19782
+ case "page_screenshot":
19783
+ return handleScreenshot(h, args);
19784
+ case "page_eval":
19785
+ return handleCdpEval(h, params);
19786
+ case "dom_query": {
19787
+ const html = await h.getCdp().querySelector(params?.selector);
19788
+ return { success: true, html };
19789
+ }
19790
+ case "input_wheel": {
19791
+ let { x, y, nx, ny, deltaX, deltaY } = params;
19792
+ if ((x === void 0 || y === void 0) && nx !== void 0 && ny !== void 0) {
19793
+ const viewport = await h.getCdp().evaluate(
19794
+ "JSON.stringify({ w: window.innerWidth, h: window.innerHeight })"
19795
+ );
19796
+ const { w, h: vh } = JSON.parse(viewport);
19797
+ x = Math.round(nx * w);
19798
+ y = Math.round(ny * vh);
19799
+ }
19800
+ await h.getCdp().send("Input.dispatchMouseEvent", {
19801
+ type: "mouseWheel",
19802
+ x: x || 0,
19803
+ y: y || 0,
19804
+ deltaX: deltaX || 0,
19805
+ deltaY: deltaY || 0
19806
+ });
19807
+ return { success: true };
20204
19808
  }
19809
+ default:
19810
+ return { success: false, error: `Unknown remote action: ${action}` };
20205
19811
  }
20206
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20207
- const resolvedAgent = agentType || this.agentStream.activeAgentType;
20208
- if (!resolvedAgent) return { success: false, error: "agentType required" };
20209
- const ok = await this.agentStream.sendToAgent(this.getCdp(), resolvedAgent, text, this._currentIdeType);
20210
- return { success: ok };
19812
+ } catch (e) {
19813
+ return { success: false, error: e.message };
20211
19814
  }
20212
- async handleAgentStreamResolve(args) {
20213
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20214
- const agentType = args?.agentType || args?.agent || this.agentStream.activeAgentType;
20215
- const action = args?.action || "approve";
20216
- if (!agentType) return { success: false, error: "agentType required" };
20217
- const ok = await this.agentStream.resolveAgentAction(this.getCdp(), agentType, action, this._currentIdeType);
20218
- return { success: ok };
19815
+ }
19816
+ async function handleDiscoverAgents(h, args) {
19817
+ if (!h.getCdp()?.isConnected) return { success: false, error: "CDP not connected" };
19818
+ const agents = await h.getCdp().discoverAgentWebviews();
19819
+ return { success: true, agents };
19820
+ }
19821
+ function resolveSafePath(requestedPath) {
19822
+ const home = os4.homedir();
19823
+ let resolved;
19824
+ if (requestedPath.startsWith("~")) {
19825
+ resolved = path32.join(home, requestedPath.slice(1));
19826
+ } else if (path32.isAbsolute(requestedPath)) {
19827
+ resolved = requestedPath;
19828
+ } else {
19829
+ resolved = path32.resolve(requestedPath);
20219
19830
  }
20220
- async handleAgentStreamNew(args) {
20221
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20222
- const agentType = args?.agentType || args?.agent || this.agentStream.activeAgentType;
20223
- if (!agentType) return { success: false, error: "agentType required" };
20224
- const ok = await this.agentStream.newAgentSession(this.getCdp(), agentType, this._currentIdeType);
20225
- return { success: ok };
19831
+ return resolved;
19832
+ }
19833
+ async function handleFileRead(h, args) {
19834
+ try {
19835
+ const filePath = resolveSafePath(args?.path);
19836
+ const content = fs32.readFileSync(filePath, "utf-8");
19837
+ return { success: true, content, path: filePath };
19838
+ } catch (e) {
19839
+ return { success: false, error: e.message };
20226
19840
  }
20227
- async handleAgentStreamListChats(args) {
20228
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20229
- const agentType = args?.agentType || args?.agent || this.agentStream.activeAgentType;
20230
- if (!agentType) return { success: false, error: "agentType required" };
20231
- const chats = await this.agentStream.listAgentChats(this.getCdp(), agentType);
20232
- return { success: true, chats };
20233
- }
20234
- async handleAgentStreamSwitchSession(args) {
20235
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20236
- const agentType = args?.agentType || args?.agent || this.agentStream.activeAgentType;
20237
- const sessionId = args?.sessionId || args?.id;
20238
- if (!agentType || !sessionId) return { success: false, error: "agentType and sessionId required" };
20239
- const ok = await this.agentStream.switchAgentSession(this.getCdp(), agentType, sessionId);
20240
- return { success: ok };
19841
+ }
19842
+ async function handleFileWrite(h, args) {
19843
+ try {
19844
+ const filePath = resolveSafePath(args?.path);
19845
+ fs32.mkdirSync(path32.dirname(filePath), { recursive: true });
19846
+ fs32.writeFileSync(filePath, args?.content || "", "utf-8");
19847
+ return { success: true, path: filePath };
19848
+ } catch (e) {
19849
+ return { success: false, error: e.message };
20241
19850
  }
20242
- async handleAgentStreamFocus(args) {
20243
- if (!this.agentStream || !this.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
20244
- const agentType = args?.agentType || args?.agent || this.agentStream.activeAgentType;
20245
- if (!agentType) return { success: false, error: "agentType required" };
20246
- await this.agentStream.ensureAgentPanelOpen(agentType, this._currentIdeType);
20247
- const ok = await this.agentStream.focusAgentEditor(this.getCdp(), agentType);
20248
- return { success: ok };
19851
+ }
19852
+ async function handleFileList(h, args) {
19853
+ try {
19854
+ const dirPath = resolveSafePath(args?.path || ".");
19855
+ const entries = fs32.readdirSync(dirPath, { withFileTypes: true });
19856
+ const files = entries.map((e) => ({
19857
+ name: e.name,
19858
+ type: e.isDirectory() ? "directory" : "file",
19859
+ size: e.isFile() ? fs32.statSync(path32.join(dirPath, e.name)).size : void 0
19860
+ }));
19861
+ return { success: true, files, path: dirPath };
19862
+ } catch (e) {
19863
+ return { success: false, error: e.message };
19864
+ }
19865
+ }
19866
+ async function handleFileListBrowse(h, args) {
19867
+ return handleFileList(h, args);
19868
+ }
19869
+ init_config();
19870
+ async function handleAgentStreamSwitch(h, args) {
19871
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19872
+ const agentType = args?.agentType || args?.agent || null;
19873
+ await h.agentStream.switchActiveAgent(h.getCdp(), agentType);
19874
+ return { success: true, activeAgent: agentType };
19875
+ }
19876
+ async function handleAgentStreamRead(h, args) {
19877
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19878
+ const streams = await h.agentStream.collectAgentStreams(h.getCdp());
19879
+ return { success: true, streams };
19880
+ }
19881
+ async function handleAgentStreamSend(h, args) {
19882
+ const agentType = args?.agentType || args?.agent;
19883
+ const text = args?.text || args?.message;
19884
+ if (!text) return { success: false, error: "text required" };
19885
+ if (agentType && h.ctx.adapters) {
19886
+ for (const [key, adapter] of h.ctx.adapters.entries()) {
19887
+ if (adapter.cliType === agentType || key.includes(agentType)) {
19888
+ LOG5.info("Command", `[agent_stream_send] Routing to CLI adapter: ${adapter.cliType}`);
19889
+ try {
19890
+ await adapter.sendMessage(text);
19891
+ return { success: true, sent: true, targetAgent: adapter.cliType };
19892
+ } catch (e) {
19893
+ LOG5.info("Command", `[agent_stream_send] CLI adapter failed: ${e.message}`);
19894
+ return { success: false, error: `CLI send failed: ${e.message}` };
19895
+ }
19896
+ }
19897
+ }
20249
19898
  }
20250
- // ─── PTY Raw I/O (terminal view) ──────────────────────
20251
- handlePtyInput(args) {
20252
- const { cliType, data } = args || {};
20253
- if (!data) return { success: false, error: "data required" };
20254
- if (this.ctx.adapters) {
20255
- const targetCli = cliType || "";
20256
- if (!targetCli && this.ctx.adapters.size > 0) {
20257
- const first = this.ctx.adapters.values().next().value;
20258
- if (first && typeof first.writeRaw === "function") {
20259
- first.writeRaw(data);
20260
- return { success: true };
20261
- }
20262
- }
20263
- const directAdapter = this.ctx.adapters.get(targetCli);
20264
- if (directAdapter && typeof directAdapter.writeRaw === "function") {
20265
- directAdapter.writeRaw(data);
19899
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19900
+ const resolvedAgent = agentType || h.agentStream.activeAgentType;
19901
+ if (!resolvedAgent) return { success: false, error: "agentType required" };
19902
+ const ok = await h.agentStream.sendToAgent(h.getCdp(), resolvedAgent, text, h.currentIdeType);
19903
+ return { success: ok };
19904
+ }
19905
+ async function handleAgentStreamResolve(h, args) {
19906
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19907
+ const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
19908
+ const action = args?.action || "approve";
19909
+ if (!agentType) return { success: false, error: "agentType required" };
19910
+ const ok = await h.agentStream.resolveAgentAction(h.getCdp(), agentType, action, h.currentIdeType);
19911
+ return { success: ok };
19912
+ }
19913
+ async function handleAgentStreamNew(h, args) {
19914
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19915
+ const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
19916
+ if (!agentType) return { success: false, error: "agentType required" };
19917
+ const ok = await h.agentStream.newAgentSession(h.getCdp(), agentType, h.currentIdeType);
19918
+ return { success: ok };
19919
+ }
19920
+ async function handleAgentStreamListChats(h, args) {
19921
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19922
+ const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
19923
+ if (!agentType) return { success: false, error: "agentType required" };
19924
+ const chats = await h.agentStream.listAgentChats(h.getCdp(), agentType);
19925
+ return { success: true, chats };
19926
+ }
19927
+ async function handleAgentStreamSwitchSession(h, args) {
19928
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19929
+ const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
19930
+ const sessionId = args?.sessionId || args?.id;
19931
+ if (!agentType || !sessionId) return { success: false, error: "agentType and sessionId required" };
19932
+ const ok = await h.agentStream.switchAgentSession(h.getCdp(), agentType, sessionId);
19933
+ return { success: ok };
19934
+ }
19935
+ async function handleAgentStreamFocus(h, args) {
19936
+ if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
19937
+ const agentType = args?.agentType || args?.agent || h.agentStream.activeAgentType;
19938
+ if (!agentType) return { success: false, error: "agentType required" };
19939
+ await h.agentStream.ensureAgentPanelOpen(agentType, h.currentIdeType);
19940
+ const ok = await h.agentStream.focusAgentEditor(h.getCdp(), agentType);
19941
+ return { success: ok };
19942
+ }
19943
+ function handlePtyInput(h, args) {
19944
+ const { cliType, data } = args || {};
19945
+ if (!data) return { success: false, error: "data required" };
19946
+ if (h.ctx.adapters) {
19947
+ const targetCli = cliType || "";
19948
+ if (!targetCli && h.ctx.adapters.size > 0) {
19949
+ const first = h.ctx.adapters.values().next().value;
19950
+ if (first && typeof first.writeRaw === "function") {
19951
+ first.writeRaw(data);
20266
19952
  return { success: true };
20267
19953
  }
20268
- for (const [, adapter] of this.ctx.adapters) {
20269
- if (adapter.cliType === targetCli && typeof adapter.writeRaw === "function") {
20270
- adapter.writeRaw(data);
20271
- return { success: true };
20272
- }
19954
+ }
19955
+ const directAdapter = h.ctx.adapters.get(targetCli);
19956
+ if (directAdapter && typeof directAdapter.writeRaw === "function") {
19957
+ directAdapter.writeRaw(data);
19958
+ return { success: true };
19959
+ }
19960
+ for (const [, adapter] of h.ctx.adapters) {
19961
+ if (adapter.cliType === targetCli && typeof adapter.writeRaw === "function") {
19962
+ adapter.writeRaw(data);
19963
+ return { success: true };
20273
19964
  }
20274
- for (const [key, adapter] of this.ctx.adapters) {
20275
- if ((key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.writeRaw === "function") {
20276
- adapter.writeRaw(data);
20277
- return { success: true };
20278
- }
19965
+ }
19966
+ for (const [key, adapter] of h.ctx.adapters) {
19967
+ if ((key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.writeRaw === "function") {
19968
+ adapter.writeRaw(data);
19969
+ return { success: true };
20279
19970
  }
20280
19971
  }
20281
- return { success: false, error: `CLI adapter not found: ${cliType}` };
20282
19972
  }
20283
- handlePtyResize(args) {
20284
- const { cliType, cols, rows, force } = args || {};
20285
- if (!cols || !rows) return { success: false, error: "cols and rows required" };
20286
- if (this.ctx.adapters) {
20287
- const targetCli = cliType || "";
20288
- if (!targetCli && this.ctx.adapters.size > 0) {
20289
- const first = this.ctx.adapters.values().next().value;
20290
- if (first && typeof first.resize === "function") {
20291
- if (force) {
20292
- first.resize(cols - 1, rows);
20293
- setTimeout(() => first.resize(cols, rows), 50);
20294
- } else {
20295
- first.resize(cols, rows);
20296
- }
20297
- return { success: true };
19973
+ return { success: false, error: `CLI adapter not found: ${cliType}` };
19974
+ }
19975
+ function handlePtyResize(h, args) {
19976
+ const { cliType, cols, rows, force } = args || {};
19977
+ if (!cols || !rows) return { success: false, error: "cols and rows required" };
19978
+ if (h.ctx.adapters) {
19979
+ const targetCli = cliType || "";
19980
+ if (!targetCli && h.ctx.adapters.size > 0) {
19981
+ const first = h.ctx.adapters.values().next().value;
19982
+ if (first && typeof first.resize === "function") {
19983
+ if (force) {
19984
+ first.resize(cols - 1, rows);
19985
+ setTimeout(() => first.resize(cols, rows), 50);
19986
+ } else {
19987
+ first.resize(cols, rows);
20298
19988
  }
19989
+ return { success: true };
19990
+ }
19991
+ }
19992
+ const directAdapter = h.ctx.adapters.get(targetCli);
19993
+ if (directAdapter && typeof directAdapter.resize === "function") {
19994
+ if (force) {
19995
+ directAdapter.resize(cols - 1, rows);
19996
+ setTimeout(() => directAdapter.resize(cols, rows), 50);
19997
+ } else {
19998
+ directAdapter.resize(cols, rows);
20299
19999
  }
20300
- const directAdapter = this.ctx.adapters.get(targetCli);
20301
- if (directAdapter && typeof directAdapter.resize === "function") {
20000
+ return { success: true };
20001
+ }
20002
+ for (const [key, adapter] of h.ctx.adapters) {
20003
+ if ((adapter.cliType === targetCli || key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.resize === "function") {
20302
20004
  if (force) {
20303
- directAdapter.resize(cols - 1, rows);
20304
- setTimeout(() => directAdapter.resize(cols, rows), 50);
20005
+ adapter.resize(cols - 1, rows);
20006
+ setTimeout(() => adapter.resize(cols, rows), 50);
20305
20007
  } else {
20306
- directAdapter.resize(cols, rows);
20008
+ adapter.resize(cols, rows);
20307
20009
  }
20308
20010
  return { success: true };
20309
20011
  }
20310
- for (const [key, adapter] of this.ctx.adapters) {
20311
- if ((adapter.cliType === targetCli || key.startsWith(targetCli) || targetCli.startsWith(adapter.cliType)) && typeof adapter.resize === "function") {
20312
- if (force) {
20313
- adapter.resize(cols - 1, rows);
20314
- setTimeout(() => adapter.resize(cols, rows), 50);
20315
- } else {
20316
- adapter.resize(cols, rows);
20317
- }
20318
- return { success: true };
20012
+ }
20013
+ }
20014
+ return { success: false, error: `CLI adapter not found: ${cliType}` };
20015
+ }
20016
+ function handleGetProviderSettings(h, args) {
20017
+ const loader = h.ctx.providerLoader;
20018
+ const { providerType } = args || {};
20019
+ if (providerType) {
20020
+ const schema = loader?.getPublicSettings(providerType) || [];
20021
+ const values = loader?.getSettings(providerType) || {};
20022
+ return { success: true, providerType, schema, values };
20023
+ }
20024
+ const allSettings = loader?.getAllPublicSettings() || {};
20025
+ const allValues = {};
20026
+ for (const type of Object.keys(allSettings)) {
20027
+ allValues[type] = loader?.getSettings(type) || {};
20028
+ }
20029
+ return { success: true, settings: allSettings, values: allValues };
20030
+ }
20031
+ function handleSetProviderSetting(h, args) {
20032
+ const loader = h.ctx.providerLoader;
20033
+ const { providerType, key, value } = args || {};
20034
+ if (!providerType || !key || value === void 0) {
20035
+ return { success: false, error: "providerType, key, and value are required" };
20036
+ }
20037
+ const result = loader?.setSetting(providerType, key, value);
20038
+ if (result) {
20039
+ if (h.ctx.instanceManager) {
20040
+ const allSettings = loader?.getSettings(providerType) || {};
20041
+ const updated = h.ctx.instanceManager.updateInstanceSettings(providerType, allSettings);
20042
+ LOG5.info("Command", `[set_provider_setting] ${providerType}.${key}=${JSON.stringify(value)} \u2192 ${updated} instance(s) updated`);
20043
+ }
20044
+ return { success: true, providerType, key, value };
20045
+ }
20046
+ return { success: false, error: `Failed to set ${providerType}.${key} \u2014 invalid key, value, or not a public setting` };
20047
+ }
20048
+ async function handleExtensionScript(h, args, scriptName) {
20049
+ const { agentType, ideType } = args || {};
20050
+ LOG5.info("Command", `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} _currentIdeType=${h.currentIdeType}`);
20051
+ if (!agentType) return { success: false, error: "agentType is required" };
20052
+ const loader = h.ctx.providerLoader;
20053
+ if (!loader) return { success: false, error: "ProviderLoader not initialized" };
20054
+ const provider2 = loader.resolve(agentType);
20055
+ if (!provider2) return { success: false, error: `Provider not found: ${agentType}` };
20056
+ const webviewScriptName = `webview${scriptName.charAt(0).toUpperCase() + scriptName.slice(1)}`;
20057
+ const hasWebviewScript = provider2.category === "ide" && !!provider2.scripts?.[webviewScriptName];
20058
+ const actualScriptName = hasWebviewScript ? webviewScriptName : scriptName;
20059
+ if (!provider2.scripts?.[actualScriptName]) {
20060
+ return { success: false, error: `Script '${actualScriptName}' not available for ${agentType}` };
20061
+ }
20062
+ const scriptFn = provider2.scripts[actualScriptName];
20063
+ const scriptCode = scriptFn(args);
20064
+ if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
20065
+ const cdpKey = provider2.category === "ide" ? h.currentIdeType || agentType : h.currentIdeType || ideType;
20066
+ LOG5.info("Command", `[ExtScript] provider=${provider2.type} category=${provider2.category} cdpKey=${cdpKey}`);
20067
+ const cdp2 = h.getCdp(cdpKey);
20068
+ if (!cdp2?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
20069
+ try {
20070
+ let result;
20071
+ if (provider2.category === "extension") {
20072
+ const sessions = cdp2.getAgentSessions();
20073
+ let targetSessionId = null;
20074
+ for (const [sessionId, target] of sessions) {
20075
+ if (target.agentType === agentType) {
20076
+ targetSessionId = sessionId;
20077
+ break;
20319
20078
  }
20320
20079
  }
20080
+ if (!targetSessionId) {
20081
+ return { success: false, error: `No active session found for ${agentType}` };
20082
+ }
20083
+ result = await cdp2.evaluateInSession(targetSessionId, scriptCode);
20084
+ } else if (hasWebviewScript && cdp2.evaluateInWebviewFrame) {
20085
+ const matchText = provider2.webviewMatchText;
20086
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
20087
+ result = await cdp2.evaluateInWebviewFrame(scriptCode, matchFn);
20088
+ } else {
20089
+ result = await cdp2.evaluate(scriptCode, 3e4);
20090
+ }
20091
+ if (typeof result === "string") {
20092
+ try {
20093
+ const parsed = JSON.parse(result);
20094
+ return { success: true, ...parsed };
20095
+ } catch {
20096
+ return { success: true, result };
20097
+ }
20098
+ }
20099
+ return { success: true, result };
20100
+ } catch (e) {
20101
+ return { success: false, error: `Script execution failed: ${e.message}` };
20102
+ }
20103
+ }
20104
+ function handleGetIdeExtensions(h, args) {
20105
+ const { ideType } = args || {};
20106
+ const loader = h.ctx.providerLoader;
20107
+ if (!loader) return { success: false, error: "ProviderLoader not initialized" };
20108
+ const allExtProviders = loader.getByCategory?.("extension") || [];
20109
+ const config2 = loadConfig4();
20110
+ if (ideType) {
20111
+ const extensions = allExtProviders.map((p) => ({
20112
+ type: p.type,
20113
+ name: p.name,
20114
+ extensionId: p.extensionId,
20115
+ enabled: config2.ideSettings?.[ideType]?.extensions?.[p.type]?.enabled === true
20116
+ }));
20117
+ return { success: true, ideType, extensions };
20118
+ }
20119
+ const connectedIdes = [...h.ctx.cdpManagers?.keys?.() || []];
20120
+ const result = {};
20121
+ for (const ide of connectedIdes) {
20122
+ result[ide] = allExtProviders.map((p) => ({
20123
+ type: p.type,
20124
+ name: p.name,
20125
+ extensionId: p.extensionId,
20126
+ enabled: config2.ideSettings?.[ide]?.extensions?.[p.type]?.enabled === true
20127
+ }));
20128
+ }
20129
+ return { success: true, ides: result };
20130
+ }
20131
+ function handleSetIdeExtension(h, args) {
20132
+ const { ideType, extensionType, enabled } = args || {};
20133
+ if (!ideType || !extensionType || enabled === void 0) {
20134
+ return { success: false, error: "ideType, extensionType, and enabled are required" };
20135
+ }
20136
+ const loader = h.ctx.providerLoader;
20137
+ if (!loader?.setIdeExtensionEnabled) {
20138
+ return { success: false, error: "ProviderLoader not initialized" };
20139
+ }
20140
+ const ok = loader.setIdeExtensionEnabled(ideType, extensionType, !!enabled);
20141
+ if (ok) {
20142
+ return { success: true, ideType, extensionType, enabled: !!enabled };
20143
+ }
20144
+ return { success: false, error: "Failed to save setting" };
20145
+ }
20146
+ var DaemonCommandHandler = class {
20147
+ _ctx;
20148
+ _agentStream = null;
20149
+ domHandlers;
20150
+ _historyWriter;
20151
+ /** Current IDE type extracted from command args (per-request) */
20152
+ _currentIdeType;
20153
+ /** Current provider type — agentType priority, ideType use */
20154
+ _currentProviderType;
20155
+ constructor(ctx) {
20156
+ this._ctx = ctx;
20157
+ this.domHandlers = new CdpDomHandlers((ideType) => this.getCdp(ideType));
20158
+ this._historyWriter = new ChatHistoryWriter();
20159
+ }
20160
+ // ─── CommandHelpers implementation ─────────────────
20161
+ get ctx() {
20162
+ return this._ctx;
20163
+ }
20164
+ get agentStream() {
20165
+ return this._agentStream;
20166
+ }
20167
+ get historyWriter() {
20168
+ return this._historyWriter;
20169
+ }
20170
+ get currentIdeType() {
20171
+ return this._currentIdeType;
20172
+ }
20173
+ get currentProviderType() {
20174
+ return this._currentProviderType;
20175
+ }
20176
+ /** Get CDP manager for a specific ideType.
20177
+ * Returns null if no match — never falls back to another IDE. */
20178
+ getCdp(ideType) {
20179
+ const key = ideType || this._currentIdeType;
20180
+ if (!key) return null;
20181
+ const m = this._ctx.cdpManagers.get(key.toLowerCase());
20182
+ if (m?.isConnected) return m;
20183
+ return null;
20184
+ }
20185
+ /**
20186
+ * Get provider module — _currentProviderType (agentType priority) use.
20187
+ */
20188
+ getProvider(overrideType) {
20189
+ const key = overrideType || this._currentProviderType || this._currentIdeType;
20190
+ if (!key || !this._ctx.providerLoader) return void 0;
20191
+ const result = this._ctx.providerLoader.resolve(key);
20192
+ if (result) return result;
20193
+ const baseType = key.split("_")[0];
20194
+ if (baseType !== key) return this._ctx.providerLoader.resolve(baseType);
20195
+ return void 0;
20196
+ }
20197
+ /** Get a provider script by name from ProviderLoader. */
20198
+ getProviderScript(scriptName, params, ideType) {
20199
+ const provider2 = this.getProvider(ideType);
20200
+ if (provider2?.scripts) {
20201
+ const fn = provider2.scripts[scriptName];
20202
+ if (typeof fn === "function") {
20203
+ const firstVal = params ? Object.values(params)[0] : void 0;
20204
+ const script = firstVal ? fn(firstVal) : fn();
20205
+ if (script) return script;
20206
+ }
20207
+ }
20208
+ return null;
20209
+ }
20210
+ /**
20211
+ * per-category CDP script execute:
20212
+ * IDE → cdp.evaluate(script) (main window)
20213
+ * Extension → cdp.evaluateInSession(sessionId, script) (webview)
20214
+ */
20215
+ async evaluateProviderScript(scriptName, params, timeout = 3e4) {
20216
+ const provider2 = this.getProvider();
20217
+ const script = this.getProviderScript(scriptName, params);
20218
+ if (!script) return null;
20219
+ const cdp2 = this.getCdp();
20220
+ if (!cdp2?.isConnected) return null;
20221
+ if (provider2?.category === "extension") {
20222
+ let sessionId = this.getExtensionSessionId(provider2);
20223
+ if (!sessionId && this._agentStream) {
20224
+ await this._agentStream.switchActiveAgent(cdp2, provider2.type);
20225
+ await this._agentStream.syncAgentSessions(cdp2);
20226
+ sessionId = this.getExtensionSessionId(provider2);
20227
+ }
20228
+ if (!sessionId) return null;
20229
+ const result2 = await cdp2.evaluateInSession(sessionId, script, timeout);
20230
+ return { result: result2, category: "extension" };
20231
+ }
20232
+ const result = await cdp2.evaluate(script, timeout);
20233
+ return { result, category: provider2?.category || "ide" };
20234
+ }
20235
+ /** CLI adapter search */
20236
+ getCliAdapter(type) {
20237
+ const target = type || this._currentIdeType;
20238
+ if (!target || !this._ctx.adapters) return null;
20239
+ for (const [key, adapter] of this._ctx.adapters.entries()) {
20240
+ if (adapter.cliType === target || key.startsWith(target)) {
20241
+ return adapter;
20242
+ }
20321
20243
  }
20322
- return { success: false, error: `CLI adapter not found: ${cliType}` };
20244
+ return null;
20323
20245
  }
20324
- // ─── Provider Settings ────────────────────────
20325
- handleGetProviderSettings(args) {
20326
- const { providerType } = args || {};
20327
- if (providerType) {
20328
- const schema = this.ctx.providerLoader?.getPublicSettings?.(providerType) || [];
20329
- const values = this.ctx.providerLoader?.getSettings?.(providerType) || {};
20330
- return { success: true, providerType, schema, values };
20331
- }
20332
- const allSettings = this.ctx.providerLoader?.getAllPublicSettings?.() || {};
20333
- const allValues = {};
20334
- for (const type of Object.keys(allSettings)) {
20335
- allValues[type] = this.ctx.providerLoader?.getSettings?.(type) || {};
20336
- }
20337
- return { success: true, settings: allSettings, values: allValues };
20246
+ // ─── Private helpers ──────────────────────────────
20247
+ getExtensionSessionId(provider2) {
20248
+ if (provider2.category !== "extension" || !this._agentStream) return null;
20249
+ const managed = this._agentStream.getManagedAgent(provider2.type);
20250
+ return managed?.sessionId || null;
20338
20251
  }
20339
- handleSetProviderSetting(args) {
20340
- const { providerType, key, value } = args || {};
20341
- if (!providerType || !key || value === void 0) {
20342
- return { success: false, error: "providerType, key, and value are required" };
20343
- }
20344
- const result = this.ctx.providerLoader?.setSetting?.(providerType, key, value);
20345
- if (result) {
20346
- if (this.ctx.instanceManager) {
20347
- const allSettings = this.ctx.providerLoader?.getSettings?.(providerType) || {};
20348
- const updated = this.ctx.instanceManager.updateInstanceSettings(providerType, allSettings);
20349
- LOG4.info("Command", `[set_provider_setting] ${providerType}.${key}=${JSON.stringify(value)} \u2192 ${updated} instance(s) updated`);
20252
+ /** Extract ideType from _targetInstance */
20253
+ extractIdeType(args) {
20254
+ if (args?._targetInstance) {
20255
+ let raw = args._targetInstance;
20256
+ const ideMatch = raw.match(/:ide:(.+)$/);
20257
+ const cliMatch = raw.match(/:cli:(.+)$/);
20258
+ const acpMatch = raw.match(/:acp:(.+)$/);
20259
+ if (ideMatch) raw = ideMatch[1];
20260
+ else if (cliMatch) raw = cliMatch[1];
20261
+ else if (acpMatch) raw = acpMatch[1];
20262
+ if (this._ctx.instanceIdMap?.has(raw)) {
20263
+ return this._ctx.instanceIdMap.get(raw);
20350
20264
  }
20351
- return { success: true, providerType, key, value };
20265
+ const lastUnderscore = raw.lastIndexOf("_");
20266
+ if (lastUnderscore > 0) return raw.substring(0, lastUnderscore);
20267
+ return raw;
20352
20268
  }
20353
- return { success: false, error: `Failed to set ${providerType}.${key} \u2014 invalid key, value, or not a public setting` };
20269
+ return void 0;
20354
20270
  }
20355
- // ─── Extension Script Execution (Model/Mode) ─────
20356
- /**
20357
- * Generic handler for executing Extension provider CDP scripts.
20358
- * args: { agentType, ideType?, model?, mode?, ... }
20359
- * scriptName: 'listModels' | 'setModel' | 'listModes' | 'setMode'
20360
- */
20361
- async handleExtensionScript(args, scriptName) {
20362
- const { agentType, ideType } = args || {};
20363
- LOG4.info("Command", `[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} _currentIdeType=${this._currentIdeType}`);
20364
- if (!agentType) return { success: false, error: "agentType is required" };
20365
- const loader = this.ctx.providerLoader;
20366
- if (!loader) return { success: false, error: "ProviderLoader not initialized" };
20367
- const provider2 = loader.resolve(agentType);
20368
- if (!provider2) return { success: false, error: `Provider not found: ${agentType}` };
20369
- const webviewScriptName = `webview${scriptName.charAt(0).toUpperCase() + scriptName.slice(1)}`;
20370
- const hasWebviewScript = provider2.category === "ide" && !!provider2.scripts?.[webviewScriptName];
20371
- const actualScriptName = hasWebviewScript ? webviewScriptName : scriptName;
20372
- if (!provider2.scripts?.[actualScriptName]) {
20373
- return { success: false, error: `Script '${actualScriptName}' not available for ${agentType}` };
20374
- }
20375
- const scriptFn = provider2.scripts[actualScriptName];
20376
- const scriptCode = scriptFn(args);
20377
- if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
20378
- const cdpKey = provider2.category === "ide" ? this._currentIdeType || agentType : this._currentIdeType || ideType;
20379
- LOG4.info("Command", `[ExtScript] provider=${provider2.type} category=${provider2.category} cdpKey=${cdpKey}`);
20380
- const cdp2 = this.getCdp(cdpKey);
20381
- if (!cdp2?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
20382
- try {
20383
- let result;
20384
- if (provider2.category === "extension") {
20385
- const sessions = cdp2.getAgentSessions();
20386
- let targetSessionId = null;
20387
- for (const [sessionId, target] of sessions) {
20388
- if (target.agentType === agentType) {
20389
- targetSessionId = sessionId;
20390
- break;
20391
- }
20392
- }
20393
- if (!targetSessionId) {
20394
- return { success: false, error: `No active session found for ${agentType}` };
20395
- }
20396
- result = await cdp2.evaluateInSession(targetSessionId, scriptCode);
20397
- } else if (hasWebviewScript && cdp2.evaluateInWebviewFrame) {
20398
- const matchText = provider2.webviewMatchText;
20399
- const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
20400
- result = await cdp2.evaluateInWebviewFrame(scriptCode, matchFn);
20401
- } else {
20402
- result = await cdp2.evaluate(scriptCode, 3e4);
20271
+ setAgentStreamManager(manager) {
20272
+ this._agentStream = manager;
20273
+ }
20274
+ // ─── Command Dispatcher ──────────────────────────
20275
+ async handle(cmd, args) {
20276
+ this._currentIdeType = this.extractIdeType(args);
20277
+ this._currentProviderType = args?.agentType || args?.providerType || this._currentIdeType;
20278
+ if (!this._currentIdeType && !this._currentProviderType) {
20279
+ const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
20280
+ if (cdpCommands.includes(cmd)) {
20281
+ return { success: false, error: "No ideType specified \u2014 cannot route command" };
20403
20282
  }
20404
- if (typeof result === "string") {
20405
- try {
20406
- const parsed = JSON.parse(result);
20407
- return { success: true, ...parsed };
20408
- } catch {
20409
- return { success: true, result };
20283
+ }
20284
+ try {
20285
+ return await this.dispatch(cmd, args);
20286
+ } catch (e) {
20287
+ LOG5.error("Command", `[${cmd}] Unhandled error: ${e?.message || e}`);
20288
+ return { success: false, error: `Internal error: ${e?.message || "unknown"}` };
20289
+ }
20290
+ }
20291
+ async dispatch(cmd, args) {
20292
+ switch (cmd) {
20293
+ // ─── Chat commands (chat-commands.ts) ───────────────
20294
+ case "read_chat":
20295
+ return handleReadChat(this, args);
20296
+ case "chat_history":
20297
+ return handleChatHistory(this, args);
20298
+ case "send_chat":
20299
+ return handleSendChat(this, args);
20300
+ case "list_chats":
20301
+ return handleListChats(this, args);
20302
+ case "new_chat":
20303
+ return handleNewChat(this, args);
20304
+ case "switch_chat":
20305
+ return handleSwitchChat(this, args);
20306
+ case "set_mode":
20307
+ return handleSetMode(this, args);
20308
+ case "change_model":
20309
+ return handleChangeModel(this, args);
20310
+ case "set_thought_level":
20311
+ return handleSetThoughtLevel(this, args);
20312
+ case "resolve_action":
20313
+ return handleResolveAction(this, args);
20314
+ // ─── CDP commands (cdp-commands.ts) ───────────────
20315
+ case "cdp_eval":
20316
+ return handleCdpEval(this, args);
20317
+ case "cdp_screenshot":
20318
+ case "screenshot":
20319
+ return handleScreenshot(this, args);
20320
+ case "cdp_command_exec":
20321
+ return handleCdpCommand(this, args);
20322
+ case "cdp_batch":
20323
+ return handleCdpBatch(this, args);
20324
+ case "cdp_remote_action":
20325
+ return handleCdpRemoteAction(this, args);
20326
+ case "cdp_discover_agents":
20327
+ return handleDiscoverAgents(this, args);
20328
+ case "cdp_dom_dump":
20329
+ return this.domHandlers.handleDomDump(args);
20330
+ case "cdp_dom_query":
20331
+ return this.domHandlers.handleDomQuery(args);
20332
+ case "cdp_dom_debug":
20333
+ return this.domHandlers.handleDomDebug(args);
20334
+ // ─── File commands (cdp-commands.ts) ──────────────
20335
+ case "file_read":
20336
+ return handleFileRead(this, args);
20337
+ case "file_write":
20338
+ return handleFileWrite(this, args);
20339
+ case "file_list":
20340
+ return handleFileList(this, args);
20341
+ case "file_list_browse":
20342
+ return handleFileListBrowse(this, args);
20343
+ // ─── VSCode API commands (not available) ────
20344
+ case "vscode_command_exec":
20345
+ case "execute_vscode_command": {
20346
+ const resolvedCmd = args?.commandId || args?.command;
20347
+ if (resolvedCmd === "adhdev.captureCdpScreenshot") {
20348
+ return handleScreenshot(this, args);
20410
20349
  }
20350
+ return { success: false, error: `VSCode command not available: ${resolvedCmd || cmd}` };
20411
20351
  }
20412
- return { success: true, result };
20413
- } catch (e) {
20414
- return { success: false, error: `Script execution failed: ${e.message}` };
20352
+ case "get_open_editors":
20353
+ case "open_tab":
20354
+ case "close_tab":
20355
+ case "open_folder":
20356
+ case "open_folder_picker":
20357
+ case "open_recent":
20358
+ case "get_commands":
20359
+ return { success: false, error: `${cmd} requires bridge-extension (removed)` };
20360
+ case "get_recent_workspaces":
20361
+ return this.handleGetRecentWorkspaces(args);
20362
+ // ─── Script manage ───────────────────
20363
+ case "refresh_scripts":
20364
+ return this.handleRefreshScripts(args);
20365
+ // ─── Stream commands (stream-commands.ts) ───────────
20366
+ case "agent_stream_switch":
20367
+ return handleAgentStreamSwitch(this, args);
20368
+ case "agent_stream_read":
20369
+ return handleAgentStreamRead(this, args);
20370
+ case "agent_stream_send":
20371
+ return handleAgentStreamSend(this, args);
20372
+ case "agent_stream_resolve":
20373
+ return handleAgentStreamResolve(this, args);
20374
+ case "agent_stream_new":
20375
+ return handleAgentStreamNew(this, args);
20376
+ case "agent_stream_list_chats":
20377
+ return handleAgentStreamListChats(this, args);
20378
+ case "agent_stream_switch_session":
20379
+ return handleAgentStreamSwitchSession(this, args);
20380
+ case "agent_stream_focus":
20381
+ return handleAgentStreamFocus(this, args);
20382
+ // ─── PTY Raw I/O (stream-commands.ts) ─────────
20383
+ case "pty_input":
20384
+ return handlePtyInput(this, args);
20385
+ case "pty_resize":
20386
+ return handlePtyResize(this, args);
20387
+ // ─── Provider Settings (stream-commands.ts) ──────────
20388
+ case "get_provider_settings":
20389
+ return handleGetProviderSettings(this, args);
20390
+ case "set_provider_setting":
20391
+ return handleSetProviderSetting(this, args);
20392
+ // ─── IDE Extension Settings (stream-commands.ts) ──────────
20393
+ case "get_ide_extensions":
20394
+ return handleGetIdeExtensions(this, args);
20395
+ case "set_ide_extension":
20396
+ return handleSetIdeExtension(this, args);
20397
+ // ─── Extension Model / Mode Control (stream-commands.ts) ──────────
20398
+ case "list_extension_models":
20399
+ return handleExtensionScript(this, args, "listModels");
20400
+ case "set_extension_model":
20401
+ return handleExtensionScript(this, args, "setModel");
20402
+ case "list_extension_modes":
20403
+ return handleExtensionScript(this, args, "listModes");
20404
+ case "set_extension_mode":
20405
+ return handleExtensionScript(this, args, "setMode");
20406
+ default:
20407
+ return { success: false, error: `Unknown command: ${cmd}` };
20415
20408
  }
20416
20409
  }
20417
- // ─── IDE Extension Settings (per-IDE on/off) ─────
20418
- handleGetIdeExtensions(args) {
20419
- const { ideType } = args || {};
20420
- const loader = this.ctx.providerLoader;
20421
- if (!loader) return { success: false, error: "ProviderLoader not initialized" };
20422
- const allExtProviders = loader.getByCategory?.("extension") || [];
20410
+ // ─── Misc (kept in handler — too small to extract) ───────
20411
+ async handleGetRecentWorkspaces(args) {
20423
20412
  const config2 = loadConfig4();
20424
- if (ideType) {
20425
- const extensions = allExtProviders.map((p) => ({
20426
- type: p.type,
20427
- name: p.name,
20428
- extensionId: p.extensionId,
20429
- enabled: config2.ideSettings?.[ideType]?.extensions?.[p.type]?.enabled === true
20430
- }));
20431
- return { success: true, ideType, extensions };
20432
- }
20433
- const connectedIdes = [...this.ctx.cdpManagers?.keys?.() || []];
20434
- const result = {};
20435
- for (const ide of connectedIdes) {
20436
- result[ide] = allExtProviders.map((p) => ({
20437
- type: p.type,
20438
- name: p.name,
20439
- extensionId: p.extensionId,
20440
- enabled: config2.ideSettings?.[ide]?.extensions?.[p.type]?.enabled === true
20441
- }));
20442
- }
20443
- return { success: true, ides: result };
20413
+ const cliRecent = config2.recentCliWorkspaces || [];
20414
+ return { success: true, result: cliRecent };
20444
20415
  }
20445
- handleSetIdeExtension(args) {
20446
- const { ideType, extensionType, enabled } = args || {};
20447
- if (!ideType || !extensionType || enabled === void 0) {
20448
- return { success: false, error: "ideType, extensionType, and enabled are required" };
20449
- }
20450
- const loader = this.ctx.providerLoader;
20451
- if (!loader?.setIdeExtensionEnabled) {
20452
- return { success: false, error: "ProviderLoader not initialized" };
20453
- }
20454
- const ok = loader.setIdeExtensionEnabled(ideType, extensionType, !!enabled);
20455
- if (ok) {
20456
- return { success: true, ideType, extensionType, enabled: !!enabled };
20416
+ async handleRefreshScripts(_args) {
20417
+ if (this._ctx.providerLoader) {
20418
+ this._ctx.providerLoader.reload();
20419
+ return { success: true };
20457
20420
  }
20458
- return { success: false, error: "Failed to save setting" };
20421
+ return { success: false, error: "ProviderLoader not initialized" };
20459
20422
  }
20460
20423
  };
20461
20424
  var import_child_process3 = require("child_process");
@@ -20488,7 +20451,7 @@ var require_dist = __commonJS({
20488
20451
  }
20489
20452
  this.userDir = options?.userDir || path4.join(os5.homedir(), ".adhdev", "providers");
20490
20453
  this.upstreamDir = path4.join(this.userDir, ".upstream");
20491
- this.logFn = options?.logFn || LOG4.forComponent("Provider").asLogFn();
20454
+ this.logFn = options?.logFn || LOG5.forComponent("Provider").asLogFn();
20492
20455
  }
20493
20456
  log(msg) {
20494
20457
  this.logFn(`[ProviderLoader] ${msg}`);
@@ -21932,18 +21895,18 @@ var require_dist = __commonJS({
21932
21895
  case "launch_ide": {
21933
21896
  const launchArgs = { ...args, ideId: args?.ideId || args?.ideType };
21934
21897
  const ideKey = launchArgs.ideId;
21935
- LOG4.info("LaunchIDE", `target=${ideKey || "auto"}`);
21898
+ LOG5.info("LaunchIDE", `target=${ideKey || "auto"}`);
21936
21899
  const result = await launchWithCdp2(launchArgs);
21937
21900
  if (result.success && result.port && result.ideId && !this.deps.cdpManagers.has(result.ideId)) {
21938
- const logFn = this.deps.getCdpLogFn ? this.deps.getCdpLogFn(result.ideId) : LOG4.forComponent(`CDP:${result.ideId}`).asLogFn();
21901
+ const logFn = this.deps.getCdpLogFn ? this.deps.getCdpLogFn(result.ideId) : LOG5.forComponent(`CDP:${result.ideId}`).asLogFn();
21939
21902
  const provider2 = this.deps.providerLoader.getMeta(result.ideId);
21940
21903
  const manager = new DaemonCdpManager2(result.port, logFn, void 0, provider2?.targetFilter);
21941
21904
  const connected = await manager.connect();
21942
21905
  if (connected) {
21943
21906
  registerExtensionProviders(this.deps.providerLoader, manager, result.ideId);
21944
21907
  this.deps.cdpManagers.set(result.ideId, manager);
21945
- LOG4.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
21946
- LOG4.info("CDP", `${this.deps.cdpManagers.size} IDE(s) connected`);
21908
+ LOG5.info("CDP", `Connected: ${result.ideId} (port ${result.port})`);
21909
+ LOG5.info("CDP", `${this.deps.cdpManagers.size} IDE(s) connected`);
21947
21910
  this.deps.onCdpManagerCreated?.(result.ideId, manager);
21948
21911
  }
21949
21912
  }
@@ -21969,7 +21932,7 @@ var require_dist = __commonJS({
21969
21932
  } catch {
21970
21933
  }
21971
21934
  this.deps.cdpManagers.delete(ideType);
21972
- LOG4.info("StopIDE", `CDP disconnected: ${ideType}`);
21935
+ LOG5.info("StopIDE", `CDP disconnected: ${ideType}`);
21973
21936
  }
21974
21937
  const instanceKey = `ide:${ideType}`;
21975
21938
  const ideInstance = this.deps.instanceManager.getInstance(instanceKey);
@@ -21983,10 +21946,10 @@ var require_dist = __commonJS({
21983
21946
  }
21984
21947
  }
21985
21948
  this.deps.instanceManager.removeInstance(instanceKey);
21986
- LOG4.info("StopIDE", `Instance removed: ${instanceKey}`);
21949
+ LOG5.info("StopIDE", `Instance removed: ${instanceKey}`);
21987
21950
  }
21988
21951
  this.deps.onStatusChange?.();
21989
- LOG4.info("StopIDE", `IDE stopped: ${ideType}`);
21952
+ LOG5.info("StopIDE", `IDE stopped: ${ideType}`);
21990
21953
  }
21991
21954
  };
21992
21955
  var os8 = __toESM2(require("os"));
@@ -22002,23 +21965,23 @@ var require_dist = __commonJS({
22002
21965
  p2pTimer = null;
22003
21966
  constructor(deps, opts) {
22004
21967
  this.deps = deps;
22005
- this.log = opts?.logFn || LOG4.forComponent("Status").asLogFn();
21968
+ this.log = opts?.logFn || LOG5.forComponent("Status").asLogFn();
22006
21969
  }
22007
21970
  // ─── Lifecycle ───────────────────────────────────
22008
21971
  startReporting() {
22009
21972
  setTimeout(() => {
22010
- this.sendUnifiedStatusReport().catch((e) => LOG4.warn("Status", `Initial report failed: ${e?.message}`));
21973
+ this.sendUnifiedStatusReport().catch((e) => LOG5.warn("Status", `Initial report failed: ${e?.message}`));
22011
21974
  }, 2e3);
22012
21975
  const scheduleServerReport = () => {
22013
21976
  this.statusTimer = setTimeout(() => {
22014
- this.sendUnifiedStatusReport().catch((e) => LOG4.warn("Status", `Periodic report failed: ${e?.message}`));
21977
+ this.sendUnifiedStatusReport().catch((e) => LOG5.warn("Status", `Periodic report failed: ${e?.message}`));
22015
21978
  scheduleServerReport();
22016
21979
  }, 3e4);
22017
21980
  };
22018
21981
  scheduleServerReport();
22019
21982
  this.p2pTimer = setInterval(() => {
22020
21983
  if (this.deps.p2p?.isConnected) {
22021
- this.sendUnifiedStatusReport({ p2pOnly: true }).catch((e) => LOG4.warn("Status", `P2P status send failed: ${e?.message}`));
21984
+ this.sendUnifiedStatusReport({ p2pOnly: true }).catch((e) => LOG5.warn("Status", `P2P status send failed: ${e?.message}`));
22022
21985
  }
22023
21986
  }, 5e3);
22024
21987
  }
@@ -22039,17 +22002,17 @@ var require_dist = __commonJS({
22039
22002
  const now = Date.now();
22040
22003
  const elapsed = now - this.lastStatusSentAt;
22041
22004
  if (elapsed >= 5e3) {
22042
- this.sendUnifiedStatusReport().catch((e) => LOG4.warn("Status", `Throttled report failed: ${e?.message}`));
22005
+ this.sendUnifiedStatusReport().catch((e) => LOG5.warn("Status", `Throttled report failed: ${e?.message}`));
22043
22006
  } else if (!this.statusPendingThrottle) {
22044
22007
  this.statusPendingThrottle = true;
22045
22008
  setTimeout(() => {
22046
22009
  this.statusPendingThrottle = false;
22047
- this.sendUnifiedStatusReport().catch((e) => LOG4.warn("Status", `Deferred report failed: ${e?.message}`));
22010
+ this.sendUnifiedStatusReport().catch((e) => LOG5.warn("Status", `Deferred report failed: ${e?.message}`));
22048
22011
  }, 5e3 - elapsed);
22049
22012
  }
22050
22013
  }
22051
22014
  emitStatusEvent(event) {
22052
- LOG4.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
22015
+ LOG5.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
22053
22016
  this.deps.serverConn?.sendMessage("status_event", event);
22054
22017
  }
22055
22018
  removeAgentTracking(_key) {
@@ -22084,9 +22047,9 @@ var require_dist = __commonJS({
22084
22047
  if (summaryChanged) {
22085
22048
  this.lastStatusSummary = summary;
22086
22049
  if (logLevel === "debug") {
22087
- LOG4.debug("StatusReport", summary);
22050
+ LOG5.debug("StatusReport", summary);
22088
22051
  } else {
22089
- LOG4.info("StatusReport", summary);
22052
+ LOG5.info("StatusReport", summary);
22090
22053
  }
22091
22054
  }
22092
22055
  const managedIdes = ideStates.map((s) => ({
@@ -22171,7 +22134,7 @@ var require_dist = __commonJS({
22171
22134
  };
22172
22135
  const p2pSent = this.sendP2PPayload(payload);
22173
22136
  if (p2pSent) {
22174
- LOG4.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
22137
+ LOG5.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
22175
22138
  }
22176
22139
  if (opts?.p2pOnly) return;
22177
22140
  const plan = serverConn.getUserPlan();
@@ -22202,7 +22165,7 @@ var require_dist = __commonJS({
22202
22165
  timestamp: now
22203
22166
  };
22204
22167
  serverConn.sendMessage("status_report", wsPayload);
22205
- LOG4.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
22168
+ LOG5.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
22206
22169
  }
22207
22170
  }
22208
22171
  // ─── P2P ─────────────────────────────────────────
@@ -22239,7 +22202,7 @@ var require_dist = __commonJS({
22239
22202
  try {
22240
22203
  pty = require("node-pty");
22241
22204
  } catch {
22242
- LOG4.error("CLI", "[ProviderCliAdapter] node-pty not found. Install: npm install node-pty@1.0.0");
22205
+ LOG5.error("CLI", "[ProviderCliAdapter] node-pty not found. Install: npm install node-pty@1.0.0");
22243
22206
  }
22244
22207
  function stripAnsi(str) {
22245
22208
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
@@ -22319,7 +22282,7 @@ var require_dist = __commonJS({
22319
22282
  const binaryPath = findBinary(spawnConfig.command);
22320
22283
  const isWin = os9.platform() === "win32";
22321
22284
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
22322
- LOG4.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
22285
+ LOG5.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
22323
22286
  let shellCmd;
22324
22287
  let shellArgs;
22325
22288
  if (spawnConfig.shell) {
@@ -22356,7 +22319,7 @@ var require_dist = __commonJS({
22356
22319
  }
22357
22320
  });
22358
22321
  this.ptyProcess.onExit(({ exitCode }) => {
22359
- LOG4.info("CLI", `[${this.cliType}] Exit code ${exitCode}`);
22322
+ LOG5.info("CLI", `[${this.cliType}] Exit code ${exitCode}`);
22360
22323
  this.ptyProcess = null;
22361
22324
  this.currentStatus = "stopped";
22362
22325
  this.ready = false;
@@ -22391,7 +22354,7 @@ var require_dist = __commonJS({
22391
22354
  if (patterns.prompt.some((p) => p.test(this.startupBuffer))) {
22392
22355
  this.ready = true;
22393
22356
  this.currentStatus = "idle";
22394
- LOG4.info("CLI", `[${this.cliType}] \u2713 Ready`);
22357
+ LOG5.info("CLI", `[${this.cliType}] \u2713 Ready`);
22395
22358
  this.onStatusChange?.();
22396
22359
  }
22397
22360
  return;
@@ -22478,7 +22441,7 @@ var require_dist = __commonJS({
22478
22441
  if (response) {
22479
22442
  this.messages.push({ role: "assistant", content: response, timestamp: Date.now() });
22480
22443
  if (this.messages.length > 200) this.messages = this.messages.slice(-200);
22481
- LOG4.info("CLI", `[${this.cliType}] Response (${response.length} chars)`);
22444
+ LOG5.info("CLI", `[${this.cliType}] Response (${response.length} chars)`);
22482
22445
  }
22483
22446
  this.responseBuffer = "";
22484
22447
  this.isWaitingForResponse = false;
@@ -22718,6 +22681,10 @@ var require_dist = __commonJS({
22718
22681
  var import_stream = require("stream");
22719
22682
  var import_child_process5 = require("child_process");
22720
22683
  var import_sdk = (init_acp(), __toCommonJS(acp_exports));
22684
+ function flattenContent(content) {
22685
+ if (typeof content === "string") return content;
22686
+ return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
22687
+ }
22721
22688
  var AcpProviderInstance = class {
22722
22689
  constructor(provider2, workingDir, cliArgs = []) {
22723
22690
  this.cliArgs = cliArgs;
@@ -22729,7 +22696,7 @@ var require_dist = __commonJS({
22729
22696
  }
22730
22697
  type;
22731
22698
  category = "acp";
22732
- log = LOG4.forComponent("ACP");
22699
+ log = LOG5.forComponent("ACP");
22733
22700
  provider;
22734
22701
  context = null;
22735
22702
  settings = {};
@@ -22750,6 +22717,10 @@ var require_dist = __commonJS({
22750
22717
  activeToolCalls = [];
22751
22718
  stopReason = null;
22752
22719
  partialContent = "";
22720
+ /** Rich content blocks accumulated during streaming */
22721
+ partialBlocks = [];
22722
+ /** Tool calls collected during current turn */
22723
+ turnToolCalls = [];
22753
22724
  // Error tracking
22754
22725
  errorMessage = null;
22755
22726
  errorReason = null;
@@ -22784,18 +22755,23 @@ var require_dist = __commonJS({
22784
22755
  }
22785
22756
  getState() {
22786
22757
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
22787
- const recentMessages = this.messages.slice(-50).map((m) => ({
22788
- role: m.role,
22789
- content: m.content.length > 2e3 ? m.content.slice(0, 2e3) + "\n... (truncated)" : m.content,
22790
- timestamp: m.timestamp
22791
- }));
22792
- if (this.currentStatus === "generating" && this.partialContent) {
22793
- const cleaned = this.partialContent.trim();
22794
- if (cleaned) {
22758
+ const recentMessages = this.messages.slice(-50).map((m) => {
22759
+ const content = this.truncateContent(m.content);
22760
+ return {
22761
+ role: m.role,
22762
+ content,
22763
+ timestamp: m.timestamp,
22764
+ toolCalls: m.toolCalls
22765
+ };
22766
+ });
22767
+ if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
22768
+ const blocks = this.buildPartialBlocks();
22769
+ if (blocks.length > 0) {
22795
22770
  recentMessages.push({
22796
22771
  role: "assistant",
22797
- content: (cleaned.length > 2e3 ? cleaned.slice(0, 2e3) + "..." : cleaned) + "...",
22798
- timestamp: Date.now()
22772
+ content: blocks,
22773
+ timestamp: Date.now(),
22774
+ toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
22799
22775
  });
22800
22776
  }
22801
22777
  }
@@ -23241,49 +23217,49 @@ var require_dist = __commonJS({
23241
23217
  this.currentStatus = "idle";
23242
23218
  }
23243
23219
  }
23244
- async sendPrompt(text) {
23220
+ async sendPrompt(text, contentBlocks) {
23245
23221
  if (!this.connection || !this.sessionId) {
23246
23222
  this.log.warn(`[${this.type}] Cannot send prompt: no active connection/session`);
23247
23223
  return;
23248
23224
  }
23225
+ let promptParts;
23226
+ if (contentBlocks && contentBlocks.length > 0) {
23227
+ promptParts = contentBlocks.map((b) => {
23228
+ if (b.type === "text") return { type: "text", text: b.text };
23229
+ if (b.type === "image") return { type: "image", data: b.data, mimeType: b.mimeType };
23230
+ if (b.type === "resource_link") return { type: "resource_link", uri: b.uri, name: b.name };
23231
+ if (b.type === "resource") return { type: "resource", resource: b.resource };
23232
+ return { type: "text", text: flattenContent([b]) };
23233
+ });
23234
+ } else {
23235
+ promptParts = [{ type: "text", text }];
23236
+ }
23249
23237
  this.messages.push({
23250
23238
  role: "user",
23251
- content: text,
23239
+ content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
23252
23240
  timestamp: Date.now()
23253
23241
  });
23254
23242
  this.currentStatus = "generating";
23255
23243
  this.partialContent = "";
23244
+ this.partialBlocks = [];
23245
+ this.turnToolCalls = [];
23256
23246
  this.detectStatusTransition();
23257
- this.log.info(`[${this.type}] Sending prompt: "${text.slice(0, 100)}"`);
23247
+ this.log.info(`[${this.type}] Sending prompt: "${text.slice(0, 100)}" (${promptParts.length} parts)`);
23258
23248
  try {
23259
23249
  const result = await this.connection.prompt({
23260
23250
  sessionId: this.sessionId,
23261
- prompt: [{ type: "text", text }]
23251
+ prompt: promptParts
23262
23252
  });
23263
23253
  if (result?.stopReason) {
23264
23254
  this.stopReason = result.stopReason;
23265
23255
  }
23266
- this.log.info(`[${this.type}] Prompt completed: stopReason=${result?.stopReason} partialContent=${this.partialContent.length} chars`);
23267
- if (this.partialContent.trim()) {
23268
- this.messages.push({
23269
- role: "assistant",
23270
- content: this.partialContent.trim(),
23271
- timestamp: Date.now()
23272
- });
23273
- this.partialContent = "";
23274
- }
23256
+ this.log.info(`[${this.type}] Prompt completed: stopReason=${result?.stopReason} partialContent=${this.partialContent.length} chars partialBlocks=${this.partialBlocks.length}`);
23257
+ this.finalizeAssistantMessage();
23275
23258
  this.currentStatus = "idle";
23276
23259
  this.detectStatusTransition();
23277
23260
  } catch (e) {
23278
23261
  this.log.warn(`[${this.type}] prompt error: ${e?.message}`);
23279
- if (this.partialContent.trim()) {
23280
- this.messages.push({
23281
- role: "assistant",
23282
- content: this.partialContent.trim(),
23283
- timestamp: Date.now()
23284
- });
23285
- this.partialContent = "";
23286
- }
23262
+ this.finalizeAssistantMessage();
23287
23263
  this.currentStatus = "idle";
23288
23264
  this.detectStatusTransition();
23289
23265
  }
@@ -23317,6 +23293,27 @@ var require_dist = __commonJS({
23317
23293
  const content = update.content;
23318
23294
  if (content?.type === "text" && content.text) {
23319
23295
  this.partialContent += content.text;
23296
+ } else if (content?.type === "image") {
23297
+ this.partialBlocks.push({
23298
+ type: "image",
23299
+ data: content.data || "",
23300
+ mimeType: content.mimeType || "image/png",
23301
+ uri: content.uri
23302
+ });
23303
+ } else if (content?.type === "resource_link") {
23304
+ this.partialBlocks.push({
23305
+ type: "resource_link",
23306
+ uri: content.uri || "",
23307
+ name: content.name || "resource",
23308
+ title: content.title,
23309
+ mimeType: content.mimeType,
23310
+ size: content.size
23311
+ });
23312
+ } else if (content?.type === "resource") {
23313
+ this.partialBlocks.push({
23314
+ type: "resource",
23315
+ resource: content.resource
23316
+ });
23320
23317
  }
23321
23318
  this.currentStatus = "generating";
23322
23319
  break;
@@ -23326,12 +23323,26 @@ var require_dist = __commonJS({
23326
23323
  break;
23327
23324
  }
23328
23325
  case "tool_call": {
23326
+ const tcId = update.toolCallId || `tc_${Date.now()}`;
23327
+ const tcTitle = update.title || "unknown";
23328
+ const tcKind = update.kind;
23329
+ const tcStatus = this.mapToolCallStatus(update.status);
23329
23330
  this.activeToolCalls.push({
23330
- id: update.toolCallId || `tc_${Date.now()}`,
23331
- name: update.title || "unknown",
23332
- status: this.mapToolCallStatus(update.status) || "running",
23331
+ id: tcId,
23332
+ name: tcTitle,
23333
+ status: tcStatus,
23333
23334
  input: update.rawInput ? typeof update.rawInput === "string" ? update.rawInput : JSON.stringify(update.rawInput) : void 0
23334
23335
  });
23336
+ const acpStatus = update.status || "in_progress";
23337
+ this.turnToolCalls.push({
23338
+ toolCallId: tcId,
23339
+ title: tcTitle,
23340
+ kind: tcKind,
23341
+ status: acpStatus,
23342
+ rawInput: update.rawInput,
23343
+ content: this.convertToolCallContent(update.content),
23344
+ locations: update.locations
23345
+ });
23335
23346
  break;
23336
23347
  }
23337
23348
  case "tool_call_update": {
@@ -23341,6 +23352,13 @@ var require_dist = __commonJS({
23341
23352
  if (update.status) existing.status = this.mapToolCallStatus(update.status);
23342
23353
  if (update.rawOutput) existing.output = typeof update.rawOutput === "string" ? update.rawOutput : JSON.stringify(update.rawOutput);
23343
23354
  }
23355
+ const tcInfo = this.turnToolCalls.find((t) => t.toolCallId === toolCallId);
23356
+ if (tcInfo) {
23357
+ if (update.status) tcInfo.status = update.status;
23358
+ if (update.rawOutput) tcInfo.rawOutput = update.rawOutput;
23359
+ if (update.content) tcInfo.content = this.convertToolCallContent(update.content);
23360
+ if (update.locations) tcInfo.locations = update.locations;
23361
+ }
23344
23362
  break;
23345
23363
  }
23346
23364
  case "current_mode_update": {
@@ -23433,6 +23451,62 @@ var require_dist = __commonJS({
23433
23451
  return "running";
23434
23452
  }
23435
23453
  }
23454
+ // ─── Rich Content Helpers ────────────────────────────
23455
+ /** Truncate content for transport (text: 2000 chars, images preserved) */
23456
+ truncateContent(content) {
23457
+ if (typeof content === "string") {
23458
+ return content.length > 2e3 ? content.slice(0, 2e3) + "\n... (truncated)" : content;
23459
+ }
23460
+ return content.map((b) => {
23461
+ if (b.type === "text" && b.text.length > 2e3) {
23462
+ return { ...b, text: b.text.slice(0, 2e3) + "\n... (truncated)" };
23463
+ }
23464
+ return b;
23465
+ });
23466
+ }
23467
+ /** Build ContentBlock[] from current partial state */
23468
+ buildPartialBlocks() {
23469
+ const blocks = [];
23470
+ if (this.partialContent.trim()) {
23471
+ blocks.push({ type: "text", text: this.partialContent.trim() + "..." });
23472
+ }
23473
+ blocks.push(...this.partialBlocks);
23474
+ return blocks;
23475
+ }
23476
+ /** Finalize streaming content into an assistant message */
23477
+ finalizeAssistantMessage() {
23478
+ const blocks = this.buildPartialBlocks();
23479
+ const finalBlocks = blocks.map((b) => {
23480
+ if (b.type === "text" && b.text.endsWith("...")) {
23481
+ return { ...b, text: b.text.slice(0, -3) };
23482
+ }
23483
+ return b;
23484
+ }).filter((b) => b.type !== "text" || b.text.trim());
23485
+ if (finalBlocks.length > 0) {
23486
+ this.messages.push({
23487
+ role: "assistant",
23488
+ content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
23489
+ timestamp: Date.now(),
23490
+ toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
23491
+ });
23492
+ }
23493
+ this.partialContent = "";
23494
+ this.partialBlocks = [];
23495
+ this.turnToolCalls = [];
23496
+ }
23497
+ /** Convert ACP ToolCallContent[] to our ToolCallContent[] */
23498
+ convertToolCallContent(acpContent) {
23499
+ if (!acpContent || !Array.isArray(acpContent)) return void 0;
23500
+ return acpContent.map((c) => {
23501
+ if (c.type === "diff") {
23502
+ return { type: "diff", path: c.path || "", oldText: c.oldText, newText: c.newText || "" };
23503
+ }
23504
+ if (c.type === "terminal") {
23505
+ return { type: "terminal", terminalId: c.terminalId || "" };
23506
+ }
23507
+ return { type: "content", content: c.content || { type: "text", text: JSON.stringify(c) } };
23508
+ });
23509
+ }
23436
23510
  // ─── status transition detect ────────────────────────────
23437
23511
  detectStatusTransition() {
23438
23512
  const now = Date.now();
@@ -23570,13 +23644,13 @@ ${installInfo}`
23570
23644
  await acpInstance.setConfigOption("model", initialModel);
23571
23645
  console.log(import_chalk4.default.green(` \u{1F916} Initial model set: ${initialModel}`));
23572
23646
  } catch (e) {
23573
- LOG4.warn("CLI", `[ACP] Initial model set failed: ${e?.message}`);
23647
+ LOG5.warn("CLI", `[ACP] Initial model set failed: ${e?.message}`);
23574
23648
  }
23575
23649
  }
23576
23650
  try {
23577
23651
  addCliHistory({ cliType: normalizedType, dir: resolvedDir, cliArgs });
23578
23652
  } catch (e) {
23579
- LOG4.warn("CLI", `ACP history save failed: ${e?.message}`);
23653
+ LOG5.warn("CLI", `ACP history save failed: ${e?.message}`);
23580
23654
  }
23581
23655
  this.deps.onStatusChange();
23582
23656
  return;
@@ -23631,7 +23705,7 @@ ${installInfo}`
23631
23705
  try {
23632
23706
  addCliHistory({ cliType, dir: resolvedDir, cliArgs });
23633
23707
  } catch (e) {
23634
- LOG4.warn("CLI", `CLI history save failed: ${e?.message}`);
23708
+ LOG5.warn("CLI", `CLI history save failed: ${e?.message}`);
23635
23709
  }
23636
23710
  this.deps.onStatusChange();
23637
23711
  }
@@ -23880,7 +23954,7 @@ ${installInfo}`
23880
23954
  discoveryIntervalMs = 1e4;
23881
23955
  _activeAgentType = null;
23882
23956
  constructor(logFn, providerLoader) {
23883
- this.logFn = logFn || LOG4.forComponent("AgentStream").asLogFn();
23957
+ this.logFn = logFn || LOG5.forComponent("AgentStream").asLogFn();
23884
23958
  if (providerLoader) {
23885
23959
  const allExtProviders = providerLoader.getByCategory("extension");
23886
23960
  for (const p of allExtProviders) {
@@ -24155,7 +24229,7 @@ ${installInfo}`
24155
24229
  for (const extType of currentExtTypes) {
24156
24230
  if (!enabledExtTypes.has(extType)) {
24157
24231
  ideInstance.removeExtension(extType);
24158
- LOG4.info("AgentStream", `Extension removed: ${extType} (disabled for ${ideType})`);
24232
+ LOG5.info("AgentStream", `Extension removed: ${extType} (disabled for ${ideType})`);
24159
24233
  }
24160
24234
  }
24161
24235
  for (const extType of enabledExtTypes) {
@@ -24164,7 +24238,7 @@ ${installInfo}`
24164
24238
  if (extProvider) {
24165
24239
  const extSettings = providerLoader.getSettings(extType);
24166
24240
  ideInstance.addExtension(extProvider, extSettings);
24167
- LOG4.info("AgentStream", `Extension added: ${extType} (enabled for ${ideType})`);
24241
+ LOG5.info("AgentStream", `Extension added: ${extType} (enabled for ${ideType})`);
24168
24242
  }
24169
24243
  }
24170
24244
  }
@@ -24191,7 +24265,7 @@ ${installInfo}`
24191
24265
  if (discovered.length > 0) {
24192
24266
  this._activeIdeType = ideType;
24193
24267
  await agentStreamManager.switchActiveAgent(cdp2, discovered[0].agentType);
24194
- LOG4.info("AgentStream", `Auto-activated: ${discovered[0].agentType} (${ideType})`);
24268
+ LOG5.info("AgentStream", `Auto-activated: ${discovered[0].agentType} (${ideType})`);
24195
24269
  await agentStreamManager.syncAgentSessions(cdp2);
24196
24270
  const streams = await agentStreamManager.collectAgentStreams(cdp2);
24197
24271
  this.deps.onStreamsUpdated?.(ideType, streams);
@@ -24215,7 +24289,7 @@ ${installInfo}`
24215
24289
  */
24216
24290
  async addInstance(id, instance, context) {
24217
24291
  if (this.instances.has(id)) {
24218
- LOG4.warn("InstanceMgr", `[InstanceManager] Instance ${id} already exists, disposing old one`);
24292
+ LOG5.warn("InstanceMgr", `[InstanceManager] Instance ${id} already exists, disposing old one`);
24219
24293
  this.instances.get(id).dispose();
24220
24294
  }
24221
24295
  this.instances.set(id, instance);
@@ -24266,7 +24340,7 @@ ${installInfo}`
24266
24340
  }
24267
24341
  }
24268
24342
  } catch (e) {
24269
- LOG4.warn("InstanceMgr", `[InstanceManager] Failed to collect state from ${id}: ${e.message}`);
24343
+ LOG5.warn("InstanceMgr", `[InstanceManager] Failed to collect state from ${id}: ${e.message}`);
24270
24344
  }
24271
24345
  }
24272
24346
  return states;
@@ -24289,7 +24363,7 @@ ${installInfo}`
24289
24363
  try {
24290
24364
  await instance.onTick();
24291
24365
  } catch (e) {
24292
- LOG4.warn("InstanceMgr", `[InstanceManager] Tick failed for ${id}: ${e.message}`);
24366
+ LOG5.warn("InstanceMgr", `[InstanceManager] Tick failed for ${id}: ${e.message}`);
24293
24367
  }
24294
24368
  }
24295
24369
  }, this.tickInterval);
@@ -24865,11 +24939,67 @@ async (params) => {
24865
24939
  constructor(options) {
24866
24940
  this.providerLoader = options.providerLoader;
24867
24941
  this.cdpManagers = options.cdpManagers;
24868
- this.logFn = options.logFn || LOG4.forComponent("DevServer").asLogFn();
24942
+ this.logFn = options.logFn || LOG5.forComponent("DevServer").asLogFn();
24869
24943
  }
24870
24944
  log(msg) {
24871
24945
  this.logFn(`[DevServer] ${msg}`);
24872
24946
  }
24947
+ // ─── Route Table ─────────────────────────────────────
24948
+ routes = [
24949
+ // Static routes
24950
+ { method: "GET", pattern: "/api/providers", handler: (q, s) => this.handleListProviders(q, s) },
24951
+ { method: "GET", pattern: "/api/providers/versions", handler: (q, s) => this.handleDetectVersions(q, s) },
24952
+ { method: "POST", pattern: "/api/providers/reload", handler: (q, s) => this.handleReload(q, s) },
24953
+ { method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s) => this.handleCdpEvaluate(q, s) },
24954
+ { method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s) => this.handleCdpDomQuery(q, s) },
24955
+ { method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s) => this.handleDomInspect(q, s) },
24956
+ { method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s) => this.handleDomChildren(q, s) },
24957
+ { method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s) => this.handleDomAnalyze(q, s) },
24958
+ { method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s) => this.handleFindByText(q, s) },
24959
+ { method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s) => this.handleFindCommon(q, s) },
24960
+ { method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s) => this.handleScreenshot(q, s) },
24961
+ { method: "GET", pattern: "/api/cdp/targets", handler: (q, s) => this.handleCdpTargets(q, s) },
24962
+ { method: "POST", pattern: "/api/scripts/run", handler: (q, s) => this.handleScriptsRun(q, s) },
24963
+ { method: "GET", pattern: "/api/status", handler: (q, s) => this.handleStatus(q, s) },
24964
+ { method: "POST", pattern: "/api/watch/start", handler: (q, s) => this.handleWatchStart(q, s) },
24965
+ { method: "POST", pattern: "/api/watch/stop", handler: (q, s) => this.handleWatchStop(q, s) },
24966
+ { method: "GET", pattern: "/api/watch/events", handler: (q, s) => this.handleSSE(q, s) },
24967
+ { method: "POST", pattern: "/api/scaffold", handler: (q, s) => this.handleScaffold(q, s) },
24968
+ // Dynamic routes (provider :type param)
24969
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s, p) => this.handleRunScript(p[0], q, s) },
24970
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s, p) => this.handleListFiles(p[0], q, s) },
24971
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleReadFile(p[0], q, s) },
24972
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleWriteFile(p[0], q, s) },
24973
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s, p) => this.handleSource(p[0], q, s) },
24974
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s, p) => this.handleSave(p[0], q, s) },
24975
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s, p) => this.handleProviderConfig(p[0], q, s) },
24976
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s, p) => this.handleDomContext(p[0], q, s) },
24977
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s, p) => this.handleAutoImplement(p[0], q, s) },
24978
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s, p) => this.handleAutoImplCancel(p[0], q, s) },
24979
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s, p) => this.handleAutoImplSSE(p[0], q, s) },
24980
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s, p) => this.handleSpawnTest(p[0], q, s) },
24981
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s, p) => this.handleValidate(p[0], q, s) },
24982
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s, p) => this.handleAcpChat(p[0], q, s) },
24983
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s, p) => this.handleScriptHints(p[0], q, s) }
24984
+ ];
24985
+ matchRoute(method, pathname) {
24986
+ for (const route of this.routes) {
24987
+ if (route.method !== method) continue;
24988
+ if (typeof route.pattern === "string") {
24989
+ if (pathname === route.pattern) return { handler: route.handler };
24990
+ } else {
24991
+ const m = pathname.match(route.pattern);
24992
+ if (m) return { handler: route.handler, params: m.slice(1) };
24993
+ }
24994
+ }
24995
+ return null;
24996
+ }
24997
+ getEndpointList() {
24998
+ return this.routes.map((r) => {
24999
+ const path10 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
25000
+ return `${r.method.padEnd(5)} ${path10}`;
25001
+ });
25002
+ }
24873
25003
  async start(port = DEV_SERVER_PORT) {
24874
25004
  this.server = http2.createServer(async (req, res) => {
24875
25005
  res.setHeader("Access-Control-Allow-Origin", "*");
@@ -24883,112 +25013,15 @@ async (params) => {
24883
25013
  const url2 = new URL(req.url || "/", `http://localhost:${port}`);
24884
25014
  const pathname = url2.pathname;
24885
25015
  try {
24886
- if (pathname === "/api/providers" && req.method === "GET") {
24887
- await this.handleListProviders(req, res);
24888
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/script$/) && req.method === "POST") {
24889
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/script$/)[1];
24890
- await this.handleRunScript(type, req, res);
24891
- } else if (pathname === "/api/cdp/evaluate" && req.method === "POST") {
24892
- await this.handleCdpEvaluate(req, res);
24893
- } else if (pathname === "/api/cdp/dom/query" && req.method === "POST") {
24894
- await this.handleCdpDomQuery(req, res);
24895
- } else if (pathname === "/api/cdp/screenshot" && req.method === "GET") {
24896
- await this.handleScreenshot(req, res);
24897
- } else if (pathname === "/api/scripts/run" && req.method === "POST") {
24898
- await this.handleScriptsRun(req, res);
24899
- } else if (pathname === "/api/status" && req.method === "GET") {
24900
- await this.handleStatus(req, res);
24901
- } else if (pathname === "/api/providers/reload" && req.method === "POST") {
24902
- await this.handleReload(req, res);
24903
- } else if (pathname === "/api/providers/versions" && req.method === "GET") {
24904
- await this.handleDetectVersions(req, res);
24905
- } else if (pathname === "/api/watch/start" && req.method === "POST") {
24906
- await this.handleWatchStart(req, res);
24907
- } else if (pathname === "/api/watch/stop" && req.method === "POST") {
24908
- await this.handleWatchStop(req, res);
24909
- } else if (pathname === "/api/watch/events" && req.method === "GET") {
24910
- this.handleSSE(req, res);
24911
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/files$/) && req.method === "GET") {
24912
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/files$/)[1];
24913
- await this.handleListFiles(type, req, res);
24914
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/file$/) && req.method === "GET") {
24915
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/file$/)[1];
24916
- await this.handleReadFile(type, req, res);
24917
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/file$/) && req.method === "POST") {
24918
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/file$/)[1];
24919
- await this.handleWriteFile(type, req, res);
24920
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/source$/) && req.method === "GET") {
24921
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/source$/)[1];
24922
- await this.handleSource(type, req, res);
24923
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/save$/) && req.method === "POST") {
24924
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/save$/)[1];
24925
- await this.handleSave(type, req, res);
24926
- } else if (pathname === "/api/cdp/dom/inspect" && req.method === "POST") {
24927
- await this.handleDomInspect(req, res);
24928
- } else if (pathname === "/api/cdp/dom/children" && req.method === "POST") {
24929
- await this.handleDomChildren(req, res);
24930
- } else if (pathname === "/api/cdp/dom/analyze" && req.method === "POST") {
24931
- await this.handleDomAnalyze(req, res);
24932
- } else if (pathname === "/api/cdp/dom/find-text" && req.method === "POST") {
24933
- await this.handleFindByText(req, res);
24934
- } else if (pathname === "/api/cdp/dom/find-common" && req.method === "POST") {
24935
- await this.handleFindCommon(req, res);
24936
- } else if (pathname === "/api/cdp/targets" && req.method === "GET") {
24937
- await this.handleCdpTargets(req, res);
24938
- } else if (pathname === "/api/scaffold" && req.method === "POST") {
24939
- await this.handleScaffold(req, res);
24940
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/dom-context$/) && req.method === "POST") {
24941
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/dom-context$/)[1];
24942
- await this.handleDomContext(type, req, res);
24943
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/auto-implement$/) && req.method === "POST") {
24944
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/auto-implement$/)[1];
24945
- await this.handleAutoImplement(type, req, res);
24946
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/) && req.method === "POST") {
24947
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/)[1];
24948
- this.handleAutoImplCancel(type, req, res);
24949
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/auto-implement\/status$/) && req.method === "GET") {
24950
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/auto-implement\/status$/)[1];
24951
- this.handleAutoImplSSE(type, req, res);
24952
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/config$/) && req.method === "GET") {
24953
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/config$/)[1];
24954
- await this.handleProviderConfig(type, req, res);
24955
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/spawn-test$/) && req.method === "POST") {
24956
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/spawn-test$/)[1];
24957
- await this.handleSpawnTest(type, req, res);
24958
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/validate$/) && req.method === "POST") {
24959
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/validate$/)[1];
24960
- await this.handleValidate(type, req, res);
24961
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/acp-chat$/) && req.method === "POST") {
24962
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/acp-chat$/)[1];
24963
- await this.handleAcpChat(type, req, res);
24964
- } else if (pathname.match(/^\/api\/providers\/([^/]+)\/script-hints$/) && req.method === "GET") {
24965
- const type = pathname.match(/^\/api\/providers\/([^/]+)\/script-hints$/)[1];
24966
- await this.handleScriptHints(type, req, res);
25016
+ const route = this.matchRoute(req.method || "GET", pathname);
25017
+ if (route) {
25018
+ await route.handler(req, res, route.params);
24967
25019
  } else if (pathname.startsWith("/assets/") || pathname === "/favicon.ico") {
24968
25020
  await this.serveStaticAsset(pathname, res);
24969
25021
  } else if (pathname === "/" || pathname === "/console" || !pathname.startsWith("/api")) {
24970
25022
  await this.serveConsole(req, res);
24971
25023
  } else {
24972
- this.json(res, 404, {
24973
- error: "Not found",
24974
- endpoints: [
24975
- "GET / \u2014 DevConsole web UI",
24976
- "GET /api/providers",
24977
- "POST /api/providers/:type/script",
24978
- "GET /api/providers/:type/source",
24979
- "POST /api/providers/:type/save",
24980
- "POST /api/cdp/evaluate",
24981
- "POST /api/cdp/dom/query",
24982
- "GET /api/cdp/screenshot",
24983
- "GET /api/cdp/targets",
24984
- "GET /api/status",
24985
- "POST /api/providers/reload",
24986
- "POST /api/watch/start",
24987
- "POST /api/watch/stop",
24988
- "GET /api/watch/events (SSE)",
24989
- "POST /api/scaffold"
24990
- ]
24991
- });
25024
+ this.json(res, 404, { error: "Not found", endpoints: this.getEndpointList() });
24992
25025
  }
24993
25026
  } catch (e) {
24994
25027
  this.log(`Error: ${e.message}`);
@@ -25255,7 +25288,7 @@ async (params) => {
25255
25288
  const buf = await cdp2.captureScreenshot();
25256
25289
  if (buf) {
25257
25290
  res.writeHead(200, {
25258
- "Content-Type": "image/jpeg",
25291
+ "Content-Type": "image/webp",
25259
25292
  "X-Viewport-Width": String(vpW),
25260
25293
  "X-Viewport-Height": String(vpH)
25261
25294
  });
@@ -27392,10 +27425,10 @@ data: ${JSON.stringify(msg.data)}
27392
27425
  ...config2.cliManagerDeps,
27393
27426
  getInstanceManager: () => instanceManager
27394
27427
  }, providerLoader);
27395
- LOG4.info("Init", "Detecting IDEs...");
27428
+ LOG5.info("Init", "Detecting IDEs...");
27396
27429
  detectedIdesRef.value = await detectIDEs3();
27397
27430
  const installed = detectedIdesRef.value.filter((i) => i.installed);
27398
- LOG4.info("Init", `Found ${installed.length} IDE(s): ${installed.map((i) => i.id).join(", ") || "none"}`);
27431
+ LOG5.info("Init", `Found ${installed.length} IDE(s): ${installed.map((i) => i.id).join(", ") || "none"}`);
27399
27432
  const cdpSetupContext = {
27400
27433
  providerLoader,
27401
27434
  instanceManager,
@@ -27423,7 +27456,7 @@ data: ${JSON.stringify(msg.data)}
27423
27456
  instanceIdMap
27424
27457
  });
27425
27458
  const agentStreamManager = new DaemonAgentStreamManager(
27426
- LOG4.forComponent("AgentStream").asLogFn(),
27459
+ LOG5.forComponent("AgentStream").asLogFn(),
27427
27460
  providerLoader
27428
27461
  );
27429
27462
  commandHandler.setAgentStreamManager(agentStreamManager);
@@ -27443,7 +27476,7 @@ data: ${JSON.stringify(msg.data)}
27443
27476
  onIdeConnected: () => poller?.start(),
27444
27477
  onStatusChange: config2.onStatusChange,
27445
27478
  onPostChatCommand: config2.onPostChatCommand,
27446
- getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG4.forComponent(`CDP:${ideType}`).asLogFn())
27479
+ getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG5.forComponent(`CDP:${ideType}`).asLogFn())
27447
27480
  });
27448
27481
  poller = new AgentStreamPoller({
27449
27482
  agentStreamManager,
@@ -27485,7 +27518,7 @@ data: ${JSON.stringify(msg.data)}
27485
27518
  await agentStreamManager.dispose(anyCdp);
27486
27519
  }
27487
27520
  } catch (e) {
27488
- LOG4.warn("Shutdown", `AgentStream dispose: ${e?.message}`);
27521
+ LOG5.warn("Shutdown", `AgentStream dispose: ${e?.message}`);
27489
27522
  }
27490
27523
  try {
27491
27524
  await cliManager.shutdownAll();
@@ -28467,6 +28500,161 @@ var init_daemon_p2p = __esm({
28467
28500
  }
28468
28501
  });
28469
28502
 
28503
+ // src/screenshot-controller.ts
28504
+ var import_daemon_core3, ScreenshotController;
28505
+ var init_screenshot_controller = __esm({
28506
+ "src/screenshot-controller.ts"() {
28507
+ "use strict";
28508
+ import_daemon_core3 = __toESM(require_dist());
28509
+ ScreenshotController = class _ScreenshotController {
28510
+ deps;
28511
+ timer = null;
28512
+ // Delta detection state
28513
+ debugCount = 0;
28514
+ lastSize = 0;
28515
+ lastHash = 0;
28516
+ staticFrameCount = 0;
28517
+ currentInterval;
28518
+ // Quality profiles
28519
+ profileDirect;
28520
+ profileRelay;
28521
+ STATIC_THRESHOLD = 3;
28522
+ // Daily budget state
28523
+ dailyBudgetMinutes;
28524
+ dailyBudgetMs;
28525
+ dailyUsedMs = 0;
28526
+ lastActiveTimestamp = 0;
28527
+ budgetDate;
28528
+ budgetExhausted = false;
28529
+ constructor(deps, planLimits) {
28530
+ this.deps = deps;
28531
+ const planMinIntervalMs = (planLimits?.screenshotIntervalSeconds ?? 0) * 1e3;
28532
+ this.profileDirect = {
28533
+ minInterval: Math.max(300, planMinIntervalMs),
28534
+ maxInterval: Math.max(2e3, planMinIntervalMs),
28535
+ quality: 25
28536
+ };
28537
+ this.profileRelay = {
28538
+ minInterval: Math.max(700, planMinIntervalMs),
28539
+ maxInterval: Math.max(3e3, planMinIntervalMs),
28540
+ quality: 12
28541
+ };
28542
+ this.currentInterval = this.profileDirect.maxInterval;
28543
+ this.dailyBudgetMinutes = planLimits?.dailyScreenshotMinutes ?? -1;
28544
+ this.dailyBudgetMs = this.dailyBudgetMinutes > 0 ? this.dailyBudgetMinutes * 6e4 : -1;
28545
+ this.budgetDate = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
28546
+ if (planMinIntervalMs > 0) {
28547
+ import_daemon_core3.LOG.info("Screenshot", `Plan limit: min interval ${planMinIntervalMs}ms (${planLimits?.screenshotIntervalSeconds}s)`);
28548
+ }
28549
+ if (this.dailyBudgetMs > 0) {
28550
+ import_daemon_core3.LOG.info("Screenshot", `Daily budget: ${this.dailyBudgetMinutes}min/day`);
28551
+ }
28552
+ }
28553
+ // ─── Lifecycle ────────────────────────────────
28554
+ start() {
28555
+ if (this.timer) return;
28556
+ this.timer = setTimeout(() => this.tick(), 1e3);
28557
+ }
28558
+ stop() {
28559
+ if (this.timer) {
28560
+ clearTimeout(this.timer);
28561
+ this.timer = null;
28562
+ }
28563
+ }
28564
+ // ─── Core loop ────────────────────────────────
28565
+ async tick() {
28566
+ if (!this.deps.isRunning()) return;
28567
+ const active = this.deps.isScreenshotActive();
28568
+ const ssIdeType = this.deps.getScreenshotIdeType();
28569
+ const cdp2 = this.deps.getCdp(ssIdeType);
28570
+ const isRelay = this.deps.isUsingRelay();
28571
+ const profile = isRelay ? this.profileRelay : this.profileDirect;
28572
+ this.checkBudgetReset();
28573
+ if (this.dailyBudgetMs > 0) {
28574
+ const now = Date.now();
28575
+ if (active && this.lastActiveTimestamp > 0) {
28576
+ this.dailyUsedMs += now - this.lastActiveTimestamp;
28577
+ }
28578
+ this.lastActiveTimestamp = active ? now : 0;
28579
+ if (this.dailyUsedMs >= this.dailyBudgetMs && !this.budgetExhausted) {
28580
+ this.budgetExhausted = true;
28581
+ const usedMin = Math.round(this.dailyUsedMs / 6e4);
28582
+ import_daemon_core3.LOG.info("Screenshot", `Daily budget exhausted: ${usedMin}/${this.dailyBudgetMinutes}min \u2014 pausing until midnight UTC`);
28583
+ }
28584
+ }
28585
+ if (!active || !cdp2 || this.budgetExhausted) {
28586
+ this.staticFrameCount = 0;
28587
+ this.currentInterval = profile.maxInterval;
28588
+ if (!active) this.lastActiveTimestamp = 0;
28589
+ this.timer = setTimeout(() => this.tick(), this.budgetExhausted ? 3e4 : this.currentInterval);
28590
+ return;
28591
+ }
28592
+ this.debugCount++;
28593
+ try {
28594
+ const buf = await cdp2.captureScreenshot({ quality: profile.quality });
28595
+ if (buf) {
28596
+ const hash2 = _ScreenshotController.fnvHash(buf);
28597
+ const sizeMatch = buf.length === this.lastSize;
28598
+ const hashMatch = hash2 === this.lastHash;
28599
+ const anyNeedsFirstFrame = this.deps.hasAnyNeedingFirstFrame();
28600
+ if (sizeMatch && hashMatch && !anyNeedsFirstFrame) {
28601
+ this.staticFrameCount++;
28602
+ if (this.staticFrameCount >= this.STATIC_THRESHOLD) {
28603
+ this.currentInterval = Math.min(this.currentInterval + 200, profile.maxInterval);
28604
+ }
28605
+ if (this.debugCount <= 5 || this.debugCount % 50 === 0) {
28606
+ import_daemon_core3.LOG.debug("Screenshot", `skip (unchanged, static=${this.staticFrameCount}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"})`);
28607
+ }
28608
+ } else {
28609
+ this.lastSize = buf.length;
28610
+ this.lastHash = hash2;
28611
+ this.staticFrameCount = 0;
28612
+ this.currentInterval = profile.minInterval;
28613
+ const sent = this.deps.sendScreenshotBuffer(buf);
28614
+ if (this.debugCount <= 3 || anyNeedsFirstFrame) {
28615
+ import_daemon_core3.LOG.debug("Screenshot", `sent: ${buf.length} bytes, delivered=${sent}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
28616
+ }
28617
+ }
28618
+ } else {
28619
+ if (this.debugCount <= 5) import_daemon_core3.LOG.debug("Screenshot", "captureScreenshot returned null");
28620
+ }
28621
+ } catch (e) {
28622
+ if (this.debugCount <= 5) import_daemon_core3.LOG.warn("Screenshot", `error: ${e?.message}`);
28623
+ }
28624
+ this.timer = setTimeout(() => this.tick(), this.currentInterval);
28625
+ }
28626
+ // ─── Budget ───────────────────────────────────
28627
+ checkBudgetReset() {
28628
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
28629
+ if (today !== this.budgetDate) {
28630
+ this.dailyUsedMs = 0;
28631
+ this.budgetDate = today;
28632
+ this.budgetExhausted = false;
28633
+ import_daemon_core3.LOG.info("Screenshot", `Daily budget reset (${this.dailyBudgetMinutes}min for today)`);
28634
+ }
28635
+ }
28636
+ // ─── Hash ─────────────────────────────────────
28637
+ /** FNV-1a hash of first 1KB + last 1KB for fast delta detection */
28638
+ static fnvHash(buf) {
28639
+ let h = 2166136261;
28640
+ const sampleEnd = Math.min(1024, buf.length);
28641
+ for (let i = 0; i < sampleEnd; i++) {
28642
+ h ^= buf[i];
28643
+ h = h * 16777619 >>> 0;
28644
+ }
28645
+ if (buf.length > 1024) {
28646
+ const start = Math.max(0, buf.length - 1024);
28647
+ for (let i = start; i < buf.length; i++) {
28648
+ h ^= buf[i];
28649
+ h = h * 16777619 >>> 0;
28650
+ }
28651
+ }
28652
+ return h;
28653
+ }
28654
+ };
28655
+ }
28656
+ });
28657
+
28470
28658
  // src/adhdev-daemon.ts
28471
28659
  var adhdev_daemon_exports = {};
28472
28660
  __export(adhdev_daemon_exports, {
@@ -28513,13 +28701,14 @@ function stopDaemon() {
28513
28701
  return false;
28514
28702
  }
28515
28703
  }
28516
- var import_daemon_core3, os2, fs2, path2, crypto2, import_chalk, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
28704
+ var import_daemon_core4, os2, fs2, path2, crypto2, import_chalk, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
28517
28705
  var init_adhdev_daemon = __esm({
28518
28706
  "src/adhdev-daemon.ts"() {
28519
28707
  "use strict";
28520
28708
  init_server_connection();
28521
- import_daemon_core3 = __toESM(require_dist());
28709
+ import_daemon_core4 = __toESM(require_dist());
28522
28710
  init_daemon_p2p();
28711
+ init_screenshot_controller();
28523
28712
  os2 = __toESM(require("os"));
28524
28713
  fs2 = __toESM(require("fs"));
28525
28714
  path2 = __toESM(require("path"));
@@ -28558,7 +28747,7 @@ var init_adhdev_daemon = __esm({
28558
28747
  AdhdevDaemon = class {
28559
28748
  serverConn = null;
28560
28749
  p2p = null;
28561
- screenshotTimer = null;
28750
+ screenshotController = null;
28562
28751
  statusReporter = null;
28563
28752
  components = null;
28564
28753
  running = false;
@@ -28573,7 +28762,7 @@ var init_adhdev_daemon = __esm({
28573
28762
  installGlobalInterceptor();
28574
28763
  } catch {
28575
28764
  }
28576
- this.localPort = options.localPort || import_daemon_core3.DEFAULT_DAEMON_PORT;
28765
+ this.localPort = options.localPort || import_daemon_core4.DEFAULT_DAEMON_PORT;
28577
28766
  const workingDir = options.workingDir || process.cwd();
28578
28767
  if (isDaemonRunning()) {
28579
28768
  console.log(import_chalk.default.yellow("\n\u26A0 ADHDev Daemon is already running."));
@@ -28582,14 +28771,14 @@ var init_adhdev_daemon = __esm({
28582
28771
  return;
28583
28772
  }
28584
28773
  writeDaemonPid(process.pid);
28585
- const config2 = (0, import_daemon_core3.loadConfig)();
28774
+ const config2 = (0, import_daemon_core4.loadConfig)();
28586
28775
  if (!config2.connectionToken) {
28587
28776
  console.log(import_chalk.default.red("\n\u2717 No connection token found."));
28588
28777
  console.log(import_chalk.default.gray(" Run `adhdev setup` first.\n"));
28589
28778
  process.exit(1);
28590
28779
  }
28591
- this.components = await (0, import_daemon_core3.initDaemonComponents)({
28592
- providerLogFn: import_daemon_core3.LOG.forComponent("Provider").asLogFn(),
28780
+ this.components = await (0, import_daemon_core4.initDaemonComponents)({
28781
+ providerLogFn: import_daemon_core4.LOG.forComponent("Provider").asLogFn(),
28593
28782
  cliManagerDeps: {
28594
28783
  getServerConn: () => this.serverConn,
28595
28784
  getP2p: () => this.p2p,
@@ -28602,7 +28791,7 @@ var init_adhdev_daemon = __esm({
28602
28791
  setTimeout(() => this.statusReporter?.throttledReport(), 1e3);
28603
28792
  setTimeout(() => this.statusReporter?.throttledReport(), 3e3);
28604
28793
  },
28605
- getCdpLogFn: (ideType) => import_daemon_core3.LOG.forComponent(`CDP:${ideType}`).asLogFn(),
28794
+ getCdpLogFn: (ideType) => import_daemon_core4.LOG.forComponent(`CDP:${ideType}`).asLogFn(),
28606
28795
  onCdpManagerSetup: (ideType) => {
28607
28796
  if (this.ideType === "unknown") this.ideType = ideType;
28608
28797
  },
@@ -28610,11 +28799,11 @@ var init_adhdev_daemon = __esm({
28610
28799
  this.statusReporter?.updateAgentStreams(ideType, streams);
28611
28800
  }
28612
28801
  });
28613
- const versionArchive = new import_daemon_core3.VersionArchive();
28614
- (0, import_daemon_core3.detectAllVersions)(this.components.providerLoader, versionArchive).then((results) => {
28802
+ const versionArchive = new import_daemon_core4.VersionArchive();
28803
+ (0, import_daemon_core4.detectAllVersions)(this.components.providerLoader, versionArchive).then((results) => {
28615
28804
  this.components.providerLoader.setVersionArchive(versionArchive);
28616
28805
  for (const info of results) {
28617
- if (info.warning) import_daemon_core3.LOG.warn("Provider", `\u26A0 [${info.name}] ${info.warning}`);
28806
+ if (info.warning) import_daemon_core4.LOG.warn("Provider", `\u26A0 [${info.name}] ${info.warning}`);
28618
28807
  }
28619
28808
  }).catch(() => {
28620
28809
  });
@@ -28622,7 +28811,7 @@ var init_adhdev_daemon = __esm({
28622
28811
  if (updated) {
28623
28812
  this.components.providerLoader.reload();
28624
28813
  this.components.providerLoader.registerToDetector();
28625
- import_daemon_core3.LOG.info("Provider", "Providers auto-updated from upstream");
28814
+ import_daemon_core4.LOG.info("Provider", "Providers auto-updated from upstream");
28626
28815
  }
28627
28816
  }).catch(() => {
28628
28817
  });
@@ -28675,99 +28864,25 @@ var init_adhdev_daemon = __esm({
28675
28864
  });
28676
28865
  this.p2p.onStateChange((state) => {
28677
28866
  if (state === "connected") {
28678
- import_daemon_core3.LOG.info("P2P", "Peer connected \u2192 sending immediate full status report");
28679
- this.statusReporter?.sendUnifiedStatusReport().catch((e) => import_daemon_core3.LOG.warn("P2P", `Immediate status report failed: ${e?.message}`));
28867
+ import_daemon_core4.LOG.info("P2P", "Peer connected \u2192 sending immediate full status report");
28868
+ this.statusReporter?.sendUnifiedStatusReport().catch((e) => import_daemon_core4.LOG.warn("P2P", `Immediate status report failed: ${e?.message}`));
28680
28869
  setTimeout(() => {
28681
28870
  this.statusReporter?.sendUnifiedStatusReport().catch(() => {
28682
28871
  });
28683
28872
  }, 2e3);
28684
28873
  }
28685
28874
  });
28686
- let ssDebugCount = 0;
28687
- let lastScreenshotSize = 0;
28688
- let lastScreenshotHash = 0;
28689
- let staticFrameCount = 0;
28690
28875
  const planLimits = this.serverConn.getPlanLimits();
28691
- const planMinIntervalMs = (planLimits?.screenshotIntervalSeconds ?? 0) * 1e3;
28692
- const PROFILE_DIRECT = {
28693
- minInterval: Math.max(300, planMinIntervalMs),
28694
- maxInterval: Math.max(2e3, planMinIntervalMs),
28695
- quality: 25
28696
- };
28697
- const PROFILE_RELAY = {
28698
- minInterval: Math.max(700, planMinIntervalMs),
28699
- maxInterval: Math.max(3e3, planMinIntervalMs),
28700
- quality: 12
28701
- };
28702
- let currentInterval = PROFILE_DIRECT.maxInterval;
28703
- const STATIC_THRESHOLD = 3;
28704
- if (planMinIntervalMs > 0) {
28705
- import_daemon_core3.LOG.info("Screenshot", `Plan limit: min interval ${planMinIntervalMs}ms (${planLimits?.screenshotIntervalSeconds}s)`);
28706
- }
28707
- const fnvHash = (buf) => {
28708
- let h = 2166136261;
28709
- const sampleEnd = Math.min(1024, buf.length);
28710
- for (let i = 0; i < sampleEnd; i++) {
28711
- h ^= buf[i];
28712
- h = h * 16777619 >>> 0;
28713
- }
28714
- if (buf.length > 1024) {
28715
- const start = Math.max(0, buf.length - 1024);
28716
- for (let i = start; i < buf.length; i++) {
28717
- h ^= buf[i];
28718
- h = h * 16777619 >>> 0;
28719
- }
28720
- }
28721
- return h;
28722
- };
28723
- const screenshotTick = async () => {
28724
- if (!this.running) return;
28725
- const active = this.p2p?.screenshotActive;
28726
- const ssIdeType = this.p2p?.screenshotIdeType;
28727
- const cdp2 = (ssIdeType ? this.getCdpFor(ssIdeType) : null) || this.getAnyCdp();
28728
- const isRelay = this.p2p?.isUsingRelay ?? false;
28729
- const profile = isRelay ? PROFILE_RELAY : PROFILE_DIRECT;
28730
- if (!active || !cdp2) {
28731
- staticFrameCount = 0;
28732
- currentInterval = profile.maxInterval;
28733
- this.screenshotTimer = setTimeout(screenshotTick, currentInterval);
28734
- return;
28735
- }
28736
- ssDebugCount++;
28737
- try {
28738
- const buf = await cdp2.captureScreenshot({ quality: profile.quality });
28739
- if (buf) {
28740
- const hash2 = fnvHash(buf);
28741
- const sizeMatch = buf.length === lastScreenshotSize;
28742
- const hashMatch = hash2 === lastScreenshotHash;
28743
- const anyNeedsFirstFrame = this.p2p.hasAnyNeedingFirstFrame();
28744
- if (sizeMatch && hashMatch && !anyNeedsFirstFrame) {
28745
- staticFrameCount++;
28746
- if (staticFrameCount >= STATIC_THRESHOLD) {
28747
- currentInterval = Math.min(currentInterval + 200, profile.maxInterval);
28748
- }
28749
- if (ssDebugCount <= 5 || ssDebugCount % 50 === 0) {
28750
- import_daemon_core3.LOG.debug("Screenshot", `skip (unchanged, static=${staticFrameCount}, interval=${currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"})`);
28751
- }
28752
- } else {
28753
- lastScreenshotSize = buf.length;
28754
- lastScreenshotHash = hash2;
28755
- staticFrameCount = 0;
28756
- currentInterval = profile.minInterval;
28757
- const sent = this.p2p.sendScreenshotBuffer(buf);
28758
- if (ssDebugCount <= 3 || anyNeedsFirstFrame) {
28759
- import_daemon_core3.LOG.debug("Screenshot", `sent: ${buf.length} bytes, delivered=${sent}, interval=${currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
28760
- }
28761
- }
28762
- } else {
28763
- if (ssDebugCount <= 5) import_daemon_core3.LOG.debug("Screenshot", "captureScreenshot returned null");
28764
- }
28765
- } catch (e) {
28766
- if (ssDebugCount <= 5) import_daemon_core3.LOG.warn("Screenshot", `error: ${e?.message}`);
28767
- }
28768
- this.screenshotTimer = setTimeout(screenshotTick, currentInterval);
28769
- };
28770
- this.screenshotTimer = setTimeout(screenshotTick, 1e3);
28876
+ this.screenshotController = new ScreenshotController({
28877
+ isRunning: () => this.running,
28878
+ isScreenshotActive: () => this.p2p?.screenshotActive ?? false,
28879
+ getScreenshotIdeType: () => this.p2p?.screenshotIdeType,
28880
+ isUsingRelay: () => this.p2p?.isUsingRelay ?? false,
28881
+ hasAnyNeedingFirstFrame: () => this.p2p?.hasAnyNeedingFirstFrame() ?? false,
28882
+ getCdp: (ideType) => (ideType ? this.getCdpFor(ideType) : null) || this.getAnyCdp(),
28883
+ sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf)
28884
+ }, planLimits ?? void 0);
28885
+ this.screenshotController.start();
28771
28886
  } else {
28772
28887
  console.log(import_chalk.default.gray(" \u26A0 P2P unavailable \u2014 using server relay"));
28773
28888
  }
@@ -28781,7 +28896,7 @@ var init_adhdev_daemon = __esm({
28781
28896
  }
28782
28897
  });
28783
28898
  await this.serverConn.connect();
28784
- this.statusReporter = new import_daemon_core3.DaemonStatusReporter({
28899
+ this.statusReporter = new import_daemon_core4.DaemonStatusReporter({
28785
28900
  serverConn: this.serverConn,
28786
28901
  cdpManagers: this.components.cdpManagers,
28787
28902
  p2p: this.p2p,
@@ -28799,7 +28914,7 @@ var init_adhdev_daemon = __esm({
28799
28914
  process.on("SIGINT", () => this.stop());
28800
28915
  process.on("SIGTERM", () => this.stop());
28801
28916
  if (options.dev) {
28802
- const devServer = new import_daemon_core3.DevServer({ providerLoader: this.components.providerLoader, cdpManagers: this.components.cdpManagers });
28917
+ const devServer = new import_daemon_core4.DevServer({ providerLoader: this.components.providerLoader, cdpManagers: this.components.cdpManagers });
28803
28918
  await devServer.start();
28804
28919
  }
28805
28920
  this.printBanner(options, config2.serverUrl);
@@ -28912,7 +29027,7 @@ var init_adhdev_daemon = __esm({
28912
29027
  }
28913
29028
  }
28914
29029
  async handleCommand(msg, cmd, args) {
28915
- import_daemon_core3.LOG.info("Command", `${cmd}${args?._targetInstance ? ` \u2192 ${args._targetType}:${args._targetInstance.split("_")[0]}` : ""}`);
29030
+ import_daemon_core4.LOG.info("Command", `${cmd}${args?._targetInstance ? ` \u2192 ${args._targetType}:${args._targetInstance.split("_")[0]}` : ""}`);
28916
29031
  const cmdStart = Date.now();
28917
29032
  const source = msg.ipcWs ? "ext" : "ws";
28918
29033
  try {
@@ -28920,7 +29035,7 @@ var init_adhdev_daemon = __esm({
28920
29035
  const cmdStr = args?.command;
28921
29036
  if (!cmdStr) throw new Error("Command string required");
28922
29037
  if (DANGEROUS_PATTERNS.some((p) => p.test(cmdStr))) {
28923
- (0, import_daemon_core3.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: "Blocked", durationMs: Date.now() - cmdStart });
29038
+ (0, import_daemon_core4.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: false, error: "Blocked", durationMs: Date.now() - cmdStart });
28924
29039
  this.sendResult(msg, false, { error: `Blocked: "${cmdStr}"` });
28925
29040
  return;
28926
29041
  }
@@ -28934,7 +29049,7 @@ var init_adhdev_daemon = __esm({
28934
29049
  if (stderr) this.serverConn.sendMessage("log", { message: stderr.slice(0, 5e3), level: "warn" });
28935
29050
  }
28936
29051
  });
28937
- (0, import_daemon_core3.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: true, durationMs: Date.now() - cmdStart });
29052
+ (0, import_daemon_core4.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd, source, args, success: true, durationMs: Date.now() - cmdStart });
28938
29053
  this.sendResult(msg, true, { started: true });
28939
29054
  return;
28940
29055
  }
@@ -28951,16 +29066,16 @@ var init_adhdev_daemon = __esm({
28951
29066
  try {
28952
29067
  switch (cmdType) {
28953
29068
  case "get_cli_history": {
28954
- const config2 = (0, import_daemon_core3.loadConfig)();
28955
- (0, import_daemon_core3.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", success: true, durationMs: Date.now() - cmdStart });
29069
+ const config2 = (0, import_daemon_core4.loadConfig)();
29070
+ (0, import_daemon_core4.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", success: true, durationMs: Date.now() - cmdStart });
28956
29071
  return { success: true, history: config2.cliHistory || [] };
28957
29072
  }
28958
29073
  case "set_machine_nickname": {
28959
29074
  const nickname = data.nickname?.trim() || null;
28960
- const config2 = (0, import_daemon_core3.loadConfig)();
29075
+ const config2 = (0, import_daemon_core4.loadConfig)();
28961
29076
  config2.machineNickname = nickname;
28962
- (0, import_daemon_core3.saveConfig)(config2);
28963
- (0, import_daemon_core3.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", args: { nickname }, success: true, durationMs: Date.now() - cmdStart });
29077
+ (0, import_daemon_core4.saveConfig)(config2);
29078
+ (0, import_daemon_core4.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", args: { nickname }, success: true, durationMs: Date.now() - cmdStart });
28964
29079
  return { success: true, nickname };
28965
29080
  }
28966
29081
  case "get_command_history": {
@@ -28972,7 +29087,7 @@ var init_adhdev_daemon = __esm({
28972
29087
  }
28973
29088
  return await this.components.router.execute(cmdType, data, "p2p");
28974
29089
  } catch (e) {
28975
- (0, import_daemon_core3.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", success: false, error: e.message, durationMs: Date.now() - cmdStart });
29090
+ (0, import_daemon_core4.logCommand)({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", success: false, error: e.message, durationMs: Date.now() - cmdStart });
28976
29091
  return { success: false, error: e.message };
28977
29092
  }
28978
29093
  }
@@ -28997,16 +29112,16 @@ var init_adhdev_daemon = __esm({
28997
29112
  if (!this.running) return;
28998
29113
  this.running = false;
28999
29114
  console.log(import_chalk.default.yellow("\n Shutting down ADHDev Daemon..."));
29000
- if (this.screenshotTimer) {
29001
- clearTimeout(this.screenshotTimer);
29002
- this.screenshotTimer = null;
29115
+ if (this.screenshotController) {
29116
+ this.screenshotController.stop();
29117
+ this.screenshotController = null;
29003
29118
  }
29004
29119
  if (this.statusReporter) {
29005
29120
  this.statusReporter.stopReporting();
29006
29121
  this.statusReporter = null;
29007
29122
  }
29008
29123
  if (this.components) {
29009
- await (0, import_daemon_core3.shutdownDaemonComponents)(this.components);
29124
+ await (0, import_daemon_core4.shutdownDaemonComponents)(this.components);
29010
29125
  }
29011
29126
  try {
29012
29127
  this.p2p?.disconnect();
@@ -29048,7 +29163,7 @@ var import_chalk2 = __toESM(require("chalk"));
29048
29163
  var import_inquirer = __toESM(require("inquirer"));
29049
29164
  var import_ora = __toESM(require("ora"));
29050
29165
  var import_open = __toESM(require("open"));
29051
- var import_daemon_core4 = __toESM(require_dist());
29166
+ var import_daemon_core5 = __toESM(require_dist());
29052
29167
  var SERVER_URL = process.env.ADHDEV_SERVER_URL || "https://api.adhf.dev";
29053
29168
  var LOGO = `
29054
29169
  ${import_chalk2.default.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}
@@ -29058,13 +29173,13 @@ ${import_chalk2.default.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u
29058
29173
  `;
29059
29174
  var DIVIDER = import_chalk2.default.gray("\u2500".repeat(44));
29060
29175
  async function runWizard(options = {}) {
29061
- const loader = new import_daemon_core4.ProviderLoader({ logFn: () => {
29176
+ const loader = new import_daemon_core5.ProviderLoader({ logFn: () => {
29062
29177
  } });
29063
29178
  loader.loadAll();
29064
29179
  loader.registerToDetector();
29065
29180
  console.log(LOGO);
29066
- if ((0, import_daemon_core4.isSetupComplete)() && !options.force) {
29067
- const config2 = (0, import_daemon_core4.loadConfig)();
29181
+ if ((0, import_daemon_core5.isSetupComplete)() && !options.force) {
29182
+ const config2 = (0, import_daemon_core5.loadConfig)();
29068
29183
  console.log(import_chalk2.default.green("\u2713") + " ADHDev is already set up!");
29069
29184
  const ides = config2.configuredIdes?.length ? config2.configuredIdes.join(", ") : config2.selectedIde || "none";
29070
29185
  console.log(import_chalk2.default.gray(` IDEs: ${ides}`));
@@ -29093,7 +29208,7 @@ async function runWizard(options = {}) {
29093
29208
  if (action === "relogin") {
29094
29209
  const loginResult = await loginFlow();
29095
29210
  if (loginResult) {
29096
- (0, import_daemon_core4.updateConfig)({
29211
+ (0, import_daemon_core5.updateConfig)({
29097
29212
  connectionToken: loginResult.connectionToken,
29098
29213
  userEmail: loginResult.email,
29099
29214
  userName: loginResult.name
@@ -29130,7 +29245,7 @@ async function runWizard(options = {}) {
29130
29245
  async function quickSetup() {
29131
29246
  console.log(import_chalk2.default.bold("\n\u{1F680} Quick Setup\n"));
29132
29247
  const spinner = (0, import_ora.default)("Detecting installed IDEs...").start();
29133
- const ides = await (0, import_daemon_core4.detectIDEs)();
29248
+ const ides = await (0, import_daemon_core5.detectIDEs)();
29134
29249
  const installedIDEs = ides.filter((i) => i.installed && i.cliCommand);
29135
29250
  spinner.stop();
29136
29251
  if (installedIDEs.length === 0) {
@@ -29178,9 +29293,9 @@ async function quickSetup() {
29178
29293
  }
29179
29294
  }
29180
29295
  const ideIds = selectedIDEs.map((i) => i.id);
29181
- (0, import_daemon_core4.markSetupComplete)(ideIds, ["adhdev"]);
29296
+ (0, import_daemon_core5.markSetupComplete)(ideIds, ["adhdev"]);
29182
29297
  if (loginResult) {
29183
- (0, import_daemon_core4.updateConfig)({
29298
+ (0, import_daemon_core5.updateConfig)({
29184
29299
  connectionToken: loginResult.connectionToken,
29185
29300
  userEmail: loginResult.email,
29186
29301
  userName: loginResult.name
@@ -29210,7 +29325,7 @@ async function quickSetup() {
29210
29325
  async function customSetup() {
29211
29326
  console.log(import_chalk2.default.bold("\n\u{1F4CD} Step 1/4 \u2014 Detecting installed IDEs...\n"));
29212
29327
  const spinner = (0, import_ora.default)("Scanning your system...").start();
29213
- const ides = await (0, import_daemon_core4.detectIDEs)();
29328
+ const ides = await (0, import_daemon_core5.detectIDEs)();
29214
29329
  const installedIDEs = ides.filter((i) => i.installed);
29215
29330
  spinner.stop();
29216
29331
  if (installedIDEs.length === 0) {
@@ -29241,7 +29356,7 @@ async function customSetup() {
29241
29356
  const selectedIDE = installedIDEs.find((i) => i.id === selectedIdeId);
29242
29357
  console.log(DIVIDER);
29243
29358
  console.log(import_chalk2.default.bold("\n\u{1F4CD} Step 3/4 \u2014 Choose AI extensions\n"));
29244
- const aiExtensions = (0, import_daemon_core4.getAIExtensions)();
29359
+ const aiExtensions = (0, import_daemon_core5.getAIExtensions)();
29245
29360
  const { selectedExtIds } = await import_inquirer.default.prompt([
29246
29361
  {
29247
29362
  type: "checkbox",
@@ -29258,7 +29373,7 @@ async function customSetup() {
29258
29373
  const allExtensions = selectedAIExts;
29259
29374
  console.log(import_chalk2.default.bold("\n\u{1F4CD} Step 4/4 \u2014 Installing extensions\n"));
29260
29375
  if (selectedIDE.cliCommand) {
29261
- await (0, import_daemon_core4.installExtensions)(
29376
+ await (0, import_daemon_core5.installExtensions)(
29262
29377
  selectedIDE,
29263
29378
  allExtensions,
29264
29379
  (current, total, ext, result) => {
@@ -29277,9 +29392,9 @@ async function customSetup() {
29277
29392
  if (loginResult?.connectionToken) {
29278
29393
  await injectTokenToIDE(selectedIDE, loginResult.connectionToken);
29279
29394
  }
29280
- (0, import_daemon_core4.markSetupComplete)(selectedIdeId, allExtensions.map((e) => e.id));
29395
+ (0, import_daemon_core5.markSetupComplete)(selectedIdeId, allExtensions.map((e) => e.id));
29281
29396
  if (loginResult) {
29282
- (0, import_daemon_core4.updateConfig)({
29397
+ (0, import_daemon_core5.updateConfig)({
29283
29398
  connectionToken: loginResult.connectionToken,
29284
29399
  userEmail: loginResult.email,
29285
29400
  userName: loginResult.name
@@ -29385,7 +29500,7 @@ async function injectTokenToIDE(ide, connectionToken) {
29385
29500
  return path3.join(home, ".config", appName2, "User", "settings.json");
29386
29501
  }
29387
29502
  };
29388
- const loader = new import_daemon_core4.ProviderLoader({ logFn: () => {
29503
+ const loader = new import_daemon_core5.ProviderLoader({ logFn: () => {
29389
29504
  } });
29390
29505
  loader.loadAll();
29391
29506
  const appNameMap = loader.getMacAppIdentifiers();
@@ -29548,7 +29663,7 @@ async function installCliOnly() {
29548
29663
  }
29549
29664
 
29550
29665
  // src/cli-entrypoint.ts
29551
- var import_daemon_core5 = __toESM(require_dist());
29666
+ var import_daemon_core6 = __toESM(require_dist());
29552
29667
  var import_fs = require("fs");
29553
29668
  var import_path = require("path");
29554
29669
  var pkgVersion2 = "unknown";
@@ -29569,7 +29684,7 @@ try {
29569
29684
  }
29570
29685
  } catch {
29571
29686
  }
29572
- var _cliProviderLoader = new import_daemon_core5.ProviderLoader({ logFn: () => {
29687
+ var _cliProviderLoader = new import_daemon_core6.ProviderLoader({ logFn: () => {
29573
29688
  } });
29574
29689
  _cliProviderLoader.loadAll();
29575
29690
  _cliProviderLoader.registerToDetector();
@@ -29645,7 +29760,7 @@ program.command("launch [target]").description("Launch IDE with CDP or start CLI
29645
29760
  }
29646
29761
  let targetIdeId = targetArg;
29647
29762
  if (!targetIdeId) {
29648
- const ides = await (0, import_daemon_core5.detectIDEs)();
29763
+ const ides = await (0, import_daemon_core6.detectIDEs)();
29649
29764
  const installed = ides.filter((i) => i.installed && i.cliCommand);
29650
29765
  if (installed.length === 0) {
29651
29766
  console.log(import_chalk3.default.red("\n\u2717 No supported IDE found.\n"));
@@ -29672,7 +29787,7 @@ program.command("launch [target]").description("Launch IDE with CDP or start CLI
29672
29787
  const ora2 = await import("ora");
29673
29788
  const spinner = ora2.default("Detecting IDE...").start();
29674
29789
  try {
29675
- const result = await (0, import_daemon_core5.launchWithCdp)({
29790
+ const result = await (0, import_daemon_core6.launchWithCdp)({
29676
29791
  ideId: targetIdeId,
29677
29792
  workspace: options.workspace,
29678
29793
  newWindow: options.newWindow
@@ -29683,14 +29798,14 @@ program.command("launch [target]").description("Launch IDE with CDP or start CLI
29683
29798
  \u2717 ${result.error}
29684
29799
  `));
29685
29800
  console.log(import_chalk3.default.gray(" Available IDEs:"));
29686
- const ides = await (0, import_daemon_core5.detectIDEs)();
29801
+ const ides = await (0, import_daemon_core6.detectIDEs)();
29687
29802
  ides.forEach((ide) => {
29688
29803
  if (ide.installed) {
29689
29804
  console.log(` ${import_chalk3.default.green("\u2713")} ${ide.icon} ${import_chalk3.default.bold(ide.id)} \u2014 ${ide.displayName}`);
29690
29805
  }
29691
29806
  });
29692
29807
  console.log(import_chalk3.default.gray("\n Available CLI Agents:"));
29693
- const clis = await (0, import_daemon_core5.detectCLIs)(_cliProviderLoader);
29808
+ const clis = await (0, import_daemon_core6.detectCLIs)(_cliProviderLoader);
29694
29809
  clis.forEach((cli) => {
29695
29810
  if (cli.installed) {
29696
29811
  console.log(` ${import_chalk3.default.green("\u2713")} ${cli.icon} ${import_chalk3.default.bold(cli.id)} \u2014 ${cli.displayName}`);
@@ -29729,7 +29844,7 @@ program.command("launch [target]").description("Launch IDE with CDP or start CLI
29729
29844
  }
29730
29845
  });
29731
29846
  program.command("status").description("Show current ADHDev setup status").action(async () => {
29732
- const config2 = (0, import_daemon_core5.loadConfig)();
29847
+ const config2 = (0, import_daemon_core6.loadConfig)();
29733
29848
  console.log(import_chalk3.default.bold("\n\u{1F9A6} ADHDev Status\n"));
29734
29849
  if (!config2.setupCompleted) {
29735
29850
  console.log(import_chalk3.default.yellow(" Status: Not configured"));
@@ -29739,7 +29854,7 @@ program.command("status").description("Show current ADHDev setup status").action
29739
29854
  const ideList = config2.configuredIdes?.length ? config2.configuredIdes : config2.selectedIde ? [config2.selectedIde] : [];
29740
29855
  console.log(` ${import_chalk3.default.bold("Status:")} ${import_chalk3.default.green("\u2713 Configured")}`);
29741
29856
  if (ideList.length > 0) {
29742
- const ides = await (0, import_daemon_core5.detectIDEs)();
29857
+ const ides = await (0, import_daemon_core6.detectIDEs)();
29743
29858
  console.log(` ${import_chalk3.default.bold("IDEs:")}`);
29744
29859
  for (const ideId of ideList) {
29745
29860
  const ide = ides.find((i) => i.id === ideId);
@@ -29751,7 +29866,7 @@ program.command("status").description("Show current ADHDev setup status").action
29751
29866
  }
29752
29867
  }
29753
29868
  }
29754
- const clis = await (0, import_daemon_core5.detectCLIs)(_cliProviderLoader);
29869
+ const clis = await (0, import_daemon_core6.detectCLIs)(_cliProviderLoader);
29755
29870
  const installedClis = clis.filter((c) => c.installed);
29756
29871
  if (installedClis.length > 0) {
29757
29872
  console.log(` ${import_chalk3.default.bold("CLI Agents:")}`);
@@ -29772,7 +29887,7 @@ program.command("status").description("Show current ADHDev setup status").action
29772
29887
  });
29773
29888
  program.command("detect").description("Detect installed IDEs, CLI agents, and ACP agents").action(async () => {
29774
29889
  console.log(import_chalk3.default.bold("\n\u{1F50D} Detecting installed IDEs...\n"));
29775
- const ides = await (0, import_daemon_core5.detectIDEs)();
29890
+ const ides = await (0, import_daemon_core6.detectIDEs)();
29776
29891
  ides.forEach((ide) => {
29777
29892
  if (ide.installed) {
29778
29893
  const version2 = ide.version ? import_chalk3.default.gray(` v${ide.version}`) : "";
@@ -29788,7 +29903,7 @@ program.command("detect").description("Detect installed IDEs, CLI agents, and AC
29788
29903
  }
29789
29904
  });
29790
29905
  console.log(import_chalk3.default.bold("\n\u{1F50D} Detecting CLI & ACP Agents...\n"));
29791
- const clis = await (0, import_daemon_core5.detectCLIs)(_cliProviderLoader);
29906
+ const clis = await (0, import_daemon_core6.detectCLIs)(_cliProviderLoader);
29792
29907
  const cliAgents = clis.filter((c) => c.category === "cli");
29793
29908
  const acpAgents = clis.filter((c) => c.category === "acp");
29794
29909
  const installedCli = cliAgents.filter((c) => c.installed);
@@ -29831,7 +29946,7 @@ program.command("reset").description("Reset ADHDev configuration").action(async
29831
29946
  }
29832
29947
  ]);
29833
29948
  if (confirm) {
29834
- (0, import_daemon_core5.resetConfig)();
29949
+ (0, import_daemon_core6.resetConfig)();
29835
29950
  console.log(import_chalk3.default.green("\n\u2713 Configuration reset successfully."));
29836
29951
  console.log(import_chalk3.default.gray(" Run `adhdev setup` to reconfigure.\n"));
29837
29952
  }