adhdev 0.7.41 → 0.7.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -34,7 +34,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
34
34
  // ../../oss/packages/daemon-core/src/config/config.ts
35
35
  var config_exports = {};
36
36
  __export(config_exports, {
37
- generateConnectionToken: () => generateConnectionToken,
38
37
  generateMachineId: () => generateMachineId,
39
38
  getConfigDir: () => getConfigDir,
40
39
  isSetupComplete: () => isSetupComplete,
@@ -45,6 +44,57 @@ __export(config_exports, {
45
44
  saveConfig: () => saveConfig,
46
45
  updateConfig: () => updateConfig
47
46
  });
47
+ function isPlainObject(value) {
48
+ return !!value && typeof value === "object" && !Array.isArray(value);
49
+ }
50
+ function asStringArray(value) {
51
+ if (!Array.isArray(value)) return [];
52
+ return value.filter((item) => typeof item === "string");
53
+ }
54
+ function asNullableString(value) {
55
+ return typeof value === "string" ? value : null;
56
+ }
57
+ function asOptionalString(value) {
58
+ return typeof value === "string" && value.trim() ? value : void 0;
59
+ }
60
+ function asBoolean(value, fallback) {
61
+ return typeof value === "boolean" ? value : fallback;
62
+ }
63
+ function normalizeConfig(raw) {
64
+ const parsed = isPlainObject(raw) ? raw : {};
65
+ const legacySessionReads = isPlainObject(parsed.recentSessionReads) ? parsed.recentSessionReads : {};
66
+ const sessionReads = isPlainObject(parsed.sessionReads) ? parsed.sessionReads : {};
67
+ const mergedSessionReads = Object.fromEntries(
68
+ Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
69
+ );
70
+ const sessionReadMarkers = Object.fromEntries(
71
+ Object.entries(isPlainObject(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
72
+ );
73
+ return {
74
+ serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
75
+ selectedIde: asNullableString(parsed.selectedIde),
76
+ configuredIdes: asStringArray(parsed.configuredIdes),
77
+ installedExtensions: asStringArray(parsed.installedExtensions),
78
+ userEmail: asNullableString(parsed.userEmail),
79
+ userName: asNullableString(parsed.userName),
80
+ setupCompleted: asBoolean(parsed.setupCompleted, DEFAULT_CONFIG.setupCompleted),
81
+ setupDate: asNullableString(parsed.setupDate),
82
+ enabledIdes: asStringArray(parsed.enabledIdes),
83
+ workspaces: Array.isArray(parsed.workspaces) ? parsed.workspaces : [],
84
+ defaultWorkspaceId: asNullableString(parsed.defaultWorkspaceId) ?? asNullableString(parsed.activeWorkspaceId),
85
+ recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
86
+ sessionReads: mergedSessionReads,
87
+ sessionReadMarkers,
88
+ machineNickname: asNullableString(parsed.machineNickname),
89
+ machineId: asOptionalString(parsed.machineId),
90
+ machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
91
+ registeredMachineId: asOptionalString(parsed.registeredMachineId),
92
+ providerSettings: isPlainObject(parsed.providerSettings) ? parsed.providerSettings : {},
93
+ ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
94
+ disableUpstream: asBoolean(parsed.disableUpstream, DEFAULT_CONFIG.disableUpstream ?? false),
95
+ providerDir: asOptionalString(parsed.providerDir)
96
+ };
97
+ }
48
98
  function generateMachineId() {
49
99
  return `${MACHINE_ID_PREFIX}${(0, import_crypto.randomUUID)().replace(/-/g, "")}`;
50
100
  }
@@ -88,14 +138,10 @@ function loadConfig() {
88
138
  try {
89
139
  const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
90
140
  const parsed = JSON.parse(raw);
91
- const merged = { ...DEFAULT_CONFIG, ...parsed };
92
- if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
93
- merged.defaultWorkspaceId = merged.activeWorkspaceId;
94
- }
95
- delete merged.activeWorkspaceId;
96
- const ensured = ensureMachineId(merged);
141
+ const normalizedInput = normalizeConfig(parsed);
142
+ const ensured = ensureMachineId(normalizedInput);
97
143
  const normalized = ensured.config;
98
- if (ensured.changed) {
144
+ if (ensured.changed || JSON.stringify(parsed) !== JSON.stringify(normalized)) {
99
145
  try {
100
146
  saveConfig(normalized);
101
147
  } catch {
@@ -110,10 +156,11 @@ function loadConfig() {
110
156
  function saveConfig(config2) {
111
157
  const configPath = getConfigPath();
112
158
  const dir = getConfigDir();
159
+ const normalized = normalizeConfig(config2);
113
160
  if (!(0, import_fs.existsSync)(dir)) {
114
161
  (0, import_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
115
162
  }
116
- (0, import_fs.writeFileSync)(configPath, JSON.stringify(config2, null, 2), { encoding: "utf-8", mode: 384 });
163
+ (0, import_fs.writeFileSync)(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
117
164
  try {
118
165
  (0, import_fs.chmodSync)(configPath, 384);
119
166
  } catch {
@@ -142,14 +189,6 @@ function isSetupComplete() {
142
189
  function resetConfig() {
143
190
  saveConfig({ ...DEFAULT_CONFIG });
144
191
  }
145
- function generateConnectionToken() {
146
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
147
- let token = "db_";
148
- for (let i = 0; i < 32; i++) {
149
- token += chars.charAt(Math.floor(Math.random() * chars.length));
150
- }
151
- return token;
152
- }
153
192
  var import_os, import_path, import_fs, import_crypto, DEFAULT_CONFIG, MACHINE_ID_PREFIX;
154
193
  var init_config = __esm({
155
194
  "../../oss/packages/daemon-core/src/config/config.ts"() {
@@ -160,18 +199,13 @@ var init_config = __esm({
160
199
  import_crypto = require("crypto");
161
200
  DEFAULT_CONFIG = {
162
201
  serverUrl: "https://api.adhf.dev",
163
- apiToken: null,
164
- connectionToken: null,
165
202
  selectedIde: null,
166
203
  configuredIdes: [],
167
204
  installedExtensions: [],
168
- autoConnect: true,
169
- notifications: true,
170
205
  userEmail: null,
171
206
  userName: null,
172
207
  setupCompleted: false,
173
208
  setupDate: null,
174
- configuredCLIs: [],
175
209
  enabledIdes: [],
176
210
  workspaces: [],
177
211
  defaultWorkspaceId: null,
@@ -2338,6 +2372,8 @@ var init_extension_provider_instance = __esm({
2338
2372
  this.detectTransition(newStatus, data);
2339
2373
  this.currentStatus = newStatus;
2340
2374
  }
2375
+ } else if (event === "stream_reset") {
2376
+ this.resetStreamState();
2341
2377
  } else if (event === "extension_connected") {
2342
2378
  this.ideType = data?.ideType || "";
2343
2379
  }
@@ -2417,6 +2453,30 @@ var init_extension_provider_instance = __esm({
2417
2453
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
2418
2454
  return title || this.agentName || this.provider.name;
2419
2455
  }
2456
+ resetStreamState() {
2457
+ if (this.currentStatus !== "idle") {
2458
+ this.detectTransition("idle", {
2459
+ title: this.chatTitle,
2460
+ agentName: this.agentName,
2461
+ extensionId: this.extensionId,
2462
+ messages: this.messages
2463
+ });
2464
+ }
2465
+ this.agentStreams = [];
2466
+ this.messages = [];
2467
+ this.activeModal = null;
2468
+ this.currentModel = "";
2469
+ this.currentMode = "";
2470
+ this.controlValues = {};
2471
+ this.currentStatus = "idle";
2472
+ this.chatId = null;
2473
+ this.chatTitle = null;
2474
+ this.agentName = "";
2475
+ this.extensionId = "";
2476
+ this.lastAgentStatus = "idle";
2477
+ this.generatingStartedAt = 0;
2478
+ this.monitor.reset();
2479
+ }
2420
2480
  };
2421
2481
  }
2422
2482
  });
@@ -2472,8 +2532,6 @@ var init_chat_history = __esm({
2472
2532
  lastSeenCounts = /* @__PURE__ */ new Map();
2473
2533
  /** Last seen message hash per agent (deduplication) */
2474
2534
  lastSeenHashes = /* @__PURE__ */ new Map();
2475
- /** Last seen append-only terminal transcript per agent */
2476
- lastSeenTerminal = /* @__PURE__ */ new Map();
2477
2535
  rotated = false;
2478
2536
  /**
2479
2537
  * Append new messages to history
@@ -2531,51 +2589,10 @@ var init_chat_history = __esm({
2531
2589
  } catch {
2532
2590
  }
2533
2591
  }
2534
- appendTerminalHistory(agentType, terminalHistory, sessionTitle, instanceId) {
2535
- const next = String(terminalHistory || "");
2536
- if (!next.trim()) return;
2537
- try {
2538
- const dedupKey = instanceId ? `${agentType}:${instanceId}:terminal` : `${agentType}:terminal`;
2539
- const prev = this.lastSeenTerminal.get(dedupKey) || "";
2540
- if (prev === next) return;
2541
- let delta = "";
2542
- if (!prev) {
2543
- delta = next;
2544
- } else if (next.startsWith(prev)) {
2545
- delta = next.slice(prev.length);
2546
- } else if (prev.includes(next)) {
2547
- this.lastSeenTerminal.set(dedupKey, next);
2548
- return;
2549
- } else {
2550
- delta = `
2551
-
2552
- [terminal snapshot reset ${(/* @__PURE__ */ new Date()).toISOString()} | ${sessionTitle || agentType}]
2553
- ${next}`;
2554
- }
2555
- if (!delta) {
2556
- this.lastSeenTerminal.set(dedupKey, next);
2557
- return;
2558
- }
2559
- const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
2560
- fs3.mkdirSync(dir, { recursive: true });
2561
- const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2562
- const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
2563
- const filePath = path4.join(dir, `${filePrefix}${date5}.terminal.log`);
2564
- fs3.appendFileSync(filePath, delta, "utf-8");
2565
- this.lastSeenTerminal.set(dedupKey, next);
2566
- if (!this.rotated) {
2567
- this.rotated = true;
2568
- this.rotateOldFiles().catch(() => {
2569
- });
2570
- }
2571
- } catch {
2572
- }
2573
- }
2574
2592
  /** Called when agent session is explicitly changed */
2575
2593
  onSessionChange(agentType) {
2576
2594
  this.lastSeenHashes.delete(agentType);
2577
2595
  this.lastSeenCounts.delete(agentType);
2578
- this.lastSeenTerminal.delete(`${agentType}:terminal`);
2579
2596
  }
2580
2597
  /** Delete history files older than 30 days */
2581
2598
  async rotateOldFiles() {
@@ -2715,11 +2732,23 @@ var init_ide_provider_instance = __esm({
2715
2732
  } else if (event === "cdp_disconnected") {
2716
2733
  this.cachedChat = null;
2717
2734
  this.currentStatus = "idle";
2735
+ for (const ext of this.extensions.values()) {
2736
+ ext.onEvent("stream_reset");
2737
+ }
2718
2738
  } else if (event === "stream_update") {
2719
2739
  const extType = data?.extensionType;
2720
2740
  if (extType && this.extensions.has(extType)) {
2721
2741
  this.extensions.get(extType).onEvent("stream_update", data);
2722
2742
  }
2743
+ } else if (event === "stream_reset") {
2744
+ const extType = data?.extensionType;
2745
+ if (extType && this.extensions.has(extType)) {
2746
+ this.extensions.get(extType).onEvent("stream_reset");
2747
+ }
2748
+ } else if (event === "stream_reset_all") {
2749
+ for (const ext of this.extensions.values()) {
2750
+ ext.onEvent("stream_reset");
2751
+ }
2723
2752
  }
2724
2753
  }
2725
2754
  dispose() {
@@ -3251,6 +3280,50 @@ var init_initializer = __esm({
3251
3280
  });
3252
3281
 
3253
3282
  // ../../oss/packages/daemon-core/src/status/normalize.ts
3283
+ function truncateString(value, maxChars) {
3284
+ if (value.length <= maxChars) return value;
3285
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
3286
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
3287
+ }
3288
+ function trimStructuredStrings(value, maxChars) {
3289
+ if (typeof value === "string") return truncateString(value, maxChars);
3290
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
3291
+ if (!value || typeof value !== "object") return value;
3292
+ return Object.fromEntries(
3293
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
3294
+ );
3295
+ }
3296
+ function estimateBytes(value) {
3297
+ try {
3298
+ return JSON.stringify(value).length;
3299
+ } catch {
3300
+ return String(value ?? "").length;
3301
+ }
3302
+ }
3303
+ function trimMessageForStatus(message, stringLimit) {
3304
+ if (!message || typeof message !== "object") return message;
3305
+ return trimStructuredStrings(message, stringLimit);
3306
+ }
3307
+ function trimMessagesForStatus(messages) {
3308
+ if (!Array.isArray(messages) || messages.length === 0) return [];
3309
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
3310
+ const kept = [];
3311
+ let totalBytes = 0;
3312
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
3313
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
3314
+ let size = estimateBytes(normalized);
3315
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
3316
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
3317
+ size = estimateBytes(normalized);
3318
+ }
3319
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
3320
+ continue;
3321
+ }
3322
+ kept.push(normalized);
3323
+ totalBytes += size;
3324
+ }
3325
+ return kept.reverse();
3326
+ }
3254
3327
  function hasApprovalButtons(activeModal) {
3255
3328
  return (activeModal?.buttons?.length ?? 0) > 0;
3256
3329
  }
@@ -3271,10 +3344,18 @@ function normalizeActiveChatData(activeChat) {
3271
3344
  if (!activeChat) return activeChat;
3272
3345
  return {
3273
3346
  ...activeChat,
3274
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
3347
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
3348
+ messages: trimMessagesForStatus(activeChat.messages),
3349
+ activeModal: activeChat.activeModal ? {
3350
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
3351
+ buttons: (activeChat.activeModal.buttons || []).map(
3352
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
3353
+ )
3354
+ } : activeChat.activeModal,
3355
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
3275
3356
  };
3276
3357
  }
3277
- var WORKING_STATUSES;
3358
+ var WORKING_STATUSES, STATUS_ACTIVE_CHAT_MESSAGE_LIMIT, STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT, STATUS_ACTIVE_CHAT_STRING_LIMIT, STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT, STATUS_INPUT_CONTENT_LIMIT, STATUS_MODAL_MESSAGE_LIMIT, STATUS_MODAL_BUTTON_LIMIT;
3278
3359
  var init_normalize = __esm({
3279
3360
  "../../oss/packages/daemon-core/src/status/normalize.ts"() {
3280
3361
  "use strict";
@@ -3286,6 +3367,13 @@ var init_normalize = __esm({
3286
3367
  "thinking",
3287
3368
  "active"
3288
3369
  ]);
3370
+ STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
3371
+ STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
3372
+ STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
3373
+ STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
3374
+ STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
3375
+ STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
3376
+ STATUS_MODAL_BUTTON_LIMIT = 120;
3289
3377
  }
3290
3378
  });
3291
3379
 
@@ -3427,11 +3515,10 @@ function buildCliSession(state) {
3427
3515
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
3428
3516
  runtimeWriteOwner: state.runtime?.writeOwner || null,
3429
3517
  runtimeAttachedClients: state.runtime?.attachedClients || [],
3430
- launchMode: state.launchMode,
3431
3518
  mode: state.mode,
3432
3519
  resume: state.resume,
3433
3520
  activeChat,
3434
- capabilities: PTY_SESSION_CAPABILITIES,
3521
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
3435
3522
  controlValues: state.controlValues,
3436
3523
  providerControls: buildFallbackControls(
3437
3524
  state.providerControls
@@ -3501,7 +3588,7 @@ function buildSessionEntries(allStates, cdpManagers) {
3501
3588
  }
3502
3589
  return sessions;
3503
3590
  }
3504
- var IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES;
3591
+ var IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, CLI_CHAT_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES;
3505
3592
  var init_builders = __esm({
3506
3593
  "../../oss/packages/daemon-core/src/status/builders.ts"() {
3507
3594
  "use strict";
@@ -3534,6 +3621,11 @@ var init_builders = __esm({
3534
3621
  "terminal_io",
3535
3622
  "resize_terminal"
3536
3623
  ];
3624
+ CLI_CHAT_SESSION_CAPABILITIES = [
3625
+ "read_chat",
3626
+ "send_message",
3627
+ "resolve_action"
3628
+ ];
3537
3629
  ACP_SESSION_CAPABILITIES = [
3538
3630
  "read_chat",
3539
3631
  "send_message",
@@ -4658,6 +4750,13 @@ var init_cdp_commands = __esm({
4658
4750
  });
4659
4751
 
4660
4752
  // ../../oss/packages/daemon-core/src/commands/stream-commands.ts
4753
+ function getCliPresentationMode(h, targetSessionId) {
4754
+ if (!targetSessionId) return null;
4755
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
4756
+ if (instance?.category !== "cli") return null;
4757
+ const mode = instance.getPresentationMode?.();
4758
+ return mode === "chat" || mode === "terminal" ? mode : null;
4759
+ }
4661
4760
  async function handleFocusSession(h, args) {
4662
4761
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4663
4762
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -4668,6 +4767,9 @@ async function handleFocusSession(h, args) {
4668
4767
  function handlePtyInput(h, args) {
4669
4768
  const { cliType, data, targetSessionId } = args || {};
4670
4769
  if (!data) return { success: false, error: "data required" };
4770
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
4771
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
4772
+ }
4671
4773
  const adapter = h.getCliAdapter(targetSessionId || cliType);
4672
4774
  if (!adapter || typeof adapter.writeRaw !== "function") {
4673
4775
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -4678,6 +4780,9 @@ function handlePtyInput(h, args) {
4678
4780
  function handlePtyResize(h, args) {
4679
4781
  const { cliType, cols, rows, force, targetSessionId } = args || {};
4680
4782
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
4783
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
4784
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
4785
+ }
4681
4786
  const adapter = h.getCliAdapter(targetSessionId || cliType);
4682
4787
  if (!adapter || typeof adapter.resize !== "function") {
4683
4788
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -8736,6 +8841,9 @@ var init_ghostty_vt_backend = __esm({
8736
8841
  getText() {
8737
8842
  return this.terminal.formatPlainText({ trim: true }) || "";
8738
8843
  }
8844
+ getCursorPosition() {
8845
+ return this.terminal.getCursorPosition();
8846
+ }
8739
8847
  dispose() {
8740
8848
  this.terminal.dispose();
8741
8849
  }
@@ -17888,6 +17996,13 @@ var init_xterm_backend = __esm({
17888
17996
  while (last > first && !lines[last - 1]?.trim()) last--;
17889
17997
  return lines.slice(first, last).join("\n");
17890
17998
  }
17999
+ getCursorPosition() {
18000
+ const buffer = this.terminal.buffer.active;
18001
+ return {
18002
+ col: Math.max(0, buffer.cursorX || 0),
18003
+ row: Math.max(0, buffer.cursorY || 0)
18004
+ };
18005
+ }
17891
18006
  dispose() {
17892
18007
  this.terminal.dispose();
17893
18008
  }
@@ -17974,6 +18089,9 @@ var init_terminal_screen = __esm({
17974
18089
  getText() {
17975
18090
  return this.terminal.getText();
17976
18091
  }
18092
+ getCursorPosition() {
18093
+ return this.terminal.getCursorPosition();
18094
+ }
17977
18095
  dispose() {
17978
18096
  this.terminal.dispose();
17979
18097
  }
@@ -18210,6 +18328,7 @@ var init_router = __esm({
18210
18328
  // ─── CLI / ACP commands ───
18211
18329
  case "launch_cli":
18212
18330
  case "stop_cli":
18331
+ case "set_cli_view_mode":
18213
18332
  case "agent_command": {
18214
18333
  return this.deps.cliManager.handleCliCommand(cmd, args);
18215
18334
  }
@@ -18562,6 +18681,20 @@ var init_reporter = __esm({
18562
18681
  ts() {
18563
18682
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
18564
18683
  }
18684
+ summarizeLargePayloadSessions(payload) {
18685
+ const sessions = Array.isArray(payload.sessions) ? payload.sessions : [];
18686
+ return sessions.map((session) => ({
18687
+ id: String(session?.id || ""),
18688
+ providerType: String(session?.providerType || ""),
18689
+ bytes: (() => {
18690
+ try {
18691
+ return JSON.stringify(session).length;
18692
+ } catch {
18693
+ return 0;
18694
+ }
18695
+ })()
18696
+ })).sort((a, b2) => b2.bytes - a.bytes).slice(0, 3).map((session) => `${session.providerType || "unknown"}:${session.id}=${session.bytes}b`).join(", ");
18697
+ }
18565
18698
  async sendUnifiedStatusReport(opts) {
18566
18699
  const { serverConn, p2p } = this.deps;
18567
18700
  if (!serverConn?.isConnected()) return;
@@ -18614,9 +18747,16 @@ var init_reporter = __esm({
18614
18747
  screenshotUsage: this.deps.getScreenshotUsage?.() || null,
18615
18748
  connectedExtensions: []
18616
18749
  };
18750
+ const payloadBytes = JSON.stringify(payload).length;
18617
18751
  const p2pSent = this.sendP2PPayload(payload);
18618
18752
  if (p2pSent) {
18619
- LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
18753
+ LOG.debug("P2P", `sent (${payloadBytes} bytes)`);
18754
+ if (payloadBytes > 256 * 1024) {
18755
+ LOG.warn(
18756
+ "P2P",
18757
+ `large status payload (${payloadBytes} bytes) top sessions: ${this.summarizeLargePayloadSessions(payload) || "n/a"}`
18758
+ );
18759
+ }
18620
18760
  }
18621
18761
  if (opts?.p2pOnly) return;
18622
18762
  const wsPayload = {
@@ -18646,7 +18786,9 @@ var init_reporter = __esm({
18646
18786
  acpModes: session.acpModes
18647
18787
  })),
18648
18788
  p2p: payload.p2p,
18649
- timestamp: now
18789
+ timestamp: now,
18790
+ detectedIdes: payload.detectedIdes,
18791
+ availableProviders: payload.availableProviders
18650
18792
  };
18651
18793
  serverConn.sendMessage("status_report", wsPayload);
18652
18794
  LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
@@ -18694,6 +18836,7 @@ var init_pty_transport = __esm({
18694
18836
  this.handle = handle;
18695
18837
  }
18696
18838
  ready = Promise.resolve();
18839
+ terminalQueriesHandled = false;
18697
18840
  get pid() {
18698
18841
  return this.handle.pid;
18699
18842
  }
@@ -18747,6 +18890,32 @@ function stripTerminalNoise(str) {
18747
18890
  function sanitizeTerminalText(str) {
18748
18891
  return stripTerminalNoise(stripAnsi(str));
18749
18892
  }
18893
+ function buildCliSpawnEnv(baseEnv, overrides) {
18894
+ const env = {};
18895
+ const source = { ...baseEnv, ...overrides || {} };
18896
+ for (const [key, value] of Object.entries(source)) {
18897
+ if (typeof value !== "string") continue;
18898
+ env[key] = value;
18899
+ }
18900
+ for (const key of Object.keys(env)) {
18901
+ if (key === "INIT_CWD" || key === "NO_COLOR" || key === "FORCE_COLOR" || key === "npm_command" || key === "npm_execpath" || key === "npm_node_execpath" || key.startsWith("npm_") || key.startsWith("npm_config_") || key.startsWith("npm_package_") || key.startsWith("npm_lifecycle_") || key.startsWith("PNPM_") || key.startsWith("YARN_") || key.startsWith("BUN_")) {
18902
+ delete env[key];
18903
+ }
18904
+ }
18905
+ return env;
18906
+ }
18907
+ function computeTerminalQueryTail(buffer) {
18908
+ const prefixes = ["\x1B[6n", "\x1B[?6n"];
18909
+ const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
18910
+ const start = Math.max(0, buffer.length - maxLength);
18911
+ for (let i = start; i < buffer.length; i++) {
18912
+ const suffix = buffer.slice(i);
18913
+ if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
18914
+ return suffix;
18915
+ }
18916
+ }
18917
+ return "";
18918
+ }
18750
18919
  function findBinary(name) {
18751
18920
  const isWin = os13.platform() === "win32";
18752
18921
  try {
@@ -18833,36 +19002,6 @@ function promptLikelyVisible(screenText, promptSnippet) {
18833
19002
  ).length;
18834
19003
  return matched >= required2;
18835
19004
  }
18836
- function splitHistoryLines(text) {
18837
- return String(text || "").split("\n").map((line) => line.replace(/\s+$/, ""));
18838
- }
18839
- function normalizeHistoryLine(line) {
18840
- return String(line || "").replace(/\s+/g, " ").trim();
18841
- }
18842
- function mergeTerminalHistory(existing, snapshot) {
18843
- const next = String(snapshot || "").trim();
18844
- if (!next) return existing;
18845
- const prev = String(existing || "").trim();
18846
- if (!prev) return next;
18847
- if (prev === next || prev.endsWith(next)) return prev;
18848
- const prevLines = splitHistoryLines(prev);
18849
- const nextLines = splitHistoryLines(next);
18850
- const prevNorm = prevLines.map(normalizeHistoryLine);
18851
- const nextNorm = nextLines.map(normalizeHistoryLine);
18852
- const maxOverlap = Math.min(prevLines.length, nextLines.length);
18853
- for (let overlap = maxOverlap; overlap >= 1; overlap -= 1) {
18854
- const prevTail = prevNorm.slice(prevNorm.length - overlap);
18855
- const nextHead = nextNorm.slice(0, overlap);
18856
- if (prevTail.every((line, index) => line === nextHead[index])) {
18857
- return [...prevLines, ...nextLines.slice(overlap)].join("\n").trim();
18858
- }
18859
- }
18860
- const compactPrev = prevNorm.join("\n");
18861
- const compactNext = nextNorm.join("\n");
18862
- if (compactPrev.includes(compactNext)) return prev;
18863
- return `${prev}
18864
- ${next}`.trim();
18865
- }
18866
19005
  function parsePatternEntry(x) {
18867
19006
  if (x instanceof RegExp) return x;
18868
19007
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -18977,6 +19116,7 @@ var init_provider_cli_adapter = __esm({
18977
19116
  pendingOutputParseTimer = null;
18978
19117
  ptyOutputBuffer = "";
18979
19118
  ptyOutputFlushTimer = null;
19119
+ pendingTerminalQueryTail = "";
18980
19120
  // Server log forwarding
18981
19121
  serverConn = null;
18982
19122
  logBuffer = [];
@@ -19008,9 +19148,7 @@ var init_provider_cli_adapter = __esm({
19008
19148
  /** Full accumulated raw PTY output (with ANSI) */
19009
19149
  accumulatedRawBuffer = "";
19010
19150
  /** Current visible terminal screen snapshot */
19011
- terminalScreen = new TerminalScreen(40, 120);
19012
- /** Rolling append-only terminal transcript built from screen snapshots */
19013
- terminalHistory = "";
19151
+ terminalScreen = new TerminalScreen(30, 100);
19014
19152
  /** Max accumulated buffer size (last 50KB) */
19015
19153
  static MAX_ACCUMULATED_BUFFER = 5e4;
19016
19154
  currentTurnScope = null;
@@ -19018,6 +19156,13 @@ var init_provider_cli_adapter = __esm({
19018
19156
  this.messages = [...this.committedMessages];
19019
19157
  this.structuredMessages = [...this.committedMessages];
19020
19158
  }
19159
+ normalizeParsedMessages(parsedMessages) {
19160
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
19161
+ role: message.role,
19162
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
19163
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
19164
+ }));
19165
+ }
19021
19166
  sliceFromOffset(text, start) {
19022
19167
  if (!text) return "";
19023
19168
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -19025,15 +19170,13 @@ var init_provider_cli_adapter = __esm({
19025
19170
  return text.slice(start);
19026
19171
  }
19027
19172
  buildParseInput(baseMessages, partialResponse, scope) {
19028
- const buffer = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
19173
+ const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
19029
19174
  const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
19030
- const terminalHistory = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.terminalHistory : this.terminalHistory;
19031
19175
  return {
19032
19176
  buffer,
19033
19177
  rawBuffer,
19034
19178
  recentBuffer: buffer.slice(-1e3) || this.recentOutputBuffer,
19035
19179
  screenText: this.terminalScreen.getText(),
19036
- terminalHistory,
19037
19180
  messages: [...baseMessages],
19038
19181
  partialResponse
19039
19182
  };
@@ -19111,13 +19254,10 @@ var init_provider_cli_adapter = __esm({
19111
19254
  shellArgs = allArgs;
19112
19255
  }
19113
19256
  const ptyOpts = {
19114
- cols: 120,
19115
- rows: 40,
19257
+ cols: 100,
19258
+ rows: 30,
19116
19259
  cwd: this.workingDir,
19117
- env: {
19118
- ...process.env,
19119
- ...spawnConfig.env
19120
- }
19260
+ env: buildCliSpawnEnv(process.env, spawnConfig.env)
19121
19261
  };
19122
19262
  try {
19123
19263
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
@@ -19135,8 +19275,8 @@ var init_provider_cli_adapter = __esm({
19135
19275
  }
19136
19276
  this.ptyProcess.onData((data) => {
19137
19277
  if (Date.now() < this.resizeSuppressUntil) return;
19138
- if (data.includes("\x1B[6n") || data.includes("\x1B[?6n")) {
19139
- this.ptyProcess?.write("\x1B[1;1R");
19278
+ if (!this.ptyProcess?.terminalQueriesHandled) {
19279
+ this.respondToTerminalQueries(data);
19140
19280
  }
19141
19281
  this.pendingOutputParseBuffer += data;
19142
19282
  if (!this.pendingOutputParseTimer) {
@@ -19171,8 +19311,8 @@ var init_provider_cli_adapter = __esm({
19171
19311
  this.spawnAt = Date.now();
19172
19312
  this.startupParseGate = true;
19173
19313
  this.startupBuffer = "";
19174
- this.terminalScreen.reset(40, 120);
19175
- this.terminalHistory = "";
19314
+ this.terminalScreen.reset(30, 100);
19315
+ this.pendingTerminalQueryTail = "";
19176
19316
  this.currentTurnScope = null;
19177
19317
  this.ready = false;
19178
19318
  await this.ptyProcess.ready;
@@ -19182,7 +19322,6 @@ var init_provider_cli_adapter = __esm({
19182
19322
  // ─── Output Handling ────────────────────────────
19183
19323
  handleOutput(rawData) {
19184
19324
  this.terminalScreen.write(rawData);
19185
- this.terminalHistory = mergeTerminalHistory(this.terminalHistory, this.terminalScreen.getText());
19186
19325
  const cleanData = sanitizeTerminalText(rawData);
19187
19326
  if (this.isWaitingForResponse && cleanData) {
19188
19327
  this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
@@ -19414,6 +19553,15 @@ var init_provider_cli_adapter = __esm({
19414
19553
  this.onStatusChange?.();
19415
19554
  }
19416
19555
  commitCurrentTranscript() {
19556
+ const parsed = this.parseCurrentTranscript(
19557
+ this.committedMessages,
19558
+ this.responseBuffer,
19559
+ this.currentTurnScope
19560
+ );
19561
+ if (parsed && Array.isArray(parsed.messages)) {
19562
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
19563
+ this.syncMessageViews();
19564
+ }
19417
19565
  }
19418
19566
  // ─── Script Execution ──────────────────────────
19419
19567
  runDetectStatus(text) {
@@ -19449,8 +19597,7 @@ var init_provider_cli_adapter = __esm({
19449
19597
  status: this.currentStatus,
19450
19598
  messages: [...this.committedMessages],
19451
19599
  workingDir: this.workingDir,
19452
- activeModal: this.activeModal,
19453
- terminalHistory: this.terminalHistory
19600
+ activeModal: this.activeModal
19454
19601
  };
19455
19602
  }
19456
19603
  /**
@@ -19458,12 +19605,25 @@ var init_provider_cli_adapter = __esm({
19458
19605
  * Called by command handler / dashboard for rich content rendering.
19459
19606
  */
19460
19607
  getScriptParsedStatus() {
19608
+ const parsed = this.parseCurrentTranscript(
19609
+ this.committedMessages,
19610
+ this.responseBuffer,
19611
+ this.currentTurnScope
19612
+ );
19613
+ if (parsed && Array.isArray(parsed.messages)) {
19614
+ return {
19615
+ id: parsed.id || "cli_session",
19616
+ status: parsed.status || this.currentStatus,
19617
+ title: parsed.title || this.cliName,
19618
+ messages: parsed.messages,
19619
+ activeModal: parsed.activeModal ?? this.activeModal
19620
+ };
19621
+ }
19461
19622
  const messages = [...this.committedMessages];
19462
19623
  return {
19463
19624
  id: "cli_session",
19464
19625
  status: this.currentStatus,
19465
19626
  title: this.cliName,
19466
- terminalHistory: this.terminalHistory,
19467
19627
  messages: messages.slice(-50).map((message, index) => ({
19468
19628
  id: `msg_${index}`,
19469
19629
  role: message.role,
@@ -19531,10 +19691,9 @@ ${data.message || ""}`.trim();
19531
19691
  prompt: text,
19532
19692
  startedAt: Date.now(),
19533
19693
  bufferStart: this.accumulatedBuffer.length,
19534
- rawBufferStart: this.accumulatedRawBuffer.length,
19535
- terminalHistoryStart: this.terminalHistory.length
19694
+ rawBufferStart: this.accumulatedRawBuffer.length
19536
19695
  };
19537
- LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} terminal=${this.currentTurnScope.terminalHistoryStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
19696
+ LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
19538
19697
  this.submitRetryUsed = false;
19539
19698
  this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
19540
19699
  const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
@@ -19719,6 +19878,7 @@ ${data.message || ""}`.trim();
19719
19878
  this.pendingOutputParseTimer = null;
19720
19879
  }
19721
19880
  this.pendingOutputParseBuffer = "";
19881
+ this.pendingTerminalQueryTail = "";
19722
19882
  if (this.ptyOutputFlushTimer) {
19723
19883
  clearTimeout(this.ptyOutputFlushTimer);
19724
19884
  this.ptyOutputFlushTimer = null;
@@ -19758,6 +19918,7 @@ ${data.message || ""}`.trim();
19758
19918
  this.pendingOutputParseTimer = null;
19759
19919
  }
19760
19920
  this.pendingOutputParseBuffer = "";
19921
+ this.pendingTerminalQueryTail = "";
19761
19922
  if (this.ptyOutputFlushTimer) {
19762
19923
  clearTimeout(this.ptyOutputFlushTimer);
19763
19924
  this.ptyOutputFlushTimer = null;
@@ -19784,7 +19945,6 @@ ${data.message || ""}`.trim();
19784
19945
  this.syncMessageViews();
19785
19946
  this.accumulatedBuffer = "";
19786
19947
  this.accumulatedRawBuffer = "";
19787
- this.terminalHistory = "";
19788
19948
  this.currentTurnScope = null;
19789
19949
  this.submitRetryUsed = false;
19790
19950
  this.submitRetryPromptSnippet = "";
@@ -19793,6 +19953,7 @@ ${data.message || ""}`.trim();
19793
19953
  this.pendingOutputParseTimer = null;
19794
19954
  }
19795
19955
  this.pendingOutputParseBuffer = "";
19956
+ this.pendingTerminalQueryTail = "";
19796
19957
  if (this.ptyOutputFlushTimer) {
19797
19958
  clearTimeout(this.ptyOutputFlushTimer);
19798
19959
  this.ptyOutputFlushTimer = null;
@@ -19854,7 +20015,6 @@ ${data.message || ""}`.trim();
19854
20015
  structuredMessages: this.structuredMessages.slice(-20),
19855
20016
  messageCount: this.committedMessages.length,
19856
20017
  screenText: sanitizeTerminalText(this.terminalScreen.getText()).slice(-4e3),
19857
- terminalHistory: this.terminalHistory.slice(-8e3),
19858
20018
  currentTurnScope: this.currentTurnScope,
19859
20019
  startupBuffer: this.startupBuffer.slice(-4e3),
19860
20020
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
@@ -19882,6 +20042,20 @@ ${data.message || ""}`.trim();
19882
20042
  ptyAlive: !!this.ptyProcess
19883
20043
  };
19884
20044
  }
20045
+ respondToTerminalQueries(data) {
20046
+ if (!this.ptyProcess || !data) return;
20047
+ const combined = this.pendingTerminalQueryTail + data;
20048
+ const regex = /\x1b\[(\?)?6n/g;
20049
+ let match;
20050
+ while ((match = regex.exec(combined)) !== null) {
20051
+ const cursor = this.terminalScreen.getCursorPosition();
20052
+ const row = Math.max(1, (cursor.row | 0) + 1);
20053
+ const col = Math.max(1, (cursor.col | 0) + 1);
20054
+ const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
20055
+ this.ptyProcess.write(response);
20056
+ }
20057
+ this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
20058
+ }
19885
20059
  };
19886
20060
  }
19887
20061
  });
@@ -19897,14 +20071,13 @@ var init_cli_provider_instance = __esm({
19897
20071
  init_chat_history();
19898
20072
  init_logger();
19899
20073
  CliProviderInstance = class {
19900
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
20074
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
19901
20075
  this.provider = provider;
19902
20076
  this.workingDir = workingDir;
19903
20077
  this.cliArgs = cliArgs;
19904
20078
  this.type = provider.type;
19905
20079
  this.instanceId = instanceId || crypto3.randomUUID();
19906
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
19907
- this.resolvedOutputFormat = this.resolveOutputFormat();
20080
+ this.presentationMode = "chat";
19908
20081
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
19909
20082
  this.monitor = new StatusMonitor();
19910
20083
  this.historyWriter = new ChatHistoryWriter();
@@ -19923,26 +20096,7 @@ var init_cli_provider_instance = __esm({
19923
20096
  lastApprovalEventAt = 0;
19924
20097
  historyWriter;
19925
20098
  instanceId;
19926
- launchMode;
19927
- resolvedOutputFormat;
19928
- /**
19929
- * Determine output rendering format from:
19930
- * 1. launchMode.outputFormat (explicit override)
19931
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
19932
- * 3. Default: 'terminal'
19933
- */
19934
- resolveOutputFormat() {
19935
- if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
19936
- if (this.provider.launchOptions?.length) {
19937
- for (const opt of this.provider.launchOptions) {
19938
- if (!opt.outputFormatMap) continue;
19939
- for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
19940
- if (this.cliArgs.includes(val)) return fmt;
19941
- }
19942
- }
19943
- }
19944
- return "terminal";
19945
- }
20099
+ presentationMode;
19946
20100
  // ─── Lifecycle ─────────────────────────────────
19947
20101
  async init(context) {
19948
20102
  this.context = context;
@@ -19967,30 +20121,21 @@ var init_cli_provider_instance = __esm({
19967
20121
  }
19968
20122
  getState() {
19969
20123
  const adapterStatus = this.adapter.getStatus();
20124
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
19970
20125
  const runtime = this.adapter.getRuntimeMetadata();
19971
20126
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
19972
- if (adapterStatus.terminalHistory?.trim()) {
19973
- this.historyWriter.appendTerminalHistory(
19974
- this.type,
19975
- adapterStatus.terminalHistory,
19976
- `${this.provider.name} \xB7 ${dirName}`,
19977
- this.instanceId
19978
- );
19979
- }
19980
20127
  return {
19981
20128
  type: this.type,
19982
20129
  name: this.provider.name,
19983
20130
  category: "cli",
19984
20131
  status: adapterStatus.status,
19985
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
19986
- launchMode: this.launchMode?.id,
20132
+ mode: this.presentationMode,
19987
20133
  activeChat: {
19988
20134
  id: `${this.type}_${this.workingDir}`,
19989
- title: `${this.provider.name} \xB7 ${dirName}`,
19990
- status: adapterStatus.status,
19991
- messages: [],
19992
- activeModal: adapterStatus.activeModal,
19993
- terminalHistory: adapterStatus.terminalHistory,
20135
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
20136
+ status: parsedStatus?.status || adapterStatus.status,
20137
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
20138
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
19994
20139
  inputContent: ""
19995
20140
  },
19996
20141
  workspace: this.workingDir,
@@ -20012,6 +20157,13 @@ var init_cli_provider_instance = __esm({
20012
20157
  providerControls: this.provider.controls
20013
20158
  };
20014
20159
  }
20160
+ setPresentationMode(mode) {
20161
+ if (this.presentationMode === mode) return;
20162
+ this.presentationMode = mode;
20163
+ }
20164
+ getPresentationMode() {
20165
+ return this.presentationMode;
20166
+ }
20015
20167
  onEvent(event, data) {
20016
20168
  if (event === "send_message" && data?.text) {
20017
20169
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -20272,7 +20424,7 @@ __export(util_exports, {
20272
20424
  getSizableOrigin: () => getSizableOrigin,
20273
20425
  hexToUint8Array: () => hexToUint8Array,
20274
20426
  isObject: () => isObject,
20275
- isPlainObject: () => isPlainObject,
20427
+ isPlainObject: () => isPlainObject2,
20276
20428
  issue: () => issue,
20277
20429
  joinValues: () => joinValues,
20278
20430
  jsonStringifyReplacer: () => jsonStringifyReplacer,
@@ -20441,7 +20593,7 @@ function slugify(input) {
20441
20593
  function isObject(data) {
20442
20594
  return typeof data === "object" && data !== null && !Array.isArray(data);
20443
20595
  }
20444
- function isPlainObject(o) {
20596
+ function isPlainObject2(o) {
20445
20597
  if (isObject(o) === false)
20446
20598
  return false;
20447
20599
  const ctor = o.constructor;
@@ -20458,7 +20610,7 @@ function isPlainObject(o) {
20458
20610
  return true;
20459
20611
  }
20460
20612
  function shallowClone(o) {
20461
- if (isPlainObject(o))
20613
+ if (isPlainObject2(o))
20462
20614
  return { ...o };
20463
20615
  if (Array.isArray(o))
20464
20616
  return [...o];
@@ -20594,7 +20746,7 @@ function omit(schema, mask) {
20594
20746
  return clone(schema, def);
20595
20747
  }
20596
20748
  function extend(schema, shape) {
20597
- if (!isPlainObject(shape)) {
20749
+ if (!isPlainObject2(shape)) {
20598
20750
  throw new Error("Invalid input to extend: expected a plain object");
20599
20751
  }
20600
20752
  const checks = schema._zod.def.checks;
@@ -20617,7 +20769,7 @@ function extend(schema, shape) {
20617
20769
  return clone(schema, def);
20618
20770
  }
20619
20771
  function safeExtend(schema, shape) {
20620
- if (!isPlainObject(shape)) {
20772
+ if (!isPlainObject2(shape)) {
20621
20773
  throw new Error("Invalid input to safeExtend: expected a plain object");
20622
20774
  }
20623
20775
  const def = mergeDefs(schema._zod.def, {
@@ -22100,7 +22252,7 @@ function mergeValues(a, b2) {
22100
22252
  if (a instanceof Date && b2 instanceof Date && +a === +b2) {
22101
22253
  return { valid: true, data: a };
22102
22254
  }
22103
- if (isPlainObject(a) && isPlainObject(b2)) {
22255
+ if (isPlainObject2(a) && isPlainObject2(b2)) {
22104
22256
  const bKeys = Object.keys(b2);
22105
22257
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
22106
22258
  const newObj = { ...a, ...b2 };
@@ -23295,7 +23447,7 @@ var init_schemas = __esm({
23295
23447
  $ZodType.init(inst, def);
23296
23448
  inst._zod.parse = (payload, ctx) => {
23297
23449
  const input = payload.value;
23298
- if (!isPlainObject(input)) {
23450
+ if (!isPlainObject2(input)) {
23299
23451
  payload.issues.push({
23300
23452
  expected: "record",
23301
23453
  code: "invalid_type",
@@ -37399,6 +37551,15 @@ var init_cli_manager = __esm({
37399
37551
  const hash2 = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
37400
37552
  return `${cliType}_${hash2}`;
37401
37553
  }
37554
+ getSessionPresentationMode(sessionId) {
37555
+ if (!sessionId) return null;
37556
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
37557
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
37558
+ return mode === "chat" || mode === "terminal" ? mode : null;
37559
+ }
37560
+ isTerminalSession(sessionId) {
37561
+ return this.getSessionPresentationMode(sessionId) === "terminal";
37562
+ }
37402
37563
  persistRecentActivity(entry) {
37403
37564
  try {
37404
37565
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -37454,12 +37615,12 @@ var init_cli_manager = __esm({
37454
37615
  }
37455
37616
  }, 3e3);
37456
37617
  }
37457
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
37618
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
37458
37619
  const instanceManager = this.deps.getInstanceManager();
37459
37620
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
37460
37621
  if (!instanceManager) throw new Error("InstanceManager not available");
37461
37622
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
37462
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
37623
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
37463
37624
  try {
37464
37625
  await instanceManager.addInstance(key, cliInstance, {
37465
37626
  serverConn: this.deps.getServerConn(),
@@ -37485,7 +37646,7 @@ var init_cli_manager = __esm({
37485
37646
  this.startCliExitMonitor(key, cliType);
37486
37647
  }
37487
37648
  // ─── Session start/management ──────────────────────────────
37488
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
37649
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
37489
37650
  const trimmed = (workingDir || "").trim();
37490
37651
  if (!trimmed) throw new Error("working directory required");
37491
37652
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os14.homedir()) : path10.resolve(trimmed);
@@ -37577,29 +37738,7 @@ ${installInfo}`
37577
37738
  if (provider) {
37578
37739
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
37579
37740
  }
37580
- let resolvedCliArgs = cliArgs;
37581
- let resolvedLaunchMode = launchMode;
37582
- const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
37583
- if (activeMode) {
37584
- resolvedLaunchMode = activeMode.id;
37585
- }
37586
- if (provider?.launchArgBuilder) {
37587
- const defaults = {};
37588
- for (const opt of provider.launchOptions || []) {
37589
- if (opt.default !== void 0) defaults[opt.id] = opt.default;
37590
- }
37591
- const modeOptions = activeMode?.options || {};
37592
- const userOptions = launchOptionValues || {};
37593
- const merged = { ...defaults, ...modeOptions, ...userOptions };
37594
- const extraArgs = provider.launchArgBuilder(merged);
37595
- if (extraArgs.length) {
37596
- resolvedCliArgs = [...cliArgs || [], ...extraArgs];
37597
- console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
37598
- }
37599
- } else if (activeMode?.extraArgs?.length) {
37600
- resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
37601
- console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
37602
- }
37741
+ const resolvedCliArgs = cliArgs;
37603
37742
  const instanceManager = this.deps.getInstanceManager();
37604
37743
  if (provider && instanceManager) {
37605
37744
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -37611,8 +37750,7 @@ ${installInfo}`
37611
37750
  resolvedCliArgs,
37612
37751
  resolvedProvider,
37613
37752
  {},
37614
- false,
37615
- resolvedLaunchMode
37753
+ false
37616
37754
  );
37617
37755
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
37618
37756
  } else {
@@ -37724,8 +37862,7 @@ ${installInfo}`
37724
37862
  record2.cliArgs,
37725
37863
  resolvedProvider,
37726
37864
  {},
37727
- true,
37728
- record2.launchMode
37865
+ true
37729
37866
  );
37730
37867
  restored += 1;
37731
37868
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record2.runtimeKey || record2.runtimeId} (${record2.displayName || record2.workspace})`);
@@ -37767,6 +37904,14 @@ ${installInfo}`
37767
37904
  }
37768
37905
  return null;
37769
37906
  }
37907
+ findAdapterBySessionId(instanceKey) {
37908
+ if (!instanceKey) return null;
37909
+ let ik = instanceKey;
37910
+ const colonIdx = ik.lastIndexOf(":");
37911
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
37912
+ const adapter = this.adapters.get(ik);
37913
+ return adapter ? { adapter, key: ik } : null;
37914
+ }
37770
37915
  // ─── CLI command handling ────────────────────────────
37771
37916
  async handleCliCommand(cmd, args) {
37772
37917
  switch (cmd) {
@@ -37795,7 +37940,7 @@ ${installInfo}`
37795
37940
  const dir = resolved.path;
37796
37941
  const launchSource = resolved.source;
37797
37942
  if (!cliType) throw new Error("cliType required");
37798
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
37943
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
37799
37944
  let newKey = null;
37800
37945
  for (const [k, adapter] of this.adapters) {
37801
37946
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -37817,6 +37962,23 @@ ${installInfo}`
37817
37962
  }
37818
37963
  return { success: true, cliType, dir, stopped: true, mode };
37819
37964
  }
37965
+ case "set_cli_view_mode": {
37966
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
37967
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
37968
+ const cliType = args?.cliType || args?.agentType || "";
37969
+ const dir = args?.dir || "";
37970
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
37971
+ if (!found) {
37972
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
37973
+ }
37974
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
37975
+ if (!(instance instanceof CliProviderInstance)) {
37976
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
37977
+ }
37978
+ instance.setPresentationMode(mode);
37979
+ this.deps.onStatusChange();
37980
+ return { success: true, id: found.key, mode };
37981
+ }
37820
37982
  case "restart_session": {
37821
37983
  const cliType = args?.cliType || args?.agentType || args?.ideType;
37822
37984
  const cfg = loadConfig();
@@ -38467,7 +38629,12 @@ var init_poller = __esm({
38467
38629
  } catch {
38468
38630
  }
38469
38631
  }
38470
- if (!resolvedActiveSessionId || !parentSessionId) continue;
38632
+ if (!resolvedActiveSessionId || !parentSessionId) {
38633
+ if (parentSessionId) {
38634
+ this.deps.onStreamsUpdated?.(ideType, []);
38635
+ }
38636
+ continue;
38637
+ }
38471
38638
  try {
38472
38639
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
38473
38640
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -38495,7 +38662,11 @@ var init_agent_stream = __esm({
38495
38662
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
38496
38663
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
38497
38664
  if (!ideInstance?.onEvent) return;
38665
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
38498
38666
  for (const stream of streams) {
38667
+ if (typeof stream.agentType === "string" && stream.agentType) {
38668
+ seenExtensionTypes.add(stream.agentType);
38669
+ }
38499
38670
  ideInstance.onEvent("stream_update", {
38500
38671
  extensionType: stream.agentType,
38501
38672
  streams: [stream],
@@ -38512,6 +38683,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
38512
38683
  inputContent: stream.inputContent || ""
38513
38684
  });
38514
38685
  }
38686
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
38687
+ if (streams.length === 0) {
38688
+ ideInstance.onEvent("stream_reset_all");
38689
+ return;
38690
+ }
38691
+ for (const extensionType of extensionTypes) {
38692
+ if (!seenExtensionTypes.has(extensionType)) {
38693
+ ideInstance.onEvent("stream_reset", { extensionType });
38694
+ }
38695
+ }
38515
38696
  }
38516
38697
  var init_forward = __esm({
38517
38698
  "../../oss/packages/daemon-core/src/agent-stream/forward.ts"() {
@@ -43094,6 +43275,7 @@ var init_session_host_transport = __esm({
43094
43275
  this.ready = this.boot();
43095
43276
  }
43096
43277
  ready;
43278
+ terminalQueriesHandled = true;
43097
43279
  client;
43098
43280
  dataCallbacks = /* @__PURE__ */ new Set();
43099
43281
  exitCallbacks = /* @__PURE__ */ new Set();
@@ -43992,13 +44174,8 @@ var init_server_connection = __esm({
43992
44174
  LOG.info("Server", `[ServerConn] Run 'adhdev setup' to re-authenticate.`);
43993
44175
  this.setState("disconnected");
43994
44176
  try {
43995
- const path18 = require("path");
43996
- const fs16 = require("fs");
43997
- const configPath = path18.join(process.env.HOME || process.env.USERPROFILE || "", ".adhdev", "config.json");
43998
- if (fs16.existsSync(configPath)) {
43999
- fs16.unlinkSync(configPath);
44000
- LOG.info("Server", `[ServerConn] Config file removed. Re-run 'adhdev setup'.`);
44001
- }
44177
+ resetConfig();
44178
+ LOG.info("Server", `[ServerConn] Config reset. Re-run 'adhdev setup'.`);
44002
44179
  } catch {
44003
44180
  }
44004
44181
  return;
@@ -44267,10 +44444,9 @@ ${e?.stack || ""}`);
44267
44444
  async fetchTurnCredentials() {
44268
44445
  try {
44269
44446
  const serverUrl = process.env.ADHDEV_SERVER_URL || "https://api.adhf.dev";
44270
- const configPath = path15.join(os18.homedir(), ".adhdev", "config.json");
44271
44447
  let token = "";
44272
44448
  try {
44273
- const config2 = JSON.parse(fs13.readFileSync(configPath, "utf-8"));
44449
+ const config2 = loadConfig();
44274
44450
  token = config2.machineSecret || "";
44275
44451
  } catch {
44276
44452
  }
@@ -44569,8 +44745,9 @@ ${e?.stack || ""}`);
44569
44745
  log(`pty_input: REJECTED \u2014 permission=${permission} peer=${peerId}`);
44570
44746
  return;
44571
44747
  }
44572
- if (this.ptyInputHandler && parsed.data) {
44573
- this.ptyInputHandler(parsed.cliType || "", parsed.data);
44748
+ const sessionId = parsed.sessionId || parsed.cliId || parsed.cliType || "";
44749
+ if (this.ptyInputHandler && parsed.data && sessionId) {
44750
+ this.ptyInputHandler(sessionId, parsed.data);
44574
44751
  }
44575
44752
  return;
44576
44753
  }
@@ -44580,8 +44757,9 @@ ${e?.stack || ""}`);
44580
44757
  log(`pty_resize: REJECTED \u2014 permission=${permission} peer=${peerId}`);
44581
44758
  return;
44582
44759
  }
44583
- if (this.ptyResizeHandler && parsed.cols && parsed.rows) {
44584
- this.ptyResizeHandler(parsed.cliType || "", parsed.cols, parsed.rows);
44760
+ const sessionId = parsed.sessionId || parsed.cliId || parsed.cliType || "";
44761
+ if (this.ptyResizeHandler && parsed.cols && parsed.rows && sessionId) {
44762
+ this.ptyResizeHandler(sessionId, parsed.cols, parsed.rows);
44585
44763
  }
44586
44764
  return;
44587
44765
  }
@@ -44609,8 +44787,8 @@ ${e?.stack || ""}`);
44609
44787
  return sentAny;
44610
44788
  }
44611
44789
  /** Broadcast PTY output to all connected peers */
44612
- broadcastPtyOutput(cliType, data) {
44613
- const msg = JSON.stringify({ type: "pty_output", cliType, data });
44790
+ broadcastPtyOutput(sessionId, data) {
44791
+ const msg = JSON.stringify({ type: "pty_output", sessionId, data });
44614
44792
  let sentAny = false;
44615
44793
  for (const peer of this.peers.values()) {
44616
44794
  if (peer.state !== "connected" || !peer.dataChannel) continue;
@@ -45191,7 +45369,7 @@ var init_adhdev_daemon = __esm({
45191
45369
  fs15 = __toESM(require("fs"));
45192
45370
  path17 = __toESM(require("path"));
45193
45371
  import_chalk2 = __toESM(require("chalk"));
45194
- pkgVersion = "0.7.41";
45372
+ pkgVersion = "0.7.43";
45195
45373
  if (pkgVersion === "unknown") {
45196
45374
  try {
45197
45375
  const possiblePaths = [
@@ -45236,6 +45414,16 @@ var init_adhdev_daemon = __esm({
45236
45414
  constructor() {
45237
45415
  this.localPort = 19222;
45238
45416
  }
45417
+ getCliPresentationMode(sessionId) {
45418
+ if (!sessionId || !this.components) return null;
45419
+ const instance = this.components.instanceManager.getInstance(sessionId);
45420
+ if (instance?.category !== "cli") return null;
45421
+ const mode = instance.getPresentationMode?.();
45422
+ return mode === "chat" || mode === "terminal" ? mode : null;
45423
+ }
45424
+ isTerminalCliSession(sessionId) {
45425
+ return this.getCliPresentationMode(sessionId) === "terminal";
45426
+ }
45239
45427
  async start(options = {}) {
45240
45428
  try {
45241
45429
  const { installGlobalInterceptor: installGlobalInterceptor2 } = require("./logging/logger");
@@ -45265,9 +45453,6 @@ ${err?.stack || ""}`);
45265
45453
  const authToken = config2.machineSecret;
45266
45454
  if (!authToken) {
45267
45455
  console.log(import_chalk2.default.red("\n\u2717 No machine secret found."));
45268
- if (config2.connectionToken) {
45269
- console.log(import_chalk2.default.yellow(" Legacy connectionToken detected \u2014 please re-run setup."));
45270
- }
45271
45456
  console.log(import_chalk2.default.gray(" Run `adhdev setup` first.\n"));
45272
45457
  process.exit(1);
45273
45458
  }
@@ -45277,7 +45462,12 @@ ${err?.stack || ""}`);
45277
45462
  providerLogFn: LOG.forComponent("Provider").asLogFn(),
45278
45463
  cliManagerDeps: {
45279
45464
  getServerConn: () => this.serverConn,
45280
- getP2p: () => this.p2p,
45465
+ getP2p: () => ({
45466
+ broadcastPtyOutput: (key, data) => {
45467
+ if (!this.isTerminalCliSession(key)) return;
45468
+ this.p2p?.broadcastPtyOutput(key, data);
45469
+ }
45470
+ }),
45281
45471
  onStatusChange: () => this.statusReporter?.onStatusChange(),
45282
45472
  removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
45283
45473
  createPtyTransportFactory: ({ runtimeId, providerType, workspace, cliArgs, attachExisting }) => new SessionHostPtyTransportFactory({
@@ -45354,14 +45544,16 @@ ${err?.stack || ""}`);
45354
45544
  return { id: req.id, success: result.success, entries: result.files, error: result.error };
45355
45545
  }
45356
45546
  });
45357
- this.p2p.onPtyInput((cliId, data) => {
45358
- const found = this.components.cliManager.findAdapter(cliId, { instanceKey: cliId });
45547
+ this.p2p.onPtyInput((sessionId, data) => {
45548
+ if (!this.isTerminalCliSession(sessionId)) return;
45549
+ const found = this.components.cliManager.findAdapter(sessionId, { instanceKey: sessionId });
45359
45550
  if (found && typeof found.adapter.writeRaw === "function") {
45360
45551
  found.adapter.writeRaw(data);
45361
45552
  }
45362
45553
  });
45363
- this.p2p.onPtyResize((cliId, cols, rows) => {
45364
- const found = this.components.cliManager.findAdapter(cliId, { instanceKey: cliId });
45554
+ this.p2p.onPtyResize((sessionId, cols, rows) => {
45555
+ if (!this.isTerminalCliSession(sessionId)) return;
45556
+ const found = this.components.cliManager.findAdapter(sessionId, { instanceKey: sessionId });
45365
45557
  if (found && typeof found.adapter.resize === "function") {
45366
45558
  found.adapter.resize(cols, rows);
45367
45559
  }
@@ -45537,6 +45729,9 @@ ${err?.stack || ""}`);
45537
45729
  case "get_runtime_snapshot": {
45538
45730
  const sessionId = typeof data.sessionId === "string" ? data.sessionId : "";
45539
45731
  if (!sessionId) return { success: false, error: "sessionId is required" };
45732
+ if (!this.isTerminalCliSession(sessionId)) {
45733
+ return { success: false, error: "CLI session is not in terminal mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
45734
+ }
45540
45735
  if (!this.sessionHostEndpoint) return { success: false, error: "Session host unavailable" };
45541
45736
  const client = new SessionHostClient({ endpoint: this.sessionHostEndpoint });
45542
45737
  try {