@adhdev/daemon-core 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.
Files changed (55) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +3 -4
  2. package/dist/cli-adapters/pty-transport.d.ts +1 -0
  3. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +4 -0
  4. package/dist/cli-adapters/terminal-backends/types.d.ts +4 -0
  5. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +4 -0
  6. package/dist/cli-adapters/terminal-screen.d.ts +4 -0
  7. package/dist/commands/cli-manager.d.ts +4 -2
  8. package/dist/config/chat-history.d.ts +0 -3
  9. package/dist/config/config.d.ts +2 -22
  10. package/dist/index.js +377 -195
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +377 -195
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/providers/cli-provider-instance.d.ts +4 -10
  15. package/dist/providers/contracts.d.ts +0 -79
  16. package/dist/providers/extension-provider-instance.d.ts +1 -0
  17. package/dist/providers/provider-instance.d.ts +0 -3
  18. package/dist/shared-types.d.ts +1 -3
  19. package/dist/status/normalize.js +60 -1
  20. package/dist/status/normalize.js.map +1 -1
  21. package/dist/status/normalize.mjs +60 -1
  22. package/dist/status/normalize.mjs.map +1 -1
  23. package/dist/status/reporter.d.ts +1 -0
  24. package/node_modules/@adhdev/session-host-core/dist/index.js +2 -2
  25. package/node_modules/@adhdev/session-host-core/dist/index.js.map +1 -1
  26. package/node_modules/@adhdev/session-host-core/dist/index.mjs +2 -2
  27. package/node_modules/@adhdev/session-host-core/dist/index.mjs.map +1 -1
  28. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  29. package/package.json +1 -1
  30. package/src/agent-stream/forward.ts +21 -1
  31. package/src/agent-stream/poller.ts +6 -1
  32. package/src/cli-adapters/provider-cli-adapter.ts +115 -71
  33. package/src/cli-adapters/pty-transport.ts +2 -0
  34. package/src/cli-adapters/session-host-transport.ts +1 -0
  35. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +5 -0
  36. package/src/cli-adapters/terminal-backends/types.ts +1 -0
  37. package/src/cli-adapters/terminal-backends/xterm-backend.ts +10 -0
  38. package/src/cli-adapters/terminal-screen.ts +4 -0
  39. package/src/commands/cli-manager.ts +44 -39
  40. package/src/commands/router.ts +1 -0
  41. package/src/commands/stream-commands.ts +14 -0
  42. package/src/config/chat-history.ts +3 -55
  43. package/src/config/config.d.ts +5 -50
  44. package/src/config/config.ts +71 -49
  45. package/src/config/workspaces.d.ts +1 -4
  46. package/src/providers/cli-provider-instance.ts +18 -42
  47. package/src/providers/contracts.ts +0 -81
  48. package/src/providers/extension-provider-instance.ts +27 -0
  49. package/src/providers/ide-provider-instance.ts +12 -0
  50. package/src/providers/provider-instance.d.ts +0 -1
  51. package/src/providers/provider-instance.ts +0 -3
  52. package/src/shared-types.ts +1 -3
  53. package/src/status/builders.ts +7 -2
  54. package/src/status/normalize.ts +81 -0
  55. package/src/status/reporter.ts +31 -2
package/dist/index.mjs CHANGED
@@ -28,7 +28,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
28
28
  // src/config/config.ts
29
29
  var config_exports = {};
30
30
  __export(config_exports, {
31
- generateConnectionToken: () => generateConnectionToken,
32
31
  generateMachineId: () => generateMachineId,
33
32
  getConfigDir: () => getConfigDir,
34
33
  isSetupComplete: () => isSetupComplete,
@@ -43,6 +42,57 @@ import { homedir } from "os";
43
42
  import { join } from "path";
44
43
  import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
45
44
  import { randomUUID } from "crypto";
45
+ function isPlainObject(value) {
46
+ return !!value && typeof value === "object" && !Array.isArray(value);
47
+ }
48
+ function asStringArray(value) {
49
+ if (!Array.isArray(value)) return [];
50
+ return value.filter((item) => typeof item === "string");
51
+ }
52
+ function asNullableString(value) {
53
+ return typeof value === "string" ? value : null;
54
+ }
55
+ function asOptionalString(value) {
56
+ return typeof value === "string" && value.trim() ? value : void 0;
57
+ }
58
+ function asBoolean(value, fallback) {
59
+ return typeof value === "boolean" ? value : fallback;
60
+ }
61
+ function normalizeConfig(raw) {
62
+ const parsed = isPlainObject(raw) ? raw : {};
63
+ const legacySessionReads = isPlainObject(parsed.recentSessionReads) ? parsed.recentSessionReads : {};
64
+ const sessionReads = isPlainObject(parsed.sessionReads) ? parsed.sessionReads : {};
65
+ const mergedSessionReads = Object.fromEntries(
66
+ Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
67
+ );
68
+ const sessionReadMarkers = Object.fromEntries(
69
+ Object.entries(isPlainObject(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
70
+ );
71
+ return {
72
+ serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
73
+ selectedIde: asNullableString(parsed.selectedIde),
74
+ configuredIdes: asStringArray(parsed.configuredIdes),
75
+ installedExtensions: asStringArray(parsed.installedExtensions),
76
+ userEmail: asNullableString(parsed.userEmail),
77
+ userName: asNullableString(parsed.userName),
78
+ setupCompleted: asBoolean(parsed.setupCompleted, DEFAULT_CONFIG.setupCompleted),
79
+ setupDate: asNullableString(parsed.setupDate),
80
+ enabledIdes: asStringArray(parsed.enabledIdes),
81
+ workspaces: Array.isArray(parsed.workspaces) ? parsed.workspaces : [],
82
+ defaultWorkspaceId: asNullableString(parsed.defaultWorkspaceId) ?? asNullableString(parsed.activeWorkspaceId),
83
+ recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
84
+ sessionReads: mergedSessionReads,
85
+ sessionReadMarkers,
86
+ machineNickname: asNullableString(parsed.machineNickname),
87
+ machineId: asOptionalString(parsed.machineId),
88
+ machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
89
+ registeredMachineId: asOptionalString(parsed.registeredMachineId),
90
+ providerSettings: isPlainObject(parsed.providerSettings) ? parsed.providerSettings : {},
91
+ ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
92
+ disableUpstream: asBoolean(parsed.disableUpstream, DEFAULT_CONFIG.disableUpstream ?? false),
93
+ providerDir: asOptionalString(parsed.providerDir)
94
+ };
95
+ }
46
96
  function generateMachineId() {
47
97
  return `${MACHINE_ID_PREFIX}${randomUUID().replace(/-/g, "")}`;
48
98
  }
@@ -86,14 +136,10 @@ function loadConfig() {
86
136
  try {
87
137
  const raw = readFileSync(configPath, "utf-8");
88
138
  const parsed = JSON.parse(raw);
89
- const merged = { ...DEFAULT_CONFIG, ...parsed };
90
- if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
91
- merged.defaultWorkspaceId = merged.activeWorkspaceId;
92
- }
93
- delete merged.activeWorkspaceId;
94
- const ensured = ensureMachineId(merged);
139
+ const normalizedInput = normalizeConfig(parsed);
140
+ const ensured = ensureMachineId(normalizedInput);
95
141
  const normalized = ensured.config;
96
- if (ensured.changed) {
142
+ if (ensured.changed || JSON.stringify(parsed) !== JSON.stringify(normalized)) {
97
143
  try {
98
144
  saveConfig(normalized);
99
145
  } catch {
@@ -108,10 +154,11 @@ function loadConfig() {
108
154
  function saveConfig(config) {
109
155
  const configPath = getConfigPath();
110
156
  const dir = getConfigDir();
157
+ const normalized = normalizeConfig(config);
111
158
  if (!existsSync(dir)) {
112
159
  mkdirSync(dir, { recursive: true, mode: 448 });
113
160
  }
114
- writeFileSync(configPath, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
161
+ writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
115
162
  try {
116
163
  chmodSync(configPath, 384);
117
164
  } catch {
@@ -140,32 +187,19 @@ function isSetupComplete() {
140
187
  function resetConfig() {
141
188
  saveConfig({ ...DEFAULT_CONFIG });
142
189
  }
143
- function generateConnectionToken() {
144
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
145
- let token = "db_";
146
- for (let i = 0; i < 32; i++) {
147
- token += chars.charAt(Math.floor(Math.random() * chars.length));
148
- }
149
- return token;
150
- }
151
190
  var DEFAULT_CONFIG, MACHINE_ID_PREFIX;
152
191
  var init_config = __esm({
153
192
  "src/config/config.ts"() {
154
193
  "use strict";
155
194
  DEFAULT_CONFIG = {
156
195
  serverUrl: "https://api.adhf.dev",
157
- apiToken: null,
158
- connectionToken: null,
159
196
  selectedIde: null,
160
197
  configuredIdes: [],
161
198
  installedExtensions: [],
162
- autoConnect: true,
163
- notifications: true,
164
199
  userEmail: null,
165
200
  userName: null,
166
201
  setupCompleted: false,
167
202
  setupDate: null,
168
- configuredCLIs: [],
169
203
  enabledIdes: [],
170
204
  workspaces: [],
171
205
  defaultWorkspaceId: null,
@@ -481,6 +515,9 @@ var init_ghostty_vt_backend = __esm({
481
515
  getText() {
482
516
  return this.terminal.formatPlainText({ trim: true }) || "";
483
517
  }
518
+ getCursorPosition() {
519
+ return this.terminal.getCursorPosition();
520
+ }
484
521
  dispose() {
485
522
  this.terminal.dispose();
486
523
  }
@@ -538,6 +575,13 @@ var init_xterm_backend = __esm({
538
575
  while (last > first && !lines[last - 1]?.trim()) last--;
539
576
  return lines.slice(first, last).join("\n");
540
577
  }
578
+ getCursorPosition() {
579
+ const buffer = this.terminal.buffer.active;
580
+ return {
581
+ col: Math.max(0, buffer.cursorX || 0),
582
+ row: Math.max(0, buffer.cursorY || 0)
583
+ };
584
+ }
541
585
  dispose() {
542
586
  this.terminal.dispose();
543
587
  }
@@ -624,6 +668,9 @@ var init_terminal_screen = __esm({
624
668
  getText() {
625
669
  return this.terminal.getText();
626
670
  }
671
+ getCursorPosition() {
672
+ return this.terminal.getCursorPosition();
673
+ }
627
674
  dispose() {
628
675
  this.terminal.dispose();
629
676
  }
@@ -654,6 +701,7 @@ var init_pty_transport = __esm({
654
701
  this.handle = handle;
655
702
  }
656
703
  ready = Promise.resolve();
704
+ terminalQueriesHandled = false;
657
705
  get pid() {
658
706
  return this.handle.pid;
659
707
  }
@@ -710,6 +758,32 @@ function stripTerminalNoise(str) {
710
758
  function sanitizeTerminalText(str) {
711
759
  return stripTerminalNoise(stripAnsi(str));
712
760
  }
761
+ function buildCliSpawnEnv(baseEnv, overrides) {
762
+ const env = {};
763
+ const source = { ...baseEnv, ...overrides || {} };
764
+ for (const [key, value] of Object.entries(source)) {
765
+ if (typeof value !== "string") continue;
766
+ env[key] = value;
767
+ }
768
+ for (const key of Object.keys(env)) {
769
+ 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_")) {
770
+ delete env[key];
771
+ }
772
+ }
773
+ return env;
774
+ }
775
+ function computeTerminalQueryTail(buffer) {
776
+ const prefixes = ["\x1B[6n", "\x1B[?6n"];
777
+ const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
778
+ const start = Math.max(0, buffer.length - maxLength);
779
+ for (let i = start; i < buffer.length; i++) {
780
+ const suffix = buffer.slice(i);
781
+ if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
782
+ return suffix;
783
+ }
784
+ }
785
+ return "";
786
+ }
713
787
  function findBinary(name) {
714
788
  const isWin = os12.platform() === "win32";
715
789
  try {
@@ -796,36 +870,6 @@ function promptLikelyVisible(screenText, promptSnippet) {
796
870
  ).length;
797
871
  return matched >= required;
798
872
  }
799
- function splitHistoryLines(text) {
800
- return String(text || "").split("\n").map((line) => line.replace(/\s+$/, ""));
801
- }
802
- function normalizeHistoryLine(line) {
803
- return String(line || "").replace(/\s+/g, " ").trim();
804
- }
805
- function mergeTerminalHistory(existing, snapshot) {
806
- const next = String(snapshot || "").trim();
807
- if (!next) return existing;
808
- const prev = String(existing || "").trim();
809
- if (!prev) return next;
810
- if (prev === next || prev.endsWith(next)) return prev;
811
- const prevLines = splitHistoryLines(prev);
812
- const nextLines = splitHistoryLines(next);
813
- const prevNorm = prevLines.map(normalizeHistoryLine);
814
- const nextNorm = nextLines.map(normalizeHistoryLine);
815
- const maxOverlap = Math.min(prevLines.length, nextLines.length);
816
- for (let overlap = maxOverlap; overlap >= 1; overlap -= 1) {
817
- const prevTail = prevNorm.slice(prevNorm.length - overlap);
818
- const nextHead = nextNorm.slice(0, overlap);
819
- if (prevTail.every((line, index) => line === nextHead[index])) {
820
- return [...prevLines, ...nextLines.slice(overlap)].join("\n").trim();
821
- }
822
- }
823
- const compactPrev = prevNorm.join("\n");
824
- const compactNext = nextNorm.join("\n");
825
- if (compactPrev.includes(compactNext)) return prev;
826
- return `${prev}
827
- ${next}`.trim();
828
- }
829
873
  function parsePatternEntry(x) {
830
874
  if (x instanceof RegExp) return x;
831
875
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -937,6 +981,7 @@ var init_provider_cli_adapter = __esm({
937
981
  pendingOutputParseTimer = null;
938
982
  ptyOutputBuffer = "";
939
983
  ptyOutputFlushTimer = null;
984
+ pendingTerminalQueryTail = "";
940
985
  // Server log forwarding
941
986
  serverConn = null;
942
987
  logBuffer = [];
@@ -968,9 +1013,7 @@ var init_provider_cli_adapter = __esm({
968
1013
  /** Full accumulated raw PTY output (with ANSI) */
969
1014
  accumulatedRawBuffer = "";
970
1015
  /** Current visible terminal screen snapshot */
971
- terminalScreen = new TerminalScreen(40, 120);
972
- /** Rolling append-only terminal transcript built from screen snapshots */
973
- terminalHistory = "";
1016
+ terminalScreen = new TerminalScreen(30, 100);
974
1017
  /** Max accumulated buffer size (last 50KB) */
975
1018
  static MAX_ACCUMULATED_BUFFER = 5e4;
976
1019
  currentTurnScope = null;
@@ -978,6 +1021,13 @@ var init_provider_cli_adapter = __esm({
978
1021
  this.messages = [...this.committedMessages];
979
1022
  this.structuredMessages = [...this.committedMessages];
980
1023
  }
1024
+ normalizeParsedMessages(parsedMessages) {
1025
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
1026
+ role: message.role,
1027
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
1028
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
1029
+ }));
1030
+ }
981
1031
  sliceFromOffset(text, start) {
982
1032
  if (!text) return "";
983
1033
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -985,15 +1035,13 @@ var init_provider_cli_adapter = __esm({
985
1035
  return text.slice(start);
986
1036
  }
987
1037
  buildParseInput(baseMessages, partialResponse, scope) {
988
- const buffer = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1038
+ const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
989
1039
  const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
990
- const terminalHistory = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.terminalHistory : this.terminalHistory;
991
1040
  return {
992
1041
  buffer,
993
1042
  rawBuffer,
994
1043
  recentBuffer: buffer.slice(-1e3) || this.recentOutputBuffer,
995
1044
  screenText: this.terminalScreen.getText(),
996
- terminalHistory,
997
1045
  messages: [...baseMessages],
998
1046
  partialResponse
999
1047
  };
@@ -1071,13 +1119,10 @@ var init_provider_cli_adapter = __esm({
1071
1119
  shellArgs = allArgs;
1072
1120
  }
1073
1121
  const ptyOpts = {
1074
- cols: 120,
1075
- rows: 40,
1122
+ cols: 100,
1123
+ rows: 30,
1076
1124
  cwd: this.workingDir,
1077
- env: {
1078
- ...process.env,
1079
- ...spawnConfig.env
1080
- }
1125
+ env: buildCliSpawnEnv(process.env, spawnConfig.env)
1081
1126
  };
1082
1127
  try {
1083
1128
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
@@ -1095,8 +1140,8 @@ var init_provider_cli_adapter = __esm({
1095
1140
  }
1096
1141
  this.ptyProcess.onData((data) => {
1097
1142
  if (Date.now() < this.resizeSuppressUntil) return;
1098
- if (data.includes("\x1B[6n") || data.includes("\x1B[?6n")) {
1099
- this.ptyProcess?.write("\x1B[1;1R");
1143
+ if (!this.ptyProcess?.terminalQueriesHandled) {
1144
+ this.respondToTerminalQueries(data);
1100
1145
  }
1101
1146
  this.pendingOutputParseBuffer += data;
1102
1147
  if (!this.pendingOutputParseTimer) {
@@ -1131,8 +1176,8 @@ var init_provider_cli_adapter = __esm({
1131
1176
  this.spawnAt = Date.now();
1132
1177
  this.startupParseGate = true;
1133
1178
  this.startupBuffer = "";
1134
- this.terminalScreen.reset(40, 120);
1135
- this.terminalHistory = "";
1179
+ this.terminalScreen.reset(30, 100);
1180
+ this.pendingTerminalQueryTail = "";
1136
1181
  this.currentTurnScope = null;
1137
1182
  this.ready = false;
1138
1183
  await this.ptyProcess.ready;
@@ -1142,7 +1187,6 @@ var init_provider_cli_adapter = __esm({
1142
1187
  // ─── Output Handling ────────────────────────────
1143
1188
  handleOutput(rawData) {
1144
1189
  this.terminalScreen.write(rawData);
1145
- this.terminalHistory = mergeTerminalHistory(this.terminalHistory, this.terminalScreen.getText());
1146
1190
  const cleanData = sanitizeTerminalText(rawData);
1147
1191
  if (this.isWaitingForResponse && cleanData) {
1148
1192
  this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
@@ -1374,6 +1418,15 @@ var init_provider_cli_adapter = __esm({
1374
1418
  this.onStatusChange?.();
1375
1419
  }
1376
1420
  commitCurrentTranscript() {
1421
+ const parsed = this.parseCurrentTranscript(
1422
+ this.committedMessages,
1423
+ this.responseBuffer,
1424
+ this.currentTurnScope
1425
+ );
1426
+ if (parsed && Array.isArray(parsed.messages)) {
1427
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
1428
+ this.syncMessageViews();
1429
+ }
1377
1430
  }
1378
1431
  // ─── Script Execution ──────────────────────────
1379
1432
  runDetectStatus(text) {
@@ -1409,8 +1462,7 @@ var init_provider_cli_adapter = __esm({
1409
1462
  status: this.currentStatus,
1410
1463
  messages: [...this.committedMessages],
1411
1464
  workingDir: this.workingDir,
1412
- activeModal: this.activeModal,
1413
- terminalHistory: this.terminalHistory
1465
+ activeModal: this.activeModal
1414
1466
  };
1415
1467
  }
1416
1468
  /**
@@ -1418,12 +1470,25 @@ var init_provider_cli_adapter = __esm({
1418
1470
  * Called by command handler / dashboard for rich content rendering.
1419
1471
  */
1420
1472
  getScriptParsedStatus() {
1473
+ const parsed = this.parseCurrentTranscript(
1474
+ this.committedMessages,
1475
+ this.responseBuffer,
1476
+ this.currentTurnScope
1477
+ );
1478
+ if (parsed && Array.isArray(parsed.messages)) {
1479
+ return {
1480
+ id: parsed.id || "cli_session",
1481
+ status: parsed.status || this.currentStatus,
1482
+ title: parsed.title || this.cliName,
1483
+ messages: parsed.messages,
1484
+ activeModal: parsed.activeModal ?? this.activeModal
1485
+ };
1486
+ }
1421
1487
  const messages = [...this.committedMessages];
1422
1488
  return {
1423
1489
  id: "cli_session",
1424
1490
  status: this.currentStatus,
1425
1491
  title: this.cliName,
1426
- terminalHistory: this.terminalHistory,
1427
1492
  messages: messages.slice(-50).map((message, index) => ({
1428
1493
  id: `msg_${index}`,
1429
1494
  role: message.role,
@@ -1491,10 +1556,9 @@ ${data.message || ""}`.trim();
1491
1556
  prompt: text,
1492
1557
  startedAt: Date.now(),
1493
1558
  bufferStart: this.accumulatedBuffer.length,
1494
- rawBufferStart: this.accumulatedRawBuffer.length,
1495
- terminalHistoryStart: this.terminalHistory.length
1559
+ rawBufferStart: this.accumulatedRawBuffer.length
1496
1560
  };
1497
- 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)}`);
1561
+ LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
1498
1562
  this.submitRetryUsed = false;
1499
1563
  this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
1500
1564
  const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
@@ -1679,6 +1743,7 @@ ${data.message || ""}`.trim();
1679
1743
  this.pendingOutputParseTimer = null;
1680
1744
  }
1681
1745
  this.pendingOutputParseBuffer = "";
1746
+ this.pendingTerminalQueryTail = "";
1682
1747
  if (this.ptyOutputFlushTimer) {
1683
1748
  clearTimeout(this.ptyOutputFlushTimer);
1684
1749
  this.ptyOutputFlushTimer = null;
@@ -1718,6 +1783,7 @@ ${data.message || ""}`.trim();
1718
1783
  this.pendingOutputParseTimer = null;
1719
1784
  }
1720
1785
  this.pendingOutputParseBuffer = "";
1786
+ this.pendingTerminalQueryTail = "";
1721
1787
  if (this.ptyOutputFlushTimer) {
1722
1788
  clearTimeout(this.ptyOutputFlushTimer);
1723
1789
  this.ptyOutputFlushTimer = null;
@@ -1744,7 +1810,6 @@ ${data.message || ""}`.trim();
1744
1810
  this.syncMessageViews();
1745
1811
  this.accumulatedBuffer = "";
1746
1812
  this.accumulatedRawBuffer = "";
1747
- this.terminalHistory = "";
1748
1813
  this.currentTurnScope = null;
1749
1814
  this.submitRetryUsed = false;
1750
1815
  this.submitRetryPromptSnippet = "";
@@ -1753,6 +1818,7 @@ ${data.message || ""}`.trim();
1753
1818
  this.pendingOutputParseTimer = null;
1754
1819
  }
1755
1820
  this.pendingOutputParseBuffer = "";
1821
+ this.pendingTerminalQueryTail = "";
1756
1822
  if (this.ptyOutputFlushTimer) {
1757
1823
  clearTimeout(this.ptyOutputFlushTimer);
1758
1824
  this.ptyOutputFlushTimer = null;
@@ -1814,7 +1880,6 @@ ${data.message || ""}`.trim();
1814
1880
  structuredMessages: this.structuredMessages.slice(-20),
1815
1881
  messageCount: this.committedMessages.length,
1816
1882
  screenText: sanitizeTerminalText(this.terminalScreen.getText()).slice(-4e3),
1817
- terminalHistory: this.terminalHistory.slice(-8e3),
1818
1883
  currentTurnScope: this.currentTurnScope,
1819
1884
  startupBuffer: this.startupBuffer.slice(-4e3),
1820
1885
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
@@ -1842,6 +1907,20 @@ ${data.message || ""}`.trim();
1842
1907
  ptyAlive: !!this.ptyProcess
1843
1908
  };
1844
1909
  }
1910
+ respondToTerminalQueries(data) {
1911
+ if (!this.ptyProcess || !data) return;
1912
+ const combined = this.pendingTerminalQueryTail + data;
1913
+ const regex = /\x1b\[(\?)?6n/g;
1914
+ let match;
1915
+ while ((match = regex.exec(combined)) !== null) {
1916
+ const cursor = this.terminalScreen.getCursorPosition();
1917
+ const row = Math.max(1, (cursor.row | 0) + 1);
1918
+ const col = Math.max(1, (cursor.col | 0) + 1);
1919
+ const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
1920
+ this.ptyProcess.write(response);
1921
+ }
1922
+ this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
1923
+ }
1845
1924
  };
1846
1925
  }
1847
1926
  });
@@ -3744,6 +3823,8 @@ var ExtensionProviderInstance = class {
3744
3823
  this.detectTransition(newStatus, data);
3745
3824
  this.currentStatus = newStatus;
3746
3825
  }
3826
+ } else if (event === "stream_reset") {
3827
+ this.resetStreamState();
3747
3828
  } else if (event === "extension_connected") {
3748
3829
  this.ideType = data?.ideType || "";
3749
3830
  }
@@ -3823,6 +3904,30 @@ var ExtensionProviderInstance = class {
3823
3904
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
3824
3905
  return title || this.agentName || this.provider.name;
3825
3906
  }
3907
+ resetStreamState() {
3908
+ if (this.currentStatus !== "idle") {
3909
+ this.detectTransition("idle", {
3910
+ title: this.chatTitle,
3911
+ agentName: this.agentName,
3912
+ extensionId: this.extensionId,
3913
+ messages: this.messages
3914
+ });
3915
+ }
3916
+ this.agentStreams = [];
3917
+ this.messages = [];
3918
+ this.activeModal = null;
3919
+ this.currentModel = "";
3920
+ this.currentMode = "";
3921
+ this.controlValues = {};
3922
+ this.currentStatus = "idle";
3923
+ this.chatId = null;
3924
+ this.chatTitle = null;
3925
+ this.agentName = "";
3926
+ this.extensionId = "";
3927
+ this.lastAgentStatus = "idle";
3928
+ this.generatingStartedAt = 0;
3929
+ this.monitor.reset();
3930
+ }
3826
3931
  };
3827
3932
 
3828
3933
  // src/config/chat-history.ts
@@ -3836,8 +3941,6 @@ var ChatHistoryWriter = class {
3836
3941
  lastSeenCounts = /* @__PURE__ */ new Map();
3837
3942
  /** Last seen message hash per agent (deduplication) */
3838
3943
  lastSeenHashes = /* @__PURE__ */ new Map();
3839
- /** Last seen append-only terminal transcript per agent */
3840
- lastSeenTerminal = /* @__PURE__ */ new Map();
3841
3944
  rotated = false;
3842
3945
  /**
3843
3946
  * Append new messages to history
@@ -3895,51 +3998,10 @@ var ChatHistoryWriter = class {
3895
3998
  } catch {
3896
3999
  }
3897
4000
  }
3898
- appendTerminalHistory(agentType, terminalHistory, sessionTitle, instanceId) {
3899
- const next = String(terminalHistory || "");
3900
- if (!next.trim()) return;
3901
- try {
3902
- const dedupKey = instanceId ? `${agentType}:${instanceId}:terminal` : `${agentType}:terminal`;
3903
- const prev = this.lastSeenTerminal.get(dedupKey) || "";
3904
- if (prev === next) return;
3905
- let delta = "";
3906
- if (!prev) {
3907
- delta = next;
3908
- } else if (next.startsWith(prev)) {
3909
- delta = next.slice(prev.length);
3910
- } else if (prev.includes(next)) {
3911
- this.lastSeenTerminal.set(dedupKey, next);
3912
- return;
3913
- } else {
3914
- delta = `
3915
-
3916
- [terminal snapshot reset ${(/* @__PURE__ */ new Date()).toISOString()} | ${sessionTitle || agentType}]
3917
- ${next}`;
3918
- }
3919
- if (!delta) {
3920
- this.lastSeenTerminal.set(dedupKey, next);
3921
- return;
3922
- }
3923
- const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
3924
- fs3.mkdirSync(dir, { recursive: true });
3925
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3926
- const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
3927
- const filePath = path4.join(dir, `${filePrefix}${date}.terminal.log`);
3928
- fs3.appendFileSync(filePath, delta, "utf-8");
3929
- this.lastSeenTerminal.set(dedupKey, next);
3930
- if (!this.rotated) {
3931
- this.rotated = true;
3932
- this.rotateOldFiles().catch(() => {
3933
- });
3934
- }
3935
- } catch {
3936
- }
3937
- }
3938
4001
  /** Called when agent session is explicitly changed */
3939
4002
  onSessionChange(agentType) {
3940
4003
  this.lastSeenHashes.delete(agentType);
3941
4004
  this.lastSeenCounts.delete(agentType);
3942
- this.lastSeenTerminal.delete(`${agentType}:terminal`);
3943
4005
  }
3944
4006
  /** Delete history files older than 30 days */
3945
4007
  async rotateOldFiles() {
@@ -4105,11 +4167,23 @@ var IdeProviderInstance = class {
4105
4167
  } else if (event === "cdp_disconnected") {
4106
4168
  this.cachedChat = null;
4107
4169
  this.currentStatus = "idle";
4170
+ for (const ext of this.extensions.values()) {
4171
+ ext.onEvent("stream_reset");
4172
+ }
4108
4173
  } else if (event === "stream_update") {
4109
4174
  const extType = data?.extensionType;
4110
4175
  if (extType && this.extensions.has(extType)) {
4111
4176
  this.extensions.get(extType).onEvent("stream_update", data);
4112
4177
  }
4178
+ } else if (event === "stream_reset") {
4179
+ const extType = data?.extensionType;
4180
+ if (extType && this.extensions.has(extType)) {
4181
+ this.extensions.get(extType).onEvent("stream_reset");
4182
+ }
4183
+ } else if (event === "stream_reset_all") {
4184
+ for (const ext of this.extensions.values()) {
4185
+ ext.onEvent("stream_reset");
4186
+ }
4113
4187
  }
4114
4188
  }
4115
4189
  dispose() {
@@ -4776,6 +4850,57 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
4776
4850
  "thinking",
4777
4851
  "active"
4778
4852
  ]);
4853
+ var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
4854
+ var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
4855
+ var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
4856
+ var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
4857
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
4858
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
4859
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
4860
+ function truncateString(value, maxChars) {
4861
+ if (value.length <= maxChars) return value;
4862
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
4863
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
4864
+ }
4865
+ function trimStructuredStrings(value, maxChars) {
4866
+ if (typeof value === "string") return truncateString(value, maxChars);
4867
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
4868
+ if (!value || typeof value !== "object") return value;
4869
+ return Object.fromEntries(
4870
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
4871
+ );
4872
+ }
4873
+ function estimateBytes(value) {
4874
+ try {
4875
+ return JSON.stringify(value).length;
4876
+ } catch {
4877
+ return String(value ?? "").length;
4878
+ }
4879
+ }
4880
+ function trimMessageForStatus(message, stringLimit) {
4881
+ if (!message || typeof message !== "object") return message;
4882
+ return trimStructuredStrings(message, stringLimit);
4883
+ }
4884
+ function trimMessagesForStatus(messages) {
4885
+ if (!Array.isArray(messages) || messages.length === 0) return [];
4886
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
4887
+ const kept = [];
4888
+ let totalBytes = 0;
4889
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
4890
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
4891
+ let size = estimateBytes(normalized);
4892
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
4893
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
4894
+ size = estimateBytes(normalized);
4895
+ }
4896
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
4897
+ continue;
4898
+ }
4899
+ kept.push(normalized);
4900
+ totalBytes += size;
4901
+ }
4902
+ return kept.reverse();
4903
+ }
4779
4904
  function hasApprovalButtons(activeModal) {
4780
4905
  return (activeModal?.buttons?.length ?? 0) > 0;
4781
4906
  }
@@ -4802,7 +4927,15 @@ function normalizeActiveChatData(activeChat) {
4802
4927
  if (!activeChat) return activeChat;
4803
4928
  return {
4804
4929
  ...activeChat,
4805
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
4930
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
4931
+ messages: trimMessagesForStatus(activeChat.messages),
4932
+ activeModal: activeChat.activeModal ? {
4933
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
4934
+ buttons: (activeChat.activeModal.buttons || []).map(
4935
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
4936
+ )
4937
+ } : activeChat.activeModal,
4938
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
4806
4939
  };
4807
4940
  }
4808
4941
 
@@ -4900,6 +5033,11 @@ var PTY_SESSION_CAPABILITIES = [
4900
5033
  "terminal_io",
4901
5034
  "resize_terminal"
4902
5035
  ];
5036
+ var CLI_CHAT_SESSION_CAPABILITIES = [
5037
+ "read_chat",
5038
+ "send_message",
5039
+ "resolve_action"
5040
+ ];
4903
5041
  var ACP_SESSION_CAPABILITIES = [
4904
5042
  "read_chat",
4905
5043
  "send_message",
@@ -4989,11 +5127,10 @@ function buildCliSession(state) {
4989
5127
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
4990
5128
  runtimeWriteOwner: state.runtime?.writeOwner || null,
4991
5129
  runtimeAttachedClients: state.runtime?.attachedClients || [],
4992
- launchMode: state.launchMode,
4993
5130
  mode: state.mode,
4994
5131
  resume: state.resume,
4995
5132
  activeChat,
4996
- capabilities: PTY_SESSION_CAPABILITIES,
5133
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
4997
5134
  controlValues: state.controlValues,
4998
5135
  providerControls: buildFallbackControls(
4999
5136
  state.providerControls
@@ -6167,6 +6304,13 @@ async function handleFileListBrowse(h, args) {
6167
6304
 
6168
6305
  // src/commands/stream-commands.ts
6169
6306
  init_logger();
6307
+ function getCliPresentationMode(h, targetSessionId) {
6308
+ if (!targetSessionId) return null;
6309
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
6310
+ if (instance?.category !== "cli") return null;
6311
+ const mode = instance.getPresentationMode?.();
6312
+ return mode === "chat" || mode === "terminal" ? mode : null;
6313
+ }
6170
6314
  async function handleFocusSession(h, args) {
6171
6315
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
6172
6316
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -6177,6 +6321,9 @@ async function handleFocusSession(h, args) {
6177
6321
  function handlePtyInput(h, args) {
6178
6322
  const { cliType, data, targetSessionId } = args || {};
6179
6323
  if (!data) return { success: false, error: "data required" };
6324
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6325
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6326
+ }
6180
6327
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6181
6328
  if (!adapter || typeof adapter.writeRaw !== "function") {
6182
6329
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -6187,6 +6334,9 @@ function handlePtyInput(h, args) {
6187
6334
  function handlePtyResize(h, args) {
6188
6335
  const { cliType, cols, rows, force, targetSessionId } = args || {};
6189
6336
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
6337
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6338
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6339
+ }
6190
6340
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6191
6341
  if (!adapter || typeof adapter.resize !== "function") {
6192
6342
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -8594,6 +8744,7 @@ var DaemonCommandRouter = class {
8594
8744
  // ─── CLI / ACP commands ───
8595
8745
  case "launch_cli":
8596
8746
  case "stop_cli":
8747
+ case "set_cli_view_mode":
8597
8748
  case "agent_command": {
8598
8749
  return this.deps.cliManager.handleCliCommand(cmd, args);
8599
8750
  }
@@ -8938,6 +9089,20 @@ var DaemonStatusReporter = class {
8938
9089
  ts() {
8939
9090
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
8940
9091
  }
9092
+ summarizeLargePayloadSessions(payload) {
9093
+ const sessions = Array.isArray(payload.sessions) ? payload.sessions : [];
9094
+ return sessions.map((session) => ({
9095
+ id: String(session?.id || ""),
9096
+ providerType: String(session?.providerType || ""),
9097
+ bytes: (() => {
9098
+ try {
9099
+ return JSON.stringify(session).length;
9100
+ } catch {
9101
+ return 0;
9102
+ }
9103
+ })()
9104
+ })).sort((a, b) => b.bytes - a.bytes).slice(0, 3).map((session) => `${session.providerType || "unknown"}:${session.id}=${session.bytes}b`).join(", ");
9105
+ }
8941
9106
  async sendUnifiedStatusReport(opts) {
8942
9107
  const { serverConn, p2p } = this.deps;
8943
9108
  if (!serverConn?.isConnected()) return;
@@ -8990,9 +9155,16 @@ var DaemonStatusReporter = class {
8990
9155
  screenshotUsage: this.deps.getScreenshotUsage?.() || null,
8991
9156
  connectedExtensions: []
8992
9157
  };
9158
+ const payloadBytes = JSON.stringify(payload).length;
8993
9159
  const p2pSent = this.sendP2PPayload(payload);
8994
9160
  if (p2pSent) {
8995
- LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
9161
+ LOG.debug("P2P", `sent (${payloadBytes} bytes)`);
9162
+ if (payloadBytes > 256 * 1024) {
9163
+ LOG.warn(
9164
+ "P2P",
9165
+ `large status payload (${payloadBytes} bytes) top sessions: ${this.summarizeLargePayloadSessions(payload) || "n/a"}`
9166
+ );
9167
+ }
8996
9168
  }
8997
9169
  if (opts?.p2pOnly) return;
8998
9170
  const wsPayload = {
@@ -9022,7 +9194,9 @@ var DaemonStatusReporter = class {
9022
9194
  acpModes: session.acpModes
9023
9195
  })),
9024
9196
  p2p: payload.p2p,
9025
- timestamp: now
9197
+ timestamp: now,
9198
+ detectedIdes: payload.detectedIdes,
9199
+ availableProviders: payload.availableProviders
9026
9200
  };
9027
9201
  serverConn.sendMessage("status_report", wsPayload);
9028
9202
  LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
@@ -9068,14 +9242,13 @@ init_provider_cli_adapter();
9068
9242
  import * as crypto3 from "crypto";
9069
9243
  init_logger();
9070
9244
  var CliProviderInstance = class {
9071
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
9245
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
9072
9246
  this.provider = provider;
9073
9247
  this.workingDir = workingDir;
9074
9248
  this.cliArgs = cliArgs;
9075
9249
  this.type = provider.type;
9076
9250
  this.instanceId = instanceId || crypto3.randomUUID();
9077
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
9078
- this.resolvedOutputFormat = this.resolveOutputFormat();
9251
+ this.presentationMode = "chat";
9079
9252
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
9080
9253
  this.monitor = new StatusMonitor();
9081
9254
  this.historyWriter = new ChatHistoryWriter();
@@ -9094,26 +9267,7 @@ var CliProviderInstance = class {
9094
9267
  lastApprovalEventAt = 0;
9095
9268
  historyWriter;
9096
9269
  instanceId;
9097
- launchMode;
9098
- resolvedOutputFormat;
9099
- /**
9100
- * Determine output rendering format from:
9101
- * 1. launchMode.outputFormat (explicit override)
9102
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
9103
- * 3. Default: 'terminal'
9104
- */
9105
- resolveOutputFormat() {
9106
- if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
9107
- if (this.provider.launchOptions?.length) {
9108
- for (const opt of this.provider.launchOptions) {
9109
- if (!opt.outputFormatMap) continue;
9110
- for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
9111
- if (this.cliArgs.includes(val)) return fmt;
9112
- }
9113
- }
9114
- }
9115
- return "terminal";
9116
- }
9270
+ presentationMode;
9117
9271
  // ─── Lifecycle ─────────────────────────────────
9118
9272
  async init(context) {
9119
9273
  this.context = context;
@@ -9138,30 +9292,21 @@ var CliProviderInstance = class {
9138
9292
  }
9139
9293
  getState() {
9140
9294
  const adapterStatus = this.adapter.getStatus();
9295
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9141
9296
  const runtime = this.adapter.getRuntimeMetadata();
9142
9297
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9143
- if (adapterStatus.terminalHistory?.trim()) {
9144
- this.historyWriter.appendTerminalHistory(
9145
- this.type,
9146
- adapterStatus.terminalHistory,
9147
- `${this.provider.name} \xB7 ${dirName}`,
9148
- this.instanceId
9149
- );
9150
- }
9151
9298
  return {
9152
9299
  type: this.type,
9153
9300
  name: this.provider.name,
9154
9301
  category: "cli",
9155
9302
  status: adapterStatus.status,
9156
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
9157
- launchMode: this.launchMode?.id,
9303
+ mode: this.presentationMode,
9158
9304
  activeChat: {
9159
9305
  id: `${this.type}_${this.workingDir}`,
9160
- title: `${this.provider.name} \xB7 ${dirName}`,
9161
- status: adapterStatus.status,
9162
- messages: [],
9163
- activeModal: adapterStatus.activeModal,
9164
- terminalHistory: adapterStatus.terminalHistory,
9306
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
9307
+ status: parsedStatus?.status || adapterStatus.status,
9308
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
9309
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
9165
9310
  inputContent: ""
9166
9311
  },
9167
9312
  workspace: this.workingDir,
@@ -9183,6 +9328,13 @@ var CliProviderInstance = class {
9183
9328
  providerControls: this.provider.controls
9184
9329
  };
9185
9330
  }
9331
+ setPresentationMode(mode) {
9332
+ if (this.presentationMode === mode) return;
9333
+ this.presentationMode = mode;
9334
+ }
9335
+ getPresentationMode() {
9336
+ return this.presentationMode;
9337
+ }
9186
9338
  onEvent(event, data) {
9187
9339
  if (event === "send_message" && data?.text) {
9188
9340
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -10246,6 +10398,15 @@ var DaemonCliManager = class {
10246
10398
  const hash = __require("crypto").createHash("md5").update(__require("path").resolve(dir)).digest("hex").slice(0, 8);
10247
10399
  return `${cliType}_${hash}`;
10248
10400
  }
10401
+ getSessionPresentationMode(sessionId) {
10402
+ if (!sessionId) return null;
10403
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
10404
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
10405
+ return mode === "chat" || mode === "terminal" ? mode : null;
10406
+ }
10407
+ isTerminalSession(sessionId) {
10408
+ return this.getSessionPresentationMode(sessionId) === "terminal";
10409
+ }
10249
10410
  persistRecentActivity(entry) {
10250
10411
  try {
10251
10412
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -10301,12 +10462,12 @@ var DaemonCliManager = class {
10301
10462
  }
10302
10463
  }, 3e3);
10303
10464
  }
10304
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
10465
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
10305
10466
  const instanceManager = this.deps.getInstanceManager();
10306
10467
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
10307
10468
  if (!instanceManager) throw new Error("InstanceManager not available");
10308
10469
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
10309
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
10470
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
10310
10471
  try {
10311
10472
  await instanceManager.addInstance(key, cliInstance, {
10312
10473
  serverConn: this.deps.getServerConn(),
@@ -10332,7 +10493,7 @@ var DaemonCliManager = class {
10332
10493
  this.startCliExitMonitor(key, cliType);
10333
10494
  }
10334
10495
  // ─── Session start/management ──────────────────────────────
10335
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
10496
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
10336
10497
  const trimmed = (workingDir || "").trim();
10337
10498
  if (!trimmed) throw new Error("working directory required");
10338
10499
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -10424,29 +10585,7 @@ ${installInfo}`
10424
10585
  if (provider) {
10425
10586
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
10426
10587
  }
10427
- let resolvedCliArgs = cliArgs;
10428
- let resolvedLaunchMode = launchMode;
10429
- const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
10430
- if (activeMode) {
10431
- resolvedLaunchMode = activeMode.id;
10432
- }
10433
- if (provider?.launchArgBuilder) {
10434
- const defaults = {};
10435
- for (const opt of provider.launchOptions || []) {
10436
- if (opt.default !== void 0) defaults[opt.id] = opt.default;
10437
- }
10438
- const modeOptions = activeMode?.options || {};
10439
- const userOptions = launchOptionValues || {};
10440
- const merged = { ...defaults, ...modeOptions, ...userOptions };
10441
- const extraArgs = provider.launchArgBuilder(merged);
10442
- if (extraArgs.length) {
10443
- resolvedCliArgs = [...cliArgs || [], ...extraArgs];
10444
- console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
10445
- }
10446
- } else if (activeMode?.extraArgs?.length) {
10447
- resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
10448
- console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
10449
- }
10588
+ const resolvedCliArgs = cliArgs;
10450
10589
  const instanceManager = this.deps.getInstanceManager();
10451
10590
  if (provider && instanceManager) {
10452
10591
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -10458,8 +10597,7 @@ ${installInfo}`
10458
10597
  resolvedCliArgs,
10459
10598
  resolvedProvider,
10460
10599
  {},
10461
- false,
10462
- resolvedLaunchMode
10600
+ false
10463
10601
  );
10464
10602
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
10465
10603
  } else {
@@ -10571,8 +10709,7 @@ ${installInfo}`
10571
10709
  record.cliArgs,
10572
10710
  resolvedProvider,
10573
10711
  {},
10574
- true,
10575
- record.launchMode
10712
+ true
10576
10713
  );
10577
10714
  restored += 1;
10578
10715
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record.runtimeKey || record.runtimeId} (${record.displayName || record.workspace})`);
@@ -10614,6 +10751,14 @@ ${installInfo}`
10614
10751
  }
10615
10752
  return null;
10616
10753
  }
10754
+ findAdapterBySessionId(instanceKey) {
10755
+ if (!instanceKey) return null;
10756
+ let ik = instanceKey;
10757
+ const colonIdx = ik.lastIndexOf(":");
10758
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
10759
+ const adapter = this.adapters.get(ik);
10760
+ return adapter ? { adapter, key: ik } : null;
10761
+ }
10617
10762
  // ─── CLI command handling ────────────────────────────
10618
10763
  async handleCliCommand(cmd, args) {
10619
10764
  switch (cmd) {
@@ -10642,7 +10787,7 @@ ${installInfo}`
10642
10787
  const dir = resolved.path;
10643
10788
  const launchSource = resolved.source;
10644
10789
  if (!cliType) throw new Error("cliType required");
10645
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
10790
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
10646
10791
  let newKey = null;
10647
10792
  for (const [k, adapter] of this.adapters) {
10648
10793
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -10664,6 +10809,23 @@ ${installInfo}`
10664
10809
  }
10665
10810
  return { success: true, cliType, dir, stopped: true, mode };
10666
10811
  }
10812
+ case "set_cli_view_mode": {
10813
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
10814
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
10815
+ const cliType = args?.cliType || args?.agentType || "";
10816
+ const dir = args?.dir || "";
10817
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
10818
+ if (!found) {
10819
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
10820
+ }
10821
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
10822
+ if (!(instance instanceof CliProviderInstance)) {
10823
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
10824
+ }
10825
+ instance.setPresentationMode(mode);
10826
+ this.deps.onStatusChange();
10827
+ return { success: true, id: found.key, mode };
10828
+ }
10667
10829
  case "restart_session": {
10668
10830
  const cliType = args?.cliType || args?.agentType || args?.ideType;
10669
10831
  const cfg = loadConfig();
@@ -11282,7 +11444,12 @@ var AgentStreamPoller = class {
11282
11444
  } catch {
11283
11445
  }
11284
11446
  }
11285
- if (!resolvedActiveSessionId || !parentSessionId) continue;
11447
+ if (!resolvedActiveSessionId || !parentSessionId) {
11448
+ if (parentSessionId) {
11449
+ this.deps.onStreamsUpdated?.(ideType, []);
11450
+ }
11451
+ continue;
11452
+ }
11286
11453
  try {
11287
11454
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
11288
11455
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -11297,7 +11464,11 @@ var AgentStreamPoller = class {
11297
11464
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11298
11465
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
11299
11466
  if (!ideInstance?.onEvent) return;
11467
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
11300
11468
  for (const stream of streams) {
11469
+ if (typeof stream.agentType === "string" && stream.agentType) {
11470
+ seenExtensionTypes.add(stream.agentType);
11471
+ }
11301
11472
  ideInstance.onEvent("stream_update", {
11302
11473
  extensionType: stream.agentType,
11303
11474
  streams: [stream],
@@ -11314,6 +11485,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11314
11485
  inputContent: stream.inputContent || ""
11315
11486
  });
11316
11487
  }
11488
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
11489
+ if (streams.length === 0) {
11490
+ ideInstance.onEvent("stream_reset_all");
11491
+ return;
11492
+ }
11493
+ for (const extensionType of extensionTypes) {
11494
+ if (!seenExtensionTypes.has(extensionType)) {
11495
+ ideInstance.onEvent("stream_reset", { extensionType });
11496
+ }
11497
+ }
11317
11498
  }
11318
11499
 
11319
11500
  // src/providers/provider-instance-manager.ts
@@ -15716,6 +15897,7 @@ var SessionHostRuntimeTransport = class {
15716
15897
  this.ready = this.boot();
15717
15898
  }
15718
15899
  ready;
15900
+ terminalQueriesHandled = true;
15719
15901
  client;
15720
15902
  dataCallbacks = /* @__PURE__ */ new Set();
15721
15903
  exitCallbacks = /* @__PURE__ */ new Set();