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/cli/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,
@@ -2345,6 +2379,8 @@ var init_extension_provider_instance = __esm({
2345
2379
  this.detectTransition(newStatus, data);
2346
2380
  this.currentStatus = newStatus;
2347
2381
  }
2382
+ } else if (event === "stream_reset") {
2383
+ this.resetStreamState();
2348
2384
  } else if (event === "extension_connected") {
2349
2385
  this.ideType = data?.ideType || "";
2350
2386
  }
@@ -2424,6 +2460,30 @@ var init_extension_provider_instance = __esm({
2424
2460
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
2425
2461
  return title || this.agentName || this.provider.name;
2426
2462
  }
2463
+ resetStreamState() {
2464
+ if (this.currentStatus !== "idle") {
2465
+ this.detectTransition("idle", {
2466
+ title: this.chatTitle,
2467
+ agentName: this.agentName,
2468
+ extensionId: this.extensionId,
2469
+ messages: this.messages
2470
+ });
2471
+ }
2472
+ this.agentStreams = [];
2473
+ this.messages = [];
2474
+ this.activeModal = null;
2475
+ this.currentModel = "";
2476
+ this.currentMode = "";
2477
+ this.controlValues = {};
2478
+ this.currentStatus = "idle";
2479
+ this.chatId = null;
2480
+ this.chatTitle = null;
2481
+ this.agentName = "";
2482
+ this.extensionId = "";
2483
+ this.lastAgentStatus = "idle";
2484
+ this.generatingStartedAt = 0;
2485
+ this.monitor.reset();
2486
+ }
2427
2487
  };
2428
2488
  }
2429
2489
  });
@@ -2479,8 +2539,6 @@ var init_chat_history = __esm({
2479
2539
  lastSeenCounts = /* @__PURE__ */ new Map();
2480
2540
  /** Last seen message hash per agent (deduplication) */
2481
2541
  lastSeenHashes = /* @__PURE__ */ new Map();
2482
- /** Last seen append-only terminal transcript per agent */
2483
- lastSeenTerminal = /* @__PURE__ */ new Map();
2484
2542
  rotated = false;
2485
2543
  /**
2486
2544
  * Append new messages to history
@@ -2538,51 +2596,10 @@ var init_chat_history = __esm({
2538
2596
  } catch {
2539
2597
  }
2540
2598
  }
2541
- appendTerminalHistory(agentType, terminalHistory, sessionTitle, instanceId) {
2542
- const next = String(terminalHistory || "");
2543
- if (!next.trim()) return;
2544
- try {
2545
- const dedupKey = instanceId ? `${agentType}:${instanceId}:terminal` : `${agentType}:terminal`;
2546
- const prev = this.lastSeenTerminal.get(dedupKey) || "";
2547
- if (prev === next) return;
2548
- let delta = "";
2549
- if (!prev) {
2550
- delta = next;
2551
- } else if (next.startsWith(prev)) {
2552
- delta = next.slice(prev.length);
2553
- } else if (prev.includes(next)) {
2554
- this.lastSeenTerminal.set(dedupKey, next);
2555
- return;
2556
- } else {
2557
- delta = `
2558
-
2559
- [terminal snapshot reset ${(/* @__PURE__ */ new Date()).toISOString()} | ${sessionTitle || agentType}]
2560
- ${next}`;
2561
- }
2562
- if (!delta) {
2563
- this.lastSeenTerminal.set(dedupKey, next);
2564
- return;
2565
- }
2566
- const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
2567
- fs3.mkdirSync(dir, { recursive: true });
2568
- const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2569
- const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
2570
- const filePath = path4.join(dir, `${filePrefix}${date5}.terminal.log`);
2571
- fs3.appendFileSync(filePath, delta, "utf-8");
2572
- this.lastSeenTerminal.set(dedupKey, next);
2573
- if (!this.rotated) {
2574
- this.rotated = true;
2575
- this.rotateOldFiles().catch(() => {
2576
- });
2577
- }
2578
- } catch {
2579
- }
2580
- }
2581
2599
  /** Called when agent session is explicitly changed */
2582
2600
  onSessionChange(agentType) {
2583
2601
  this.lastSeenHashes.delete(agentType);
2584
2602
  this.lastSeenCounts.delete(agentType);
2585
- this.lastSeenTerminal.delete(`${agentType}:terminal`);
2586
2603
  }
2587
2604
  /** Delete history files older than 30 days */
2588
2605
  async rotateOldFiles() {
@@ -2722,11 +2739,23 @@ var init_ide_provider_instance = __esm({
2722
2739
  } else if (event === "cdp_disconnected") {
2723
2740
  this.cachedChat = null;
2724
2741
  this.currentStatus = "idle";
2742
+ for (const ext of this.extensions.values()) {
2743
+ ext.onEvent("stream_reset");
2744
+ }
2725
2745
  } else if (event === "stream_update") {
2726
2746
  const extType = data?.extensionType;
2727
2747
  if (extType && this.extensions.has(extType)) {
2728
2748
  this.extensions.get(extType).onEvent("stream_update", data);
2729
2749
  }
2750
+ } else if (event === "stream_reset") {
2751
+ const extType = data?.extensionType;
2752
+ if (extType && this.extensions.has(extType)) {
2753
+ this.extensions.get(extType).onEvent("stream_reset");
2754
+ }
2755
+ } else if (event === "stream_reset_all") {
2756
+ for (const ext of this.extensions.values()) {
2757
+ ext.onEvent("stream_reset");
2758
+ }
2730
2759
  }
2731
2760
  }
2732
2761
  dispose() {
@@ -3411,6 +3440,50 @@ var init_initializer = __esm({
3411
3440
  });
3412
3441
 
3413
3442
  // ../../oss/packages/daemon-core/src/status/normalize.ts
3443
+ function truncateString(value, maxChars) {
3444
+ if (value.length <= maxChars) return value;
3445
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
3446
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
3447
+ }
3448
+ function trimStructuredStrings(value, maxChars) {
3449
+ if (typeof value === "string") return truncateString(value, maxChars);
3450
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
3451
+ if (!value || typeof value !== "object") return value;
3452
+ return Object.fromEntries(
3453
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
3454
+ );
3455
+ }
3456
+ function estimateBytes(value) {
3457
+ try {
3458
+ return JSON.stringify(value).length;
3459
+ } catch {
3460
+ return String(value ?? "").length;
3461
+ }
3462
+ }
3463
+ function trimMessageForStatus(message, stringLimit) {
3464
+ if (!message || typeof message !== "object") return message;
3465
+ return trimStructuredStrings(message, stringLimit);
3466
+ }
3467
+ function trimMessagesForStatus(messages) {
3468
+ if (!Array.isArray(messages) || messages.length === 0) return [];
3469
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
3470
+ const kept = [];
3471
+ let totalBytes = 0;
3472
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
3473
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
3474
+ let size = estimateBytes(normalized);
3475
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
3476
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
3477
+ size = estimateBytes(normalized);
3478
+ }
3479
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
3480
+ continue;
3481
+ }
3482
+ kept.push(normalized);
3483
+ totalBytes += size;
3484
+ }
3485
+ return kept.reverse();
3486
+ }
3414
3487
  function hasApprovalButtons(activeModal) {
3415
3488
  return (activeModal?.buttons?.length ?? 0) > 0;
3416
3489
  }
@@ -3437,10 +3510,18 @@ function normalizeActiveChatData(activeChat) {
3437
3510
  if (!activeChat) return activeChat;
3438
3511
  return {
3439
3512
  ...activeChat,
3440
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
3513
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
3514
+ messages: trimMessagesForStatus(activeChat.messages),
3515
+ activeModal: activeChat.activeModal ? {
3516
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
3517
+ buttons: (activeChat.activeModal.buttons || []).map(
3518
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
3519
+ )
3520
+ } : activeChat.activeModal,
3521
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
3441
3522
  };
3442
3523
  }
3443
- var WORKING_STATUSES;
3524
+ 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;
3444
3525
  var init_normalize = __esm({
3445
3526
  "../../oss/packages/daemon-core/src/status/normalize.ts"() {
3446
3527
  "use strict";
@@ -3452,6 +3533,13 @@ var init_normalize = __esm({
3452
3533
  "thinking",
3453
3534
  "active"
3454
3535
  ]);
3536
+ STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
3537
+ STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
3538
+ STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
3539
+ STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
3540
+ STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
3541
+ STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
3542
+ STATUS_MODAL_BUTTON_LIMIT = 120;
3455
3543
  }
3456
3544
  });
3457
3545
 
@@ -3601,11 +3689,10 @@ function buildCliSession(state) {
3601
3689
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
3602
3690
  runtimeWriteOwner: state.runtime?.writeOwner || null,
3603
3691
  runtimeAttachedClients: state.runtime?.attachedClients || [],
3604
- launchMode: state.launchMode,
3605
3692
  mode: state.mode,
3606
3693
  resume: state.resume,
3607
3694
  activeChat,
3608
- capabilities: PTY_SESSION_CAPABILITIES,
3695
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
3609
3696
  controlValues: state.controlValues,
3610
3697
  providerControls: buildFallbackControls(
3611
3698
  state.providerControls
@@ -3675,7 +3762,7 @@ function buildSessionEntries(allStates, cdpManagers) {
3675
3762
  }
3676
3763
  return sessions;
3677
3764
  }
3678
- var IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES;
3765
+ var IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, CLI_CHAT_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES;
3679
3766
  var init_builders = __esm({
3680
3767
  "../../oss/packages/daemon-core/src/status/builders.ts"() {
3681
3768
  "use strict";
@@ -3708,6 +3795,11 @@ var init_builders = __esm({
3708
3795
  "terminal_io",
3709
3796
  "resize_terminal"
3710
3797
  ];
3798
+ CLI_CHAT_SESSION_CAPABILITIES = [
3799
+ "read_chat",
3800
+ "send_message",
3801
+ "resolve_action"
3802
+ ];
3711
3803
  ACP_SESSION_CAPABILITIES = [
3712
3804
  "read_chat",
3713
3805
  "send_message",
@@ -4832,6 +4924,13 @@ var init_cdp_commands = __esm({
4832
4924
  });
4833
4925
 
4834
4926
  // ../../oss/packages/daemon-core/src/commands/stream-commands.ts
4927
+ function getCliPresentationMode(h, targetSessionId) {
4928
+ if (!targetSessionId) return null;
4929
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
4930
+ if (instance?.category !== "cli") return null;
4931
+ const mode = instance.getPresentationMode?.();
4932
+ return mode === "chat" || mode === "terminal" ? mode : null;
4933
+ }
4835
4934
  async function handleFocusSession(h, args) {
4836
4935
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
4837
4936
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -4842,6 +4941,9 @@ async function handleFocusSession(h, args) {
4842
4941
  function handlePtyInput(h, args) {
4843
4942
  const { cliType, data, targetSessionId } = args || {};
4844
4943
  if (!data) return { success: false, error: "data required" };
4944
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
4945
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
4946
+ }
4845
4947
  const adapter = h.getCliAdapter(targetSessionId || cliType);
4846
4948
  if (!adapter || typeof adapter.writeRaw !== "function") {
4847
4949
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -4852,6 +4954,9 @@ function handlePtyInput(h, args) {
4852
4954
  function handlePtyResize(h, args) {
4853
4955
  const { cliType, cols, rows, force, targetSessionId } = args || {};
4854
4956
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
4957
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
4958
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
4959
+ }
4855
4960
  const adapter = h.getCliAdapter(targetSessionId || cliType);
4856
4961
  if (!adapter || typeof adapter.resize !== "function") {
4857
4962
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -8938,6 +9043,9 @@ var init_ghostty_vt_backend = __esm({
8938
9043
  getText() {
8939
9044
  return this.terminal.formatPlainText({ trim: true }) || "";
8940
9045
  }
9046
+ getCursorPosition() {
9047
+ return this.terminal.getCursorPosition();
9048
+ }
8941
9049
  dispose() {
8942
9050
  this.terminal.dispose();
8943
9051
  }
@@ -18090,6 +18198,13 @@ var init_xterm_backend = __esm({
18090
18198
  while (last > first && !lines[last - 1]?.trim()) last--;
18091
18199
  return lines.slice(first, last).join("\n");
18092
18200
  }
18201
+ getCursorPosition() {
18202
+ const buffer = this.terminal.buffer.active;
18203
+ return {
18204
+ col: Math.max(0, buffer.cursorX || 0),
18205
+ row: Math.max(0, buffer.cursorY || 0)
18206
+ };
18207
+ }
18093
18208
  dispose() {
18094
18209
  this.terminal.dispose();
18095
18210
  }
@@ -18176,6 +18291,9 @@ var init_terminal_screen = __esm({
18176
18291
  getText() {
18177
18292
  return this.terminal.getText();
18178
18293
  }
18294
+ getCursorPosition() {
18295
+ return this.terminal.getCursorPosition();
18296
+ }
18179
18297
  dispose() {
18180
18298
  this.terminal.dispose();
18181
18299
  }
@@ -18412,6 +18530,7 @@ var init_router = __esm({
18412
18530
  // ─── CLI / ACP commands ───
18413
18531
  case "launch_cli":
18414
18532
  case "stop_cli":
18533
+ case "set_cli_view_mode":
18415
18534
  case "agent_command": {
18416
18535
  return this.deps.cliManager.handleCliCommand(cmd, args);
18417
18536
  }
@@ -18764,6 +18883,20 @@ var init_reporter = __esm({
18764
18883
  ts() {
18765
18884
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
18766
18885
  }
18886
+ summarizeLargePayloadSessions(payload) {
18887
+ const sessions = Array.isArray(payload.sessions) ? payload.sessions : [];
18888
+ return sessions.map((session) => ({
18889
+ id: String(session?.id || ""),
18890
+ providerType: String(session?.providerType || ""),
18891
+ bytes: (() => {
18892
+ try {
18893
+ return JSON.stringify(session).length;
18894
+ } catch {
18895
+ return 0;
18896
+ }
18897
+ })()
18898
+ })).sort((a, b2) => b2.bytes - a.bytes).slice(0, 3).map((session) => `${session.providerType || "unknown"}:${session.id}=${session.bytes}b`).join(", ");
18899
+ }
18767
18900
  async sendUnifiedStatusReport(opts) {
18768
18901
  const { serverConn, p2p } = this.deps;
18769
18902
  if (!serverConn?.isConnected()) return;
@@ -18816,9 +18949,16 @@ var init_reporter = __esm({
18816
18949
  screenshotUsage: this.deps.getScreenshotUsage?.() || null,
18817
18950
  connectedExtensions: []
18818
18951
  };
18952
+ const payloadBytes = JSON.stringify(payload).length;
18819
18953
  const p2pSent = this.sendP2PPayload(payload);
18820
18954
  if (p2pSent) {
18821
- LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
18955
+ LOG.debug("P2P", `sent (${payloadBytes} bytes)`);
18956
+ if (payloadBytes > 256 * 1024) {
18957
+ LOG.warn(
18958
+ "P2P",
18959
+ `large status payload (${payloadBytes} bytes) top sessions: ${this.summarizeLargePayloadSessions(payload) || "n/a"}`
18960
+ );
18961
+ }
18822
18962
  }
18823
18963
  if (opts?.p2pOnly) return;
18824
18964
  const wsPayload = {
@@ -18848,7 +18988,9 @@ var init_reporter = __esm({
18848
18988
  acpModes: session.acpModes
18849
18989
  })),
18850
18990
  p2p: payload.p2p,
18851
- timestamp: now
18991
+ timestamp: now,
18992
+ detectedIdes: payload.detectedIdes,
18993
+ availableProviders: payload.availableProviders
18852
18994
  };
18853
18995
  serverConn.sendMessage("status_report", wsPayload);
18854
18996
  LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
@@ -18896,6 +19038,7 @@ var init_pty_transport = __esm({
18896
19038
  this.handle = handle;
18897
19039
  }
18898
19040
  ready = Promise.resolve();
19041
+ terminalQueriesHandled = false;
18899
19042
  get pid() {
18900
19043
  return this.handle.pid;
18901
19044
  }
@@ -18949,6 +19092,32 @@ function stripTerminalNoise(str) {
18949
19092
  function sanitizeTerminalText(str) {
18950
19093
  return stripTerminalNoise(stripAnsi(str));
18951
19094
  }
19095
+ function buildCliSpawnEnv(baseEnv, overrides) {
19096
+ const env = {};
19097
+ const source = { ...baseEnv, ...overrides || {} };
19098
+ for (const [key, value] of Object.entries(source)) {
19099
+ if (typeof value !== "string") continue;
19100
+ env[key] = value;
19101
+ }
19102
+ for (const key of Object.keys(env)) {
19103
+ 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_")) {
19104
+ delete env[key];
19105
+ }
19106
+ }
19107
+ return env;
19108
+ }
19109
+ function computeTerminalQueryTail(buffer) {
19110
+ const prefixes = ["\x1B[6n", "\x1B[?6n"];
19111
+ const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
19112
+ const start = Math.max(0, buffer.length - maxLength);
19113
+ for (let i = start; i < buffer.length; i++) {
19114
+ const suffix = buffer.slice(i);
19115
+ if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
19116
+ return suffix;
19117
+ }
19118
+ }
19119
+ return "";
19120
+ }
18952
19121
  function findBinary(name) {
18953
19122
  const isWin = os13.platform() === "win32";
18954
19123
  try {
@@ -19035,36 +19204,6 @@ function promptLikelyVisible(screenText, promptSnippet) {
19035
19204
  ).length;
19036
19205
  return matched >= required2;
19037
19206
  }
19038
- function splitHistoryLines(text) {
19039
- return String(text || "").split("\n").map((line) => line.replace(/\s+$/, ""));
19040
- }
19041
- function normalizeHistoryLine(line) {
19042
- return String(line || "").replace(/\s+/g, " ").trim();
19043
- }
19044
- function mergeTerminalHistory(existing, snapshot) {
19045
- const next = String(snapshot || "").trim();
19046
- if (!next) return existing;
19047
- const prev = String(existing || "").trim();
19048
- if (!prev) return next;
19049
- if (prev === next || prev.endsWith(next)) return prev;
19050
- const prevLines = splitHistoryLines(prev);
19051
- const nextLines = splitHistoryLines(next);
19052
- const prevNorm = prevLines.map(normalizeHistoryLine);
19053
- const nextNorm = nextLines.map(normalizeHistoryLine);
19054
- const maxOverlap = Math.min(prevLines.length, nextLines.length);
19055
- for (let overlap = maxOverlap; overlap >= 1; overlap -= 1) {
19056
- const prevTail = prevNorm.slice(prevNorm.length - overlap);
19057
- const nextHead = nextNorm.slice(0, overlap);
19058
- if (prevTail.every((line, index) => line === nextHead[index])) {
19059
- return [...prevLines, ...nextLines.slice(overlap)].join("\n").trim();
19060
- }
19061
- }
19062
- const compactPrev = prevNorm.join("\n");
19063
- const compactNext = nextNorm.join("\n");
19064
- if (compactPrev.includes(compactNext)) return prev;
19065
- return `${prev}
19066
- ${next}`.trim();
19067
- }
19068
19207
  function parsePatternEntry(x) {
19069
19208
  if (x instanceof RegExp) return x;
19070
19209
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -19179,6 +19318,7 @@ var init_provider_cli_adapter = __esm({
19179
19318
  pendingOutputParseTimer = null;
19180
19319
  ptyOutputBuffer = "";
19181
19320
  ptyOutputFlushTimer = null;
19321
+ pendingTerminalQueryTail = "";
19182
19322
  // Server log forwarding
19183
19323
  serverConn = null;
19184
19324
  logBuffer = [];
@@ -19210,9 +19350,7 @@ var init_provider_cli_adapter = __esm({
19210
19350
  /** Full accumulated raw PTY output (with ANSI) */
19211
19351
  accumulatedRawBuffer = "";
19212
19352
  /** Current visible terminal screen snapshot */
19213
- terminalScreen = new TerminalScreen(40, 120);
19214
- /** Rolling append-only terminal transcript built from screen snapshots */
19215
- terminalHistory = "";
19353
+ terminalScreen = new TerminalScreen(30, 100);
19216
19354
  /** Max accumulated buffer size (last 50KB) */
19217
19355
  static MAX_ACCUMULATED_BUFFER = 5e4;
19218
19356
  currentTurnScope = null;
@@ -19220,6 +19358,13 @@ var init_provider_cli_adapter = __esm({
19220
19358
  this.messages = [...this.committedMessages];
19221
19359
  this.structuredMessages = [...this.committedMessages];
19222
19360
  }
19361
+ normalizeParsedMessages(parsedMessages) {
19362
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
19363
+ role: message.role,
19364
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
19365
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
19366
+ }));
19367
+ }
19223
19368
  sliceFromOffset(text, start) {
19224
19369
  if (!text) return "";
19225
19370
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -19227,15 +19372,13 @@ var init_provider_cli_adapter = __esm({
19227
19372
  return text.slice(start);
19228
19373
  }
19229
19374
  buildParseInput(baseMessages, partialResponse, scope) {
19230
- const buffer = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
19375
+ const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
19231
19376
  const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
19232
- const terminalHistory = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.terminalHistory : this.terminalHistory;
19233
19377
  return {
19234
19378
  buffer,
19235
19379
  rawBuffer,
19236
19380
  recentBuffer: buffer.slice(-1e3) || this.recentOutputBuffer,
19237
19381
  screenText: this.terminalScreen.getText(),
19238
- terminalHistory,
19239
19382
  messages: [...baseMessages],
19240
19383
  partialResponse
19241
19384
  };
@@ -19313,13 +19456,10 @@ var init_provider_cli_adapter = __esm({
19313
19456
  shellArgs = allArgs;
19314
19457
  }
19315
19458
  const ptyOpts = {
19316
- cols: 120,
19317
- rows: 40,
19459
+ cols: 100,
19460
+ rows: 30,
19318
19461
  cwd: this.workingDir,
19319
- env: {
19320
- ...process.env,
19321
- ...spawnConfig.env
19322
- }
19462
+ env: buildCliSpawnEnv(process.env, spawnConfig.env)
19323
19463
  };
19324
19464
  try {
19325
19465
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
@@ -19337,8 +19477,8 @@ var init_provider_cli_adapter = __esm({
19337
19477
  }
19338
19478
  this.ptyProcess.onData((data) => {
19339
19479
  if (Date.now() < this.resizeSuppressUntil) return;
19340
- if (data.includes("\x1B[6n") || data.includes("\x1B[?6n")) {
19341
- this.ptyProcess?.write("\x1B[1;1R");
19480
+ if (!this.ptyProcess?.terminalQueriesHandled) {
19481
+ this.respondToTerminalQueries(data);
19342
19482
  }
19343
19483
  this.pendingOutputParseBuffer += data;
19344
19484
  if (!this.pendingOutputParseTimer) {
@@ -19373,8 +19513,8 @@ var init_provider_cli_adapter = __esm({
19373
19513
  this.spawnAt = Date.now();
19374
19514
  this.startupParseGate = true;
19375
19515
  this.startupBuffer = "";
19376
- this.terminalScreen.reset(40, 120);
19377
- this.terminalHistory = "";
19516
+ this.terminalScreen.reset(30, 100);
19517
+ this.pendingTerminalQueryTail = "";
19378
19518
  this.currentTurnScope = null;
19379
19519
  this.ready = false;
19380
19520
  await this.ptyProcess.ready;
@@ -19384,7 +19524,6 @@ var init_provider_cli_adapter = __esm({
19384
19524
  // ─── Output Handling ────────────────────────────
19385
19525
  handleOutput(rawData) {
19386
19526
  this.terminalScreen.write(rawData);
19387
- this.terminalHistory = mergeTerminalHistory(this.terminalHistory, this.terminalScreen.getText());
19388
19527
  const cleanData = sanitizeTerminalText(rawData);
19389
19528
  if (this.isWaitingForResponse && cleanData) {
19390
19529
  this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
@@ -19616,6 +19755,15 @@ var init_provider_cli_adapter = __esm({
19616
19755
  this.onStatusChange?.();
19617
19756
  }
19618
19757
  commitCurrentTranscript() {
19758
+ const parsed = this.parseCurrentTranscript(
19759
+ this.committedMessages,
19760
+ this.responseBuffer,
19761
+ this.currentTurnScope
19762
+ );
19763
+ if (parsed && Array.isArray(parsed.messages)) {
19764
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
19765
+ this.syncMessageViews();
19766
+ }
19619
19767
  }
19620
19768
  // ─── Script Execution ──────────────────────────
19621
19769
  runDetectStatus(text) {
@@ -19651,8 +19799,7 @@ var init_provider_cli_adapter = __esm({
19651
19799
  status: this.currentStatus,
19652
19800
  messages: [...this.committedMessages],
19653
19801
  workingDir: this.workingDir,
19654
- activeModal: this.activeModal,
19655
- terminalHistory: this.terminalHistory
19802
+ activeModal: this.activeModal
19656
19803
  };
19657
19804
  }
19658
19805
  /**
@@ -19660,12 +19807,25 @@ var init_provider_cli_adapter = __esm({
19660
19807
  * Called by command handler / dashboard for rich content rendering.
19661
19808
  */
19662
19809
  getScriptParsedStatus() {
19810
+ const parsed = this.parseCurrentTranscript(
19811
+ this.committedMessages,
19812
+ this.responseBuffer,
19813
+ this.currentTurnScope
19814
+ );
19815
+ if (parsed && Array.isArray(parsed.messages)) {
19816
+ return {
19817
+ id: parsed.id || "cli_session",
19818
+ status: parsed.status || this.currentStatus,
19819
+ title: parsed.title || this.cliName,
19820
+ messages: parsed.messages,
19821
+ activeModal: parsed.activeModal ?? this.activeModal
19822
+ };
19823
+ }
19663
19824
  const messages = [...this.committedMessages];
19664
19825
  return {
19665
19826
  id: "cli_session",
19666
19827
  status: this.currentStatus,
19667
19828
  title: this.cliName,
19668
- terminalHistory: this.terminalHistory,
19669
19829
  messages: messages.slice(-50).map((message, index) => ({
19670
19830
  id: `msg_${index}`,
19671
19831
  role: message.role,
@@ -19733,10 +19893,9 @@ ${data.message || ""}`.trim();
19733
19893
  prompt: text,
19734
19894
  startedAt: Date.now(),
19735
19895
  bufferStart: this.accumulatedBuffer.length,
19736
- rawBufferStart: this.accumulatedRawBuffer.length,
19737
- terminalHistoryStart: this.terminalHistory.length
19896
+ rawBufferStart: this.accumulatedRawBuffer.length
19738
19897
  };
19739
- 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)}`);
19898
+ LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
19740
19899
  this.submitRetryUsed = false;
19741
19900
  this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
19742
19901
  const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
@@ -19921,6 +20080,7 @@ ${data.message || ""}`.trim();
19921
20080
  this.pendingOutputParseTimer = null;
19922
20081
  }
19923
20082
  this.pendingOutputParseBuffer = "";
20083
+ this.pendingTerminalQueryTail = "";
19924
20084
  if (this.ptyOutputFlushTimer) {
19925
20085
  clearTimeout(this.ptyOutputFlushTimer);
19926
20086
  this.ptyOutputFlushTimer = null;
@@ -19960,6 +20120,7 @@ ${data.message || ""}`.trim();
19960
20120
  this.pendingOutputParseTimer = null;
19961
20121
  }
19962
20122
  this.pendingOutputParseBuffer = "";
20123
+ this.pendingTerminalQueryTail = "";
19963
20124
  if (this.ptyOutputFlushTimer) {
19964
20125
  clearTimeout(this.ptyOutputFlushTimer);
19965
20126
  this.ptyOutputFlushTimer = null;
@@ -19986,7 +20147,6 @@ ${data.message || ""}`.trim();
19986
20147
  this.syncMessageViews();
19987
20148
  this.accumulatedBuffer = "";
19988
20149
  this.accumulatedRawBuffer = "";
19989
- this.terminalHistory = "";
19990
20150
  this.currentTurnScope = null;
19991
20151
  this.submitRetryUsed = false;
19992
20152
  this.submitRetryPromptSnippet = "";
@@ -19995,6 +20155,7 @@ ${data.message || ""}`.trim();
19995
20155
  this.pendingOutputParseTimer = null;
19996
20156
  }
19997
20157
  this.pendingOutputParseBuffer = "";
20158
+ this.pendingTerminalQueryTail = "";
19998
20159
  if (this.ptyOutputFlushTimer) {
19999
20160
  clearTimeout(this.ptyOutputFlushTimer);
20000
20161
  this.ptyOutputFlushTimer = null;
@@ -20056,7 +20217,6 @@ ${data.message || ""}`.trim();
20056
20217
  structuredMessages: this.structuredMessages.slice(-20),
20057
20218
  messageCount: this.committedMessages.length,
20058
20219
  screenText: sanitizeTerminalText(this.terminalScreen.getText()).slice(-4e3),
20059
- terminalHistory: this.terminalHistory.slice(-8e3),
20060
20220
  currentTurnScope: this.currentTurnScope,
20061
20221
  startupBuffer: this.startupBuffer.slice(-4e3),
20062
20222
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
@@ -20084,6 +20244,20 @@ ${data.message || ""}`.trim();
20084
20244
  ptyAlive: !!this.ptyProcess
20085
20245
  };
20086
20246
  }
20247
+ respondToTerminalQueries(data) {
20248
+ if (!this.ptyProcess || !data) return;
20249
+ const combined = this.pendingTerminalQueryTail + data;
20250
+ const regex = /\x1b\[(\?)?6n/g;
20251
+ let match;
20252
+ while ((match = regex.exec(combined)) !== null) {
20253
+ const cursor = this.terminalScreen.getCursorPosition();
20254
+ const row = Math.max(1, (cursor.row | 0) + 1);
20255
+ const col = Math.max(1, (cursor.col | 0) + 1);
20256
+ const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
20257
+ this.ptyProcess.write(response);
20258
+ }
20259
+ this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
20260
+ }
20087
20261
  };
20088
20262
  }
20089
20263
  });
@@ -20099,14 +20273,13 @@ var init_cli_provider_instance = __esm({
20099
20273
  init_chat_history();
20100
20274
  init_logger();
20101
20275
  CliProviderInstance = class {
20102
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
20276
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
20103
20277
  this.provider = provider;
20104
20278
  this.workingDir = workingDir;
20105
20279
  this.cliArgs = cliArgs;
20106
20280
  this.type = provider.type;
20107
20281
  this.instanceId = instanceId || crypto3.randomUUID();
20108
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
20109
- this.resolvedOutputFormat = this.resolveOutputFormat();
20282
+ this.presentationMode = "chat";
20110
20283
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
20111
20284
  this.monitor = new StatusMonitor();
20112
20285
  this.historyWriter = new ChatHistoryWriter();
@@ -20125,26 +20298,7 @@ var init_cli_provider_instance = __esm({
20125
20298
  lastApprovalEventAt = 0;
20126
20299
  historyWriter;
20127
20300
  instanceId;
20128
- launchMode;
20129
- resolvedOutputFormat;
20130
- /**
20131
- * Determine output rendering format from:
20132
- * 1. launchMode.outputFormat (explicit override)
20133
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
20134
- * 3. Default: 'terminal'
20135
- */
20136
- resolveOutputFormat() {
20137
- if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
20138
- if (this.provider.launchOptions?.length) {
20139
- for (const opt of this.provider.launchOptions) {
20140
- if (!opt.outputFormatMap) continue;
20141
- for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
20142
- if (this.cliArgs.includes(val)) return fmt;
20143
- }
20144
- }
20145
- }
20146
- return "terminal";
20147
- }
20301
+ presentationMode;
20148
20302
  // ─── Lifecycle ─────────────────────────────────
20149
20303
  async init(context) {
20150
20304
  this.context = context;
@@ -20169,30 +20323,21 @@ var init_cli_provider_instance = __esm({
20169
20323
  }
20170
20324
  getState() {
20171
20325
  const adapterStatus = this.adapter.getStatus();
20326
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
20172
20327
  const runtime = this.adapter.getRuntimeMetadata();
20173
20328
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
20174
- if (adapterStatus.terminalHistory?.trim()) {
20175
- this.historyWriter.appendTerminalHistory(
20176
- this.type,
20177
- adapterStatus.terminalHistory,
20178
- `${this.provider.name} \xB7 ${dirName}`,
20179
- this.instanceId
20180
- );
20181
- }
20182
20329
  return {
20183
20330
  type: this.type,
20184
20331
  name: this.provider.name,
20185
20332
  category: "cli",
20186
20333
  status: adapterStatus.status,
20187
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
20188
- launchMode: this.launchMode?.id,
20334
+ mode: this.presentationMode,
20189
20335
  activeChat: {
20190
20336
  id: `${this.type}_${this.workingDir}`,
20191
- title: `${this.provider.name} \xB7 ${dirName}`,
20192
- status: adapterStatus.status,
20193
- messages: [],
20194
- activeModal: adapterStatus.activeModal,
20195
- terminalHistory: adapterStatus.terminalHistory,
20337
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
20338
+ status: parsedStatus?.status || adapterStatus.status,
20339
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
20340
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
20196
20341
  inputContent: ""
20197
20342
  },
20198
20343
  workspace: this.workingDir,
@@ -20214,6 +20359,13 @@ var init_cli_provider_instance = __esm({
20214
20359
  providerControls: this.provider.controls
20215
20360
  };
20216
20361
  }
20362
+ setPresentationMode(mode) {
20363
+ if (this.presentationMode === mode) return;
20364
+ this.presentationMode = mode;
20365
+ }
20366
+ getPresentationMode() {
20367
+ return this.presentationMode;
20368
+ }
20217
20369
  onEvent(event, data) {
20218
20370
  if (event === "send_message" && data?.text) {
20219
20371
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -20474,7 +20626,7 @@ __export(util_exports, {
20474
20626
  getSizableOrigin: () => getSizableOrigin,
20475
20627
  hexToUint8Array: () => hexToUint8Array,
20476
20628
  isObject: () => isObject,
20477
- isPlainObject: () => isPlainObject,
20629
+ isPlainObject: () => isPlainObject2,
20478
20630
  issue: () => issue,
20479
20631
  joinValues: () => joinValues,
20480
20632
  jsonStringifyReplacer: () => jsonStringifyReplacer,
@@ -20643,7 +20795,7 @@ function slugify(input) {
20643
20795
  function isObject(data) {
20644
20796
  return typeof data === "object" && data !== null && !Array.isArray(data);
20645
20797
  }
20646
- function isPlainObject(o) {
20798
+ function isPlainObject2(o) {
20647
20799
  if (isObject(o) === false)
20648
20800
  return false;
20649
20801
  const ctor = o.constructor;
@@ -20660,7 +20812,7 @@ function isPlainObject(o) {
20660
20812
  return true;
20661
20813
  }
20662
20814
  function shallowClone(o) {
20663
- if (isPlainObject(o))
20815
+ if (isPlainObject2(o))
20664
20816
  return { ...o };
20665
20817
  if (Array.isArray(o))
20666
20818
  return [...o];
@@ -20796,7 +20948,7 @@ function omit(schema, mask) {
20796
20948
  return clone(schema, def);
20797
20949
  }
20798
20950
  function extend(schema, shape) {
20799
- if (!isPlainObject(shape)) {
20951
+ if (!isPlainObject2(shape)) {
20800
20952
  throw new Error("Invalid input to extend: expected a plain object");
20801
20953
  }
20802
20954
  const checks = schema._zod.def.checks;
@@ -20819,7 +20971,7 @@ function extend(schema, shape) {
20819
20971
  return clone(schema, def);
20820
20972
  }
20821
20973
  function safeExtend(schema, shape) {
20822
- if (!isPlainObject(shape)) {
20974
+ if (!isPlainObject2(shape)) {
20823
20975
  throw new Error("Invalid input to safeExtend: expected a plain object");
20824
20976
  }
20825
20977
  const def = mergeDefs(schema._zod.def, {
@@ -22302,7 +22454,7 @@ function mergeValues(a, b2) {
22302
22454
  if (a instanceof Date && b2 instanceof Date && +a === +b2) {
22303
22455
  return { valid: true, data: a };
22304
22456
  }
22305
- if (isPlainObject(a) && isPlainObject(b2)) {
22457
+ if (isPlainObject2(a) && isPlainObject2(b2)) {
22306
22458
  const bKeys = Object.keys(b2);
22307
22459
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
22308
22460
  const newObj = { ...a, ...b2 };
@@ -23497,7 +23649,7 @@ var init_schemas = __esm({
23497
23649
  $ZodType.init(inst, def);
23498
23650
  inst._zod.parse = (payload, ctx) => {
23499
23651
  const input = payload.value;
23500
- if (!isPlainObject(input)) {
23652
+ if (!isPlainObject2(input)) {
23501
23653
  payload.issues.push({
23502
23654
  expected: "record",
23503
23655
  code: "invalid_type",
@@ -37601,6 +37753,15 @@ var init_cli_manager = __esm({
37601
37753
  const hash2 = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
37602
37754
  return `${cliType}_${hash2}`;
37603
37755
  }
37756
+ getSessionPresentationMode(sessionId) {
37757
+ if (!sessionId) return null;
37758
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
37759
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
37760
+ return mode === "chat" || mode === "terminal" ? mode : null;
37761
+ }
37762
+ isTerminalSession(sessionId) {
37763
+ return this.getSessionPresentationMode(sessionId) === "terminal";
37764
+ }
37604
37765
  persistRecentActivity(entry) {
37605
37766
  try {
37606
37767
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -37656,12 +37817,12 @@ var init_cli_manager = __esm({
37656
37817
  }
37657
37818
  }, 3e3);
37658
37819
  }
37659
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
37820
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
37660
37821
  const instanceManager = this.deps.getInstanceManager();
37661
37822
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
37662
37823
  if (!instanceManager) throw new Error("InstanceManager not available");
37663
37824
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
37664
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
37825
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
37665
37826
  try {
37666
37827
  await instanceManager.addInstance(key, cliInstance, {
37667
37828
  serverConn: this.deps.getServerConn(),
@@ -37687,7 +37848,7 @@ var init_cli_manager = __esm({
37687
37848
  this.startCliExitMonitor(key, cliType);
37688
37849
  }
37689
37850
  // ─── Session start/management ──────────────────────────────
37690
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
37851
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
37691
37852
  const trimmed = (workingDir || "").trim();
37692
37853
  if (!trimmed) throw new Error("working directory required");
37693
37854
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os14.homedir()) : path10.resolve(trimmed);
@@ -37779,29 +37940,7 @@ ${installInfo}`
37779
37940
  if (provider) {
37780
37941
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
37781
37942
  }
37782
- let resolvedCliArgs = cliArgs;
37783
- let resolvedLaunchMode = launchMode;
37784
- const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
37785
- if (activeMode) {
37786
- resolvedLaunchMode = activeMode.id;
37787
- }
37788
- if (provider?.launchArgBuilder) {
37789
- const defaults = {};
37790
- for (const opt of provider.launchOptions || []) {
37791
- if (opt.default !== void 0) defaults[opt.id] = opt.default;
37792
- }
37793
- const modeOptions = activeMode?.options || {};
37794
- const userOptions = launchOptionValues || {};
37795
- const merged = { ...defaults, ...modeOptions, ...userOptions };
37796
- const extraArgs = provider.launchArgBuilder(merged);
37797
- if (extraArgs.length) {
37798
- resolvedCliArgs = [...cliArgs || [], ...extraArgs];
37799
- console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
37800
- }
37801
- } else if (activeMode?.extraArgs?.length) {
37802
- resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
37803
- console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
37804
- }
37943
+ const resolvedCliArgs = cliArgs;
37805
37944
  const instanceManager = this.deps.getInstanceManager();
37806
37945
  if (provider && instanceManager) {
37807
37946
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -37813,8 +37952,7 @@ ${installInfo}`
37813
37952
  resolvedCliArgs,
37814
37953
  resolvedProvider,
37815
37954
  {},
37816
- false,
37817
- resolvedLaunchMode
37955
+ false
37818
37956
  );
37819
37957
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
37820
37958
  } else {
@@ -37926,8 +38064,7 @@ ${installInfo}`
37926
38064
  record2.cliArgs,
37927
38065
  resolvedProvider,
37928
38066
  {},
37929
- true,
37930
- record2.launchMode
38067
+ true
37931
38068
  );
37932
38069
  restored += 1;
37933
38070
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record2.runtimeKey || record2.runtimeId} (${record2.displayName || record2.workspace})`);
@@ -37969,6 +38106,14 @@ ${installInfo}`
37969
38106
  }
37970
38107
  return null;
37971
38108
  }
38109
+ findAdapterBySessionId(instanceKey) {
38110
+ if (!instanceKey) return null;
38111
+ let ik = instanceKey;
38112
+ const colonIdx = ik.lastIndexOf(":");
38113
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
38114
+ const adapter = this.adapters.get(ik);
38115
+ return adapter ? { adapter, key: ik } : null;
38116
+ }
37972
38117
  // ─── CLI command handling ────────────────────────────
37973
38118
  async handleCliCommand(cmd, args) {
37974
38119
  switch (cmd) {
@@ -37997,7 +38142,7 @@ ${installInfo}`
37997
38142
  const dir = resolved.path;
37998
38143
  const launchSource = resolved.source;
37999
38144
  if (!cliType) throw new Error("cliType required");
38000
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
38145
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
38001
38146
  let newKey = null;
38002
38147
  for (const [k, adapter] of this.adapters) {
38003
38148
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -38019,6 +38164,23 @@ ${installInfo}`
38019
38164
  }
38020
38165
  return { success: true, cliType, dir, stopped: true, mode };
38021
38166
  }
38167
+ case "set_cli_view_mode": {
38168
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
38169
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
38170
+ const cliType = args?.cliType || args?.agentType || "";
38171
+ const dir = args?.dir || "";
38172
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
38173
+ if (!found) {
38174
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
38175
+ }
38176
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
38177
+ if (!(instance instanceof CliProviderInstance)) {
38178
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
38179
+ }
38180
+ instance.setPresentationMode(mode);
38181
+ this.deps.onStatusChange();
38182
+ return { success: true, id: found.key, mode };
38183
+ }
38022
38184
  case "restart_session": {
38023
38185
  const cliType = args?.cliType || args?.agentType || args?.ideType;
38024
38186
  const cfg = loadConfig();
@@ -38670,7 +38832,12 @@ var init_poller = __esm({
38670
38832
  } catch {
38671
38833
  }
38672
38834
  }
38673
- if (!resolvedActiveSessionId || !parentSessionId) continue;
38835
+ if (!resolvedActiveSessionId || !parentSessionId) {
38836
+ if (parentSessionId) {
38837
+ this.deps.onStreamsUpdated?.(ideType, []);
38838
+ }
38839
+ continue;
38840
+ }
38674
38841
  try {
38675
38842
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
38676
38843
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -38698,7 +38865,11 @@ var init_agent_stream = __esm({
38698
38865
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
38699
38866
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
38700
38867
  if (!ideInstance?.onEvent) return;
38868
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
38701
38869
  for (const stream of streams) {
38870
+ if (typeof stream.agentType === "string" && stream.agentType) {
38871
+ seenExtensionTypes.add(stream.agentType);
38872
+ }
38702
38873
  ideInstance.onEvent("stream_update", {
38703
38874
  extensionType: stream.agentType,
38704
38875
  streams: [stream],
@@ -38715,6 +38886,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
38715
38886
  inputContent: stream.inputContent || ""
38716
38887
  });
38717
38888
  }
38889
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
38890
+ if (streams.length === 0) {
38891
+ ideInstance.onEvent("stream_reset_all");
38892
+ return;
38893
+ }
38894
+ for (const extensionType of extensionTypes) {
38895
+ if (!seenExtensionTypes.has(extensionType)) {
38896
+ ideInstance.onEvent("stream_reset", { extensionType });
38897
+ }
38898
+ }
38718
38899
  }
38719
38900
  var init_forward = __esm({
38720
38901
  "../../oss/packages/daemon-core/src/agent-stream/forward.ts"() {
@@ -43297,6 +43478,7 @@ var init_session_host_transport = __esm({
43297
43478
  this.ready = this.boot();
43298
43479
  }
43299
43480
  ready;
43481
+ terminalQueriesHandled = true;
43300
43482
  client;
43301
43483
  dataCallbacks = /* @__PURE__ */ new Set();
43302
43484
  exitCallbacks = /* @__PURE__ */ new Set();
@@ -44458,13 +44640,8 @@ var init_server_connection = __esm({
44458
44640
  LOG.info("Server", `[ServerConn] Run 'adhdev setup' to re-authenticate.`);
44459
44641
  this.setState("disconnected");
44460
44642
  try {
44461
- const path18 = require("path");
44462
- const fs16 = require("fs");
44463
- const configPath = path18.join(process.env.HOME || process.env.USERPROFILE || "", ".adhdev", "config.json");
44464
- if (fs16.existsSync(configPath)) {
44465
- fs16.unlinkSync(configPath);
44466
- LOG.info("Server", `[ServerConn] Config file removed. Re-run 'adhdev setup'.`);
44467
- }
44643
+ resetConfig();
44644
+ LOG.info("Server", `[ServerConn] Config reset. Re-run 'adhdev setup'.`);
44468
44645
  } catch {
44469
44646
  }
44470
44647
  return;
@@ -44733,10 +44910,9 @@ ${e?.stack || ""}`);
44733
44910
  async fetchTurnCredentials() {
44734
44911
  try {
44735
44912
  const serverUrl = process.env.ADHDEV_SERVER_URL || "https://api.adhf.dev";
44736
- const configPath = path15.join(os18.homedir(), ".adhdev", "config.json");
44737
44913
  let token = "";
44738
44914
  try {
44739
- const config2 = JSON.parse(fs13.readFileSync(configPath, "utf-8"));
44915
+ const config2 = loadConfig();
44740
44916
  token = config2.machineSecret || "";
44741
44917
  } catch {
44742
44918
  }
@@ -45035,8 +45211,9 @@ ${e?.stack || ""}`);
45035
45211
  log(`pty_input: REJECTED \u2014 permission=${permission} peer=${peerId}`);
45036
45212
  return;
45037
45213
  }
45038
- if (this.ptyInputHandler && parsed.data) {
45039
- this.ptyInputHandler(parsed.cliType || "", parsed.data);
45214
+ const sessionId = parsed.sessionId || parsed.cliId || parsed.cliType || "";
45215
+ if (this.ptyInputHandler && parsed.data && sessionId) {
45216
+ this.ptyInputHandler(sessionId, parsed.data);
45040
45217
  }
45041
45218
  return;
45042
45219
  }
@@ -45046,8 +45223,9 @@ ${e?.stack || ""}`);
45046
45223
  log(`pty_resize: REJECTED \u2014 permission=${permission} peer=${peerId}`);
45047
45224
  return;
45048
45225
  }
45049
- if (this.ptyResizeHandler && parsed.cols && parsed.rows) {
45050
- this.ptyResizeHandler(parsed.cliType || "", parsed.cols, parsed.rows);
45226
+ const sessionId = parsed.sessionId || parsed.cliId || parsed.cliType || "";
45227
+ if (this.ptyResizeHandler && parsed.cols && parsed.rows && sessionId) {
45228
+ this.ptyResizeHandler(sessionId, parsed.cols, parsed.rows);
45051
45229
  }
45052
45230
  return;
45053
45231
  }
@@ -45075,8 +45253,8 @@ ${e?.stack || ""}`);
45075
45253
  return sentAny;
45076
45254
  }
45077
45255
  /** Broadcast PTY output to all connected peers */
45078
- broadcastPtyOutput(cliType, data) {
45079
- const msg = JSON.stringify({ type: "pty_output", cliType, data });
45256
+ broadcastPtyOutput(sessionId, data) {
45257
+ const msg = JSON.stringify({ type: "pty_output", sessionId, data });
45080
45258
  let sentAny = false;
45081
45259
  for (const peer of this.peers.values()) {
45082
45260
  if (peer.state !== "connected" || !peer.dataChannel) continue;
@@ -45710,7 +45888,7 @@ var init_adhdev_daemon = __esm({
45710
45888
  fs15 = __toESM(require("fs"));
45711
45889
  path17 = __toESM(require("path"));
45712
45890
  import_chalk2 = __toESM(require("chalk"));
45713
- pkgVersion = "0.7.41";
45891
+ pkgVersion = "0.7.43";
45714
45892
  if (pkgVersion === "unknown") {
45715
45893
  try {
45716
45894
  const possiblePaths = [
@@ -45755,6 +45933,16 @@ var init_adhdev_daemon = __esm({
45755
45933
  constructor() {
45756
45934
  this.localPort = 19222;
45757
45935
  }
45936
+ getCliPresentationMode(sessionId) {
45937
+ if (!sessionId || !this.components) return null;
45938
+ const instance = this.components.instanceManager.getInstance(sessionId);
45939
+ if (instance?.category !== "cli") return null;
45940
+ const mode = instance.getPresentationMode?.();
45941
+ return mode === "chat" || mode === "terminal" ? mode : null;
45942
+ }
45943
+ isTerminalCliSession(sessionId) {
45944
+ return this.getCliPresentationMode(sessionId) === "terminal";
45945
+ }
45758
45946
  async start(options = {}) {
45759
45947
  try {
45760
45948
  const { installGlobalInterceptor: installGlobalInterceptor2 } = require("./logging/logger");
@@ -45784,9 +45972,6 @@ ${err?.stack || ""}`);
45784
45972
  const authToken = config2.machineSecret;
45785
45973
  if (!authToken) {
45786
45974
  console.log(import_chalk2.default.red("\n\u2717 No machine secret found."));
45787
- if (config2.connectionToken) {
45788
- console.log(import_chalk2.default.yellow(" Legacy connectionToken detected \u2014 please re-run setup."));
45789
- }
45790
45975
  console.log(import_chalk2.default.gray(" Run `adhdev setup` first.\n"));
45791
45976
  process.exit(1);
45792
45977
  }
@@ -45796,7 +45981,12 @@ ${err?.stack || ""}`);
45796
45981
  providerLogFn: LOG.forComponent("Provider").asLogFn(),
45797
45982
  cliManagerDeps: {
45798
45983
  getServerConn: () => this.serverConn,
45799
- getP2p: () => this.p2p,
45984
+ getP2p: () => ({
45985
+ broadcastPtyOutput: (key, data) => {
45986
+ if (!this.isTerminalCliSession(key)) return;
45987
+ this.p2p?.broadcastPtyOutput(key, data);
45988
+ }
45989
+ }),
45800
45990
  onStatusChange: () => this.statusReporter?.onStatusChange(),
45801
45991
  removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
45802
45992
  createPtyTransportFactory: ({ runtimeId, providerType, workspace, cliArgs, attachExisting }) => new SessionHostPtyTransportFactory({
@@ -45873,14 +46063,16 @@ ${err?.stack || ""}`);
45873
46063
  return { id: req.id, success: result.success, entries: result.files, error: result.error };
45874
46064
  }
45875
46065
  });
45876
- this.p2p.onPtyInput((cliId, data) => {
45877
- const found = this.components.cliManager.findAdapter(cliId, { instanceKey: cliId });
46066
+ this.p2p.onPtyInput((sessionId, data) => {
46067
+ if (!this.isTerminalCliSession(sessionId)) return;
46068
+ const found = this.components.cliManager.findAdapter(sessionId, { instanceKey: sessionId });
45878
46069
  if (found && typeof found.adapter.writeRaw === "function") {
45879
46070
  found.adapter.writeRaw(data);
45880
46071
  }
45881
46072
  });
45882
- this.p2p.onPtyResize((cliId, cols, rows) => {
45883
- const found = this.components.cliManager.findAdapter(cliId, { instanceKey: cliId });
46073
+ this.p2p.onPtyResize((sessionId, cols, rows) => {
46074
+ if (!this.isTerminalCliSession(sessionId)) return;
46075
+ const found = this.components.cliManager.findAdapter(sessionId, { instanceKey: sessionId });
45884
46076
  if (found && typeof found.adapter.resize === "function") {
45885
46077
  found.adapter.resize(cols, rows);
45886
46078
  }
@@ -46056,6 +46248,9 @@ ${err?.stack || ""}`);
46056
46248
  case "get_runtime_snapshot": {
46057
46249
  const sessionId = typeof data.sessionId === "string" ? data.sessionId : "";
46058
46250
  if (!sessionId) return { success: false, error: "sessionId is required" };
46251
+ if (!this.isTerminalCliSession(sessionId)) {
46252
+ return { success: false, error: "CLI session is not in terminal mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
46253
+ }
46059
46254
  if (!this.sessionHostEndpoint) return { success: false, error: "Session host unavailable" };
46060
46255
  const client = new SessionHostClient({ endpoint: this.sessionHostEndpoint });
46061
46256
  try {
@@ -46905,7 +47100,6 @@ function registerSetupCommands(program2, providerLoader) {
46905
47100
  console.log(import_chalk4.default.gray(` \u2022 ${ext}`));
46906
47101
  });
46907
47102
  console.log(` ${import_chalk4.default.bold("User:")} ${config2.userEmail || import_chalk4.default.gray("not logged in")}`);
46908
- console.log(` ${import_chalk4.default.bold("Auto-connect:")} ${config2.autoConnect ? import_chalk4.default.green("enabled") : import_chalk4.default.gray("disabled")}`);
46909
47103
  console.log(` ${import_chalk4.default.bold("Server:")} ${config2.serverUrl}`);
46910
47104
  console.log(` ${import_chalk4.default.bold("Setup date:")} ${config2.setupDate || "unknown"}`);
46911
47105
  console.log();
@@ -47001,7 +47195,6 @@ function registerSetupCommands(program2, providerLoader) {
47001
47195
  } catch {
47002
47196
  }
47003
47197
  const config2 = loadConfig2();
47004
- config2.apiToken = null;
47005
47198
  config2.machineSecret = void 0;
47006
47199
  config2.userEmail = null;
47007
47200
  config2.userName = null;