@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.js CHANGED
@@ -33,7 +33,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
33
33
  // src/config/config.ts
34
34
  var config_exports = {};
35
35
  __export(config_exports, {
36
- generateConnectionToken: () => generateConnectionToken,
37
36
  generateMachineId: () => generateMachineId,
38
37
  getConfigDir: () => getConfigDir,
39
38
  isSetupComplete: () => isSetupComplete,
@@ -44,6 +43,57 @@ __export(config_exports, {
44
43
  saveConfig: () => saveConfig,
45
44
  updateConfig: () => updateConfig
46
45
  });
46
+ function isPlainObject(value) {
47
+ return !!value && typeof value === "object" && !Array.isArray(value);
48
+ }
49
+ function asStringArray(value) {
50
+ if (!Array.isArray(value)) return [];
51
+ return value.filter((item) => typeof item === "string");
52
+ }
53
+ function asNullableString(value) {
54
+ return typeof value === "string" ? value : null;
55
+ }
56
+ function asOptionalString(value) {
57
+ return typeof value === "string" && value.trim() ? value : void 0;
58
+ }
59
+ function asBoolean(value, fallback) {
60
+ return typeof value === "boolean" ? value : fallback;
61
+ }
62
+ function normalizeConfig(raw) {
63
+ const parsed = isPlainObject(raw) ? raw : {};
64
+ const legacySessionReads = isPlainObject(parsed.recentSessionReads) ? parsed.recentSessionReads : {};
65
+ const sessionReads = isPlainObject(parsed.sessionReads) ? parsed.sessionReads : {};
66
+ const mergedSessionReads = Object.fromEntries(
67
+ Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
68
+ );
69
+ const sessionReadMarkers = Object.fromEntries(
70
+ Object.entries(isPlainObject(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
71
+ );
72
+ return {
73
+ serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
74
+ selectedIde: asNullableString(parsed.selectedIde),
75
+ configuredIdes: asStringArray(parsed.configuredIdes),
76
+ installedExtensions: asStringArray(parsed.installedExtensions),
77
+ userEmail: asNullableString(parsed.userEmail),
78
+ userName: asNullableString(parsed.userName),
79
+ setupCompleted: asBoolean(parsed.setupCompleted, DEFAULT_CONFIG.setupCompleted),
80
+ setupDate: asNullableString(parsed.setupDate),
81
+ enabledIdes: asStringArray(parsed.enabledIdes),
82
+ workspaces: Array.isArray(parsed.workspaces) ? parsed.workspaces : [],
83
+ defaultWorkspaceId: asNullableString(parsed.defaultWorkspaceId) ?? asNullableString(parsed.activeWorkspaceId),
84
+ recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
85
+ sessionReads: mergedSessionReads,
86
+ sessionReadMarkers,
87
+ machineNickname: asNullableString(parsed.machineNickname),
88
+ machineId: asOptionalString(parsed.machineId),
89
+ machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
90
+ registeredMachineId: asOptionalString(parsed.registeredMachineId),
91
+ providerSettings: isPlainObject(parsed.providerSettings) ? parsed.providerSettings : {},
92
+ ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
93
+ disableUpstream: asBoolean(parsed.disableUpstream, DEFAULT_CONFIG.disableUpstream ?? false),
94
+ providerDir: asOptionalString(parsed.providerDir)
95
+ };
96
+ }
47
97
  function generateMachineId() {
48
98
  return `${MACHINE_ID_PREFIX}${(0, import_crypto.randomUUID)().replace(/-/g, "")}`;
49
99
  }
@@ -87,14 +137,10 @@ function loadConfig() {
87
137
  try {
88
138
  const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
89
139
  const parsed = JSON.parse(raw);
90
- const merged = { ...DEFAULT_CONFIG, ...parsed };
91
- if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
92
- merged.defaultWorkspaceId = merged.activeWorkspaceId;
93
- }
94
- delete merged.activeWorkspaceId;
95
- const ensured = ensureMachineId(merged);
140
+ const normalizedInput = normalizeConfig(parsed);
141
+ const ensured = ensureMachineId(normalizedInput);
96
142
  const normalized = ensured.config;
97
- if (ensured.changed) {
143
+ if (ensured.changed || JSON.stringify(parsed) !== JSON.stringify(normalized)) {
98
144
  try {
99
145
  saveConfig(normalized);
100
146
  } catch {
@@ -109,10 +155,11 @@ function loadConfig() {
109
155
  function saveConfig(config) {
110
156
  const configPath = getConfigPath();
111
157
  const dir = getConfigDir();
158
+ const normalized = normalizeConfig(config);
112
159
  if (!(0, import_fs.existsSync)(dir)) {
113
160
  (0, import_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
114
161
  }
115
- (0, import_fs.writeFileSync)(configPath, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
162
+ (0, import_fs.writeFileSync)(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
116
163
  try {
117
164
  (0, import_fs.chmodSync)(configPath, 384);
118
165
  } catch {
@@ -141,14 +188,6 @@ function isSetupComplete() {
141
188
  function resetConfig() {
142
189
  saveConfig({ ...DEFAULT_CONFIG });
143
190
  }
144
- function generateConnectionToken() {
145
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
146
- let token = "db_";
147
- for (let i = 0; i < 32; i++) {
148
- token += chars.charAt(Math.floor(Math.random() * chars.length));
149
- }
150
- return token;
151
- }
152
191
  var import_os, import_path, import_fs, import_crypto, DEFAULT_CONFIG, MACHINE_ID_PREFIX;
153
192
  var init_config = __esm({
154
193
  "src/config/config.ts"() {
@@ -159,18 +198,13 @@ var init_config = __esm({
159
198
  import_crypto = require("crypto");
160
199
  DEFAULT_CONFIG = {
161
200
  serverUrl: "https://api.adhf.dev",
162
- apiToken: null,
163
- connectionToken: null,
164
201
  selectedIde: null,
165
202
  configuredIdes: [],
166
203
  installedExtensions: [],
167
- autoConnect: true,
168
- notifications: true,
169
204
  userEmail: null,
170
205
  userName: null,
171
206
  setupCompleted: false,
172
207
  setupDate: null,
173
- configuredCLIs: [],
174
208
  enabledIdes: [],
175
209
  workspaces: [],
176
210
  defaultWorkspaceId: null,
@@ -486,6 +520,9 @@ var init_ghostty_vt_backend = __esm({
486
520
  getText() {
487
521
  return this.terminal.formatPlainText({ trim: true }) || "";
488
522
  }
523
+ getCursorPosition() {
524
+ return this.terminal.getCursorPosition();
525
+ }
489
526
  dispose() {
490
527
  this.terminal.dispose();
491
528
  }
@@ -543,6 +580,13 @@ var init_xterm_backend = __esm({
543
580
  while (last > first && !lines[last - 1]?.trim()) last--;
544
581
  return lines.slice(first, last).join("\n");
545
582
  }
583
+ getCursorPosition() {
584
+ const buffer = this.terminal.buffer.active;
585
+ return {
586
+ col: Math.max(0, buffer.cursorX || 0),
587
+ row: Math.max(0, buffer.cursorY || 0)
588
+ };
589
+ }
546
590
  dispose() {
547
591
  this.terminal.dispose();
548
592
  }
@@ -629,6 +673,9 @@ var init_terminal_screen = __esm({
629
673
  getText() {
630
674
  return this.terminal.getText();
631
675
  }
676
+ getCursorPosition() {
677
+ return this.terminal.getCursorPosition();
678
+ }
632
679
  dispose() {
633
680
  this.terminal.dispose();
634
681
  }
@@ -659,6 +706,7 @@ var init_pty_transport = __esm({
659
706
  this.handle = handle;
660
707
  }
661
708
  ready = Promise.resolve();
709
+ terminalQueriesHandled = false;
662
710
  get pid() {
663
711
  return this.handle.pid;
664
712
  }
@@ -712,6 +760,32 @@ function stripTerminalNoise(str) {
712
760
  function sanitizeTerminalText(str) {
713
761
  return stripTerminalNoise(stripAnsi(str));
714
762
  }
763
+ function buildCliSpawnEnv(baseEnv, overrides) {
764
+ const env = {};
765
+ const source = { ...baseEnv, ...overrides || {} };
766
+ for (const [key, value] of Object.entries(source)) {
767
+ if (typeof value !== "string") continue;
768
+ env[key] = value;
769
+ }
770
+ for (const key of Object.keys(env)) {
771
+ 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_")) {
772
+ delete env[key];
773
+ }
774
+ }
775
+ return env;
776
+ }
777
+ function computeTerminalQueryTail(buffer) {
778
+ const prefixes = ["\x1B[6n", "\x1B[?6n"];
779
+ const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
780
+ const start = Math.max(0, buffer.length - maxLength);
781
+ for (let i = start; i < buffer.length; i++) {
782
+ const suffix = buffer.slice(i);
783
+ if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
784
+ return suffix;
785
+ }
786
+ }
787
+ return "";
788
+ }
715
789
  function findBinary(name) {
716
790
  const isWin = os12.platform() === "win32";
717
791
  try {
@@ -798,36 +872,6 @@ function promptLikelyVisible(screenText, promptSnippet) {
798
872
  ).length;
799
873
  return matched >= required;
800
874
  }
801
- function splitHistoryLines(text) {
802
- return String(text || "").split("\n").map((line) => line.replace(/\s+$/, ""));
803
- }
804
- function normalizeHistoryLine(line) {
805
- return String(line || "").replace(/\s+/g, " ").trim();
806
- }
807
- function mergeTerminalHistory(existing, snapshot) {
808
- const next = String(snapshot || "").trim();
809
- if (!next) return existing;
810
- const prev = String(existing || "").trim();
811
- if (!prev) return next;
812
- if (prev === next || prev.endsWith(next)) return prev;
813
- const prevLines = splitHistoryLines(prev);
814
- const nextLines = splitHistoryLines(next);
815
- const prevNorm = prevLines.map(normalizeHistoryLine);
816
- const nextNorm = nextLines.map(normalizeHistoryLine);
817
- const maxOverlap = Math.min(prevLines.length, nextLines.length);
818
- for (let overlap = maxOverlap; overlap >= 1; overlap -= 1) {
819
- const prevTail = prevNorm.slice(prevNorm.length - overlap);
820
- const nextHead = nextNorm.slice(0, overlap);
821
- if (prevTail.every((line, index) => line === nextHead[index])) {
822
- return [...prevLines, ...nextLines.slice(overlap)].join("\n").trim();
823
- }
824
- }
825
- const compactPrev = prevNorm.join("\n");
826
- const compactNext = nextNorm.join("\n");
827
- if (compactPrev.includes(compactNext)) return prev;
828
- return `${prev}
829
- ${next}`.trim();
830
- }
831
875
  function parsePatternEntry(x) {
832
876
  if (x instanceof RegExp) return x;
833
877
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -942,6 +986,7 @@ var init_provider_cli_adapter = __esm({
942
986
  pendingOutputParseTimer = null;
943
987
  ptyOutputBuffer = "";
944
988
  ptyOutputFlushTimer = null;
989
+ pendingTerminalQueryTail = "";
945
990
  // Server log forwarding
946
991
  serverConn = null;
947
992
  logBuffer = [];
@@ -973,9 +1018,7 @@ var init_provider_cli_adapter = __esm({
973
1018
  /** Full accumulated raw PTY output (with ANSI) */
974
1019
  accumulatedRawBuffer = "";
975
1020
  /** Current visible terminal screen snapshot */
976
- terminalScreen = new TerminalScreen(40, 120);
977
- /** Rolling append-only terminal transcript built from screen snapshots */
978
- terminalHistory = "";
1021
+ terminalScreen = new TerminalScreen(30, 100);
979
1022
  /** Max accumulated buffer size (last 50KB) */
980
1023
  static MAX_ACCUMULATED_BUFFER = 5e4;
981
1024
  currentTurnScope = null;
@@ -983,6 +1026,13 @@ var init_provider_cli_adapter = __esm({
983
1026
  this.messages = [...this.committedMessages];
984
1027
  this.structuredMessages = [...this.committedMessages];
985
1028
  }
1029
+ normalizeParsedMessages(parsedMessages) {
1030
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
1031
+ role: message.role,
1032
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
1033
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
1034
+ }));
1035
+ }
986
1036
  sliceFromOffset(text, start) {
987
1037
  if (!text) return "";
988
1038
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -990,15 +1040,13 @@ var init_provider_cli_adapter = __esm({
990
1040
  return text.slice(start);
991
1041
  }
992
1042
  buildParseInput(baseMessages, partialResponse, scope) {
993
- const buffer = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
1043
+ const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
994
1044
  const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
995
- const terminalHistory = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.terminalHistory : this.terminalHistory;
996
1045
  return {
997
1046
  buffer,
998
1047
  rawBuffer,
999
1048
  recentBuffer: buffer.slice(-1e3) || this.recentOutputBuffer,
1000
1049
  screenText: this.terminalScreen.getText(),
1001
- terminalHistory,
1002
1050
  messages: [...baseMessages],
1003
1051
  partialResponse
1004
1052
  };
@@ -1076,13 +1124,10 @@ var init_provider_cli_adapter = __esm({
1076
1124
  shellArgs = allArgs;
1077
1125
  }
1078
1126
  const ptyOpts = {
1079
- cols: 120,
1080
- rows: 40,
1127
+ cols: 100,
1128
+ rows: 30,
1081
1129
  cwd: this.workingDir,
1082
- env: {
1083
- ...process.env,
1084
- ...spawnConfig.env
1085
- }
1130
+ env: buildCliSpawnEnv(process.env, spawnConfig.env)
1086
1131
  };
1087
1132
  try {
1088
1133
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
@@ -1100,8 +1145,8 @@ var init_provider_cli_adapter = __esm({
1100
1145
  }
1101
1146
  this.ptyProcess.onData((data) => {
1102
1147
  if (Date.now() < this.resizeSuppressUntil) return;
1103
- if (data.includes("\x1B[6n") || data.includes("\x1B[?6n")) {
1104
- this.ptyProcess?.write("\x1B[1;1R");
1148
+ if (!this.ptyProcess?.terminalQueriesHandled) {
1149
+ this.respondToTerminalQueries(data);
1105
1150
  }
1106
1151
  this.pendingOutputParseBuffer += data;
1107
1152
  if (!this.pendingOutputParseTimer) {
@@ -1136,8 +1181,8 @@ var init_provider_cli_adapter = __esm({
1136
1181
  this.spawnAt = Date.now();
1137
1182
  this.startupParseGate = true;
1138
1183
  this.startupBuffer = "";
1139
- this.terminalScreen.reset(40, 120);
1140
- this.terminalHistory = "";
1184
+ this.terminalScreen.reset(30, 100);
1185
+ this.pendingTerminalQueryTail = "";
1141
1186
  this.currentTurnScope = null;
1142
1187
  this.ready = false;
1143
1188
  await this.ptyProcess.ready;
@@ -1147,7 +1192,6 @@ var init_provider_cli_adapter = __esm({
1147
1192
  // ─── Output Handling ────────────────────────────
1148
1193
  handleOutput(rawData) {
1149
1194
  this.terminalScreen.write(rawData);
1150
- this.terminalHistory = mergeTerminalHistory(this.terminalHistory, this.terminalScreen.getText());
1151
1195
  const cleanData = sanitizeTerminalText(rawData);
1152
1196
  if (this.isWaitingForResponse && cleanData) {
1153
1197
  this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
@@ -1379,6 +1423,15 @@ var init_provider_cli_adapter = __esm({
1379
1423
  this.onStatusChange?.();
1380
1424
  }
1381
1425
  commitCurrentTranscript() {
1426
+ const parsed = this.parseCurrentTranscript(
1427
+ this.committedMessages,
1428
+ this.responseBuffer,
1429
+ this.currentTurnScope
1430
+ );
1431
+ if (parsed && Array.isArray(parsed.messages)) {
1432
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
1433
+ this.syncMessageViews();
1434
+ }
1382
1435
  }
1383
1436
  // ─── Script Execution ──────────────────────────
1384
1437
  runDetectStatus(text) {
@@ -1414,8 +1467,7 @@ var init_provider_cli_adapter = __esm({
1414
1467
  status: this.currentStatus,
1415
1468
  messages: [...this.committedMessages],
1416
1469
  workingDir: this.workingDir,
1417
- activeModal: this.activeModal,
1418
- terminalHistory: this.terminalHistory
1470
+ activeModal: this.activeModal
1419
1471
  };
1420
1472
  }
1421
1473
  /**
@@ -1423,12 +1475,25 @@ var init_provider_cli_adapter = __esm({
1423
1475
  * Called by command handler / dashboard for rich content rendering.
1424
1476
  */
1425
1477
  getScriptParsedStatus() {
1478
+ const parsed = this.parseCurrentTranscript(
1479
+ this.committedMessages,
1480
+ this.responseBuffer,
1481
+ this.currentTurnScope
1482
+ );
1483
+ if (parsed && Array.isArray(parsed.messages)) {
1484
+ return {
1485
+ id: parsed.id || "cli_session",
1486
+ status: parsed.status || this.currentStatus,
1487
+ title: parsed.title || this.cliName,
1488
+ messages: parsed.messages,
1489
+ activeModal: parsed.activeModal ?? this.activeModal
1490
+ };
1491
+ }
1426
1492
  const messages = [...this.committedMessages];
1427
1493
  return {
1428
1494
  id: "cli_session",
1429
1495
  status: this.currentStatus,
1430
1496
  title: this.cliName,
1431
- terminalHistory: this.terminalHistory,
1432
1497
  messages: messages.slice(-50).map((message, index) => ({
1433
1498
  id: `msg_${index}`,
1434
1499
  role: message.role,
@@ -1496,10 +1561,9 @@ ${data.message || ""}`.trim();
1496
1561
  prompt: text,
1497
1562
  startedAt: Date.now(),
1498
1563
  bufferStart: this.accumulatedBuffer.length,
1499
- rawBufferStart: this.accumulatedRawBuffer.length,
1500
- terminalHistoryStart: this.terminalHistory.length
1564
+ rawBufferStart: this.accumulatedRawBuffer.length
1501
1565
  };
1502
- 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)}`);
1566
+ LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
1503
1567
  this.submitRetryUsed = false;
1504
1568
  this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
1505
1569
  const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
@@ -1684,6 +1748,7 @@ ${data.message || ""}`.trim();
1684
1748
  this.pendingOutputParseTimer = null;
1685
1749
  }
1686
1750
  this.pendingOutputParseBuffer = "";
1751
+ this.pendingTerminalQueryTail = "";
1687
1752
  if (this.ptyOutputFlushTimer) {
1688
1753
  clearTimeout(this.ptyOutputFlushTimer);
1689
1754
  this.ptyOutputFlushTimer = null;
@@ -1723,6 +1788,7 @@ ${data.message || ""}`.trim();
1723
1788
  this.pendingOutputParseTimer = null;
1724
1789
  }
1725
1790
  this.pendingOutputParseBuffer = "";
1791
+ this.pendingTerminalQueryTail = "";
1726
1792
  if (this.ptyOutputFlushTimer) {
1727
1793
  clearTimeout(this.ptyOutputFlushTimer);
1728
1794
  this.ptyOutputFlushTimer = null;
@@ -1749,7 +1815,6 @@ ${data.message || ""}`.trim();
1749
1815
  this.syncMessageViews();
1750
1816
  this.accumulatedBuffer = "";
1751
1817
  this.accumulatedRawBuffer = "";
1752
- this.terminalHistory = "";
1753
1818
  this.currentTurnScope = null;
1754
1819
  this.submitRetryUsed = false;
1755
1820
  this.submitRetryPromptSnippet = "";
@@ -1758,6 +1823,7 @@ ${data.message || ""}`.trim();
1758
1823
  this.pendingOutputParseTimer = null;
1759
1824
  }
1760
1825
  this.pendingOutputParseBuffer = "";
1826
+ this.pendingTerminalQueryTail = "";
1761
1827
  if (this.ptyOutputFlushTimer) {
1762
1828
  clearTimeout(this.ptyOutputFlushTimer);
1763
1829
  this.ptyOutputFlushTimer = null;
@@ -1819,7 +1885,6 @@ ${data.message || ""}`.trim();
1819
1885
  structuredMessages: this.structuredMessages.slice(-20),
1820
1886
  messageCount: this.committedMessages.length,
1821
1887
  screenText: sanitizeTerminalText(this.terminalScreen.getText()).slice(-4e3),
1822
- terminalHistory: this.terminalHistory.slice(-8e3),
1823
1888
  currentTurnScope: this.currentTurnScope,
1824
1889
  startupBuffer: this.startupBuffer.slice(-4e3),
1825
1890
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
@@ -1847,6 +1912,20 @@ ${data.message || ""}`.trim();
1847
1912
  ptyAlive: !!this.ptyProcess
1848
1913
  };
1849
1914
  }
1915
+ respondToTerminalQueries(data) {
1916
+ if (!this.ptyProcess || !data) return;
1917
+ const combined = this.pendingTerminalQueryTail + data;
1918
+ const regex = /\x1b\[(\?)?6n/g;
1919
+ let match;
1920
+ while ((match = regex.exec(combined)) !== null) {
1921
+ const cursor = this.terminalScreen.getCursorPosition();
1922
+ const row = Math.max(1, (cursor.row | 0) + 1);
1923
+ const col = Math.max(1, (cursor.col | 0) + 1);
1924
+ const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
1925
+ this.ptyProcess.write(response);
1926
+ }
1927
+ this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
1928
+ }
1850
1929
  };
1851
1930
  }
1852
1931
  });
@@ -3823,6 +3902,8 @@ var ExtensionProviderInstance = class {
3823
3902
  this.detectTransition(newStatus, data);
3824
3903
  this.currentStatus = newStatus;
3825
3904
  }
3905
+ } else if (event === "stream_reset") {
3906
+ this.resetStreamState();
3826
3907
  } else if (event === "extension_connected") {
3827
3908
  this.ideType = data?.ideType || "";
3828
3909
  }
@@ -3902,6 +3983,30 @@ var ExtensionProviderInstance = class {
3902
3983
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
3903
3984
  return title || this.agentName || this.provider.name;
3904
3985
  }
3986
+ resetStreamState() {
3987
+ if (this.currentStatus !== "idle") {
3988
+ this.detectTransition("idle", {
3989
+ title: this.chatTitle,
3990
+ agentName: this.agentName,
3991
+ extensionId: this.extensionId,
3992
+ messages: this.messages
3993
+ });
3994
+ }
3995
+ this.agentStreams = [];
3996
+ this.messages = [];
3997
+ this.activeModal = null;
3998
+ this.currentModel = "";
3999
+ this.currentMode = "";
4000
+ this.controlValues = {};
4001
+ this.currentStatus = "idle";
4002
+ this.chatId = null;
4003
+ this.chatTitle = null;
4004
+ this.agentName = "";
4005
+ this.extensionId = "";
4006
+ this.lastAgentStatus = "idle";
4007
+ this.generatingStartedAt = 0;
4008
+ this.monitor.reset();
4009
+ }
3905
4010
  };
3906
4011
 
3907
4012
  // src/config/chat-history.ts
@@ -3915,8 +4020,6 @@ var ChatHistoryWriter = class {
3915
4020
  lastSeenCounts = /* @__PURE__ */ new Map();
3916
4021
  /** Last seen message hash per agent (deduplication) */
3917
4022
  lastSeenHashes = /* @__PURE__ */ new Map();
3918
- /** Last seen append-only terminal transcript per agent */
3919
- lastSeenTerminal = /* @__PURE__ */ new Map();
3920
4023
  rotated = false;
3921
4024
  /**
3922
4025
  * Append new messages to history
@@ -3974,51 +4077,10 @@ var ChatHistoryWriter = class {
3974
4077
  } catch {
3975
4078
  }
3976
4079
  }
3977
- appendTerminalHistory(agentType, terminalHistory, sessionTitle, instanceId) {
3978
- const next = String(terminalHistory || "");
3979
- if (!next.trim()) return;
3980
- try {
3981
- const dedupKey = instanceId ? `${agentType}:${instanceId}:terminal` : `${agentType}:terminal`;
3982
- const prev = this.lastSeenTerminal.get(dedupKey) || "";
3983
- if (prev === next) return;
3984
- let delta = "";
3985
- if (!prev) {
3986
- delta = next;
3987
- } else if (next.startsWith(prev)) {
3988
- delta = next.slice(prev.length);
3989
- } else if (prev.includes(next)) {
3990
- this.lastSeenTerminal.set(dedupKey, next);
3991
- return;
3992
- } else {
3993
- delta = `
3994
-
3995
- [terminal snapshot reset ${(/* @__PURE__ */ new Date()).toISOString()} | ${sessionTitle || agentType}]
3996
- ${next}`;
3997
- }
3998
- if (!delta) {
3999
- this.lastSeenTerminal.set(dedupKey, next);
4000
- return;
4001
- }
4002
- const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
4003
- fs3.mkdirSync(dir, { recursive: true });
4004
- const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4005
- const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
4006
- const filePath = path4.join(dir, `${filePrefix}${date}.terminal.log`);
4007
- fs3.appendFileSync(filePath, delta, "utf-8");
4008
- this.lastSeenTerminal.set(dedupKey, next);
4009
- if (!this.rotated) {
4010
- this.rotated = true;
4011
- this.rotateOldFiles().catch(() => {
4012
- });
4013
- }
4014
- } catch {
4015
- }
4016
- }
4017
4080
  /** Called when agent session is explicitly changed */
4018
4081
  onSessionChange(agentType) {
4019
4082
  this.lastSeenHashes.delete(agentType);
4020
4083
  this.lastSeenCounts.delete(agentType);
4021
- this.lastSeenTerminal.delete(`${agentType}:terminal`);
4022
4084
  }
4023
4085
  /** Delete history files older than 30 days */
4024
4086
  async rotateOldFiles() {
@@ -4184,11 +4246,23 @@ var IdeProviderInstance = class {
4184
4246
  } else if (event === "cdp_disconnected") {
4185
4247
  this.cachedChat = null;
4186
4248
  this.currentStatus = "idle";
4249
+ for (const ext of this.extensions.values()) {
4250
+ ext.onEvent("stream_reset");
4251
+ }
4187
4252
  } else if (event === "stream_update") {
4188
4253
  const extType = data?.extensionType;
4189
4254
  if (extType && this.extensions.has(extType)) {
4190
4255
  this.extensions.get(extType).onEvent("stream_update", data);
4191
4256
  }
4257
+ } else if (event === "stream_reset") {
4258
+ const extType = data?.extensionType;
4259
+ if (extType && this.extensions.has(extType)) {
4260
+ this.extensions.get(extType).onEvent("stream_reset");
4261
+ }
4262
+ } else if (event === "stream_reset_all") {
4263
+ for (const ext of this.extensions.values()) {
4264
+ ext.onEvent("stream_reset");
4265
+ }
4192
4266
  }
4193
4267
  }
4194
4268
  dispose() {
@@ -4855,6 +4929,57 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
4855
4929
  "thinking",
4856
4930
  "active"
4857
4931
  ]);
4932
+ var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
4933
+ var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
4934
+ var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
4935
+ var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
4936
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
4937
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
4938
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
4939
+ function truncateString(value, maxChars) {
4940
+ if (value.length <= maxChars) return value;
4941
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
4942
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
4943
+ }
4944
+ function trimStructuredStrings(value, maxChars) {
4945
+ if (typeof value === "string") return truncateString(value, maxChars);
4946
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
4947
+ if (!value || typeof value !== "object") return value;
4948
+ return Object.fromEntries(
4949
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
4950
+ );
4951
+ }
4952
+ function estimateBytes(value) {
4953
+ try {
4954
+ return JSON.stringify(value).length;
4955
+ } catch {
4956
+ return String(value ?? "").length;
4957
+ }
4958
+ }
4959
+ function trimMessageForStatus(message, stringLimit) {
4960
+ if (!message || typeof message !== "object") return message;
4961
+ return trimStructuredStrings(message, stringLimit);
4962
+ }
4963
+ function trimMessagesForStatus(messages) {
4964
+ if (!Array.isArray(messages) || messages.length === 0) return [];
4965
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
4966
+ const kept = [];
4967
+ let totalBytes = 0;
4968
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
4969
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
4970
+ let size = estimateBytes(normalized);
4971
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
4972
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
4973
+ size = estimateBytes(normalized);
4974
+ }
4975
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
4976
+ continue;
4977
+ }
4978
+ kept.push(normalized);
4979
+ totalBytes += size;
4980
+ }
4981
+ return kept.reverse();
4982
+ }
4858
4983
  function hasApprovalButtons(activeModal) {
4859
4984
  return (activeModal?.buttons?.length ?? 0) > 0;
4860
4985
  }
@@ -4881,7 +5006,15 @@ function normalizeActiveChatData(activeChat) {
4881
5006
  if (!activeChat) return activeChat;
4882
5007
  return {
4883
5008
  ...activeChat,
4884
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
5009
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
5010
+ messages: trimMessagesForStatus(activeChat.messages),
5011
+ activeModal: activeChat.activeModal ? {
5012
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
5013
+ buttons: (activeChat.activeModal.buttons || []).map(
5014
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
5015
+ )
5016
+ } : activeChat.activeModal,
5017
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
4885
5018
  };
4886
5019
  }
4887
5020
 
@@ -4979,6 +5112,11 @@ var PTY_SESSION_CAPABILITIES = [
4979
5112
  "terminal_io",
4980
5113
  "resize_terminal"
4981
5114
  ];
5115
+ var CLI_CHAT_SESSION_CAPABILITIES = [
5116
+ "read_chat",
5117
+ "send_message",
5118
+ "resolve_action"
5119
+ ];
4982
5120
  var ACP_SESSION_CAPABILITIES = [
4983
5121
  "read_chat",
4984
5122
  "send_message",
@@ -5068,11 +5206,10 @@ function buildCliSession(state) {
5068
5206
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
5069
5207
  runtimeWriteOwner: state.runtime?.writeOwner || null,
5070
5208
  runtimeAttachedClients: state.runtime?.attachedClients || [],
5071
- launchMode: state.launchMode,
5072
5209
  mode: state.mode,
5073
5210
  resume: state.resume,
5074
5211
  activeChat,
5075
- capabilities: PTY_SESSION_CAPABILITIES,
5212
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
5076
5213
  controlValues: state.controlValues,
5077
5214
  providerControls: buildFallbackControls(
5078
5215
  state.providerControls
@@ -6246,6 +6383,13 @@ async function handleFileListBrowse(h, args) {
6246
6383
 
6247
6384
  // src/commands/stream-commands.ts
6248
6385
  init_logger();
6386
+ function getCliPresentationMode(h, targetSessionId) {
6387
+ if (!targetSessionId) return null;
6388
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
6389
+ if (instance?.category !== "cli") return null;
6390
+ const mode = instance.getPresentationMode?.();
6391
+ return mode === "chat" || mode === "terminal" ? mode : null;
6392
+ }
6249
6393
  async function handleFocusSession(h, args) {
6250
6394
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
6251
6395
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -6256,6 +6400,9 @@ async function handleFocusSession(h, args) {
6256
6400
  function handlePtyInput(h, args) {
6257
6401
  const { cliType, data, targetSessionId } = args || {};
6258
6402
  if (!data) return { success: false, error: "data required" };
6403
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6404
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6405
+ }
6259
6406
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6260
6407
  if (!adapter || typeof adapter.writeRaw !== "function") {
6261
6408
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -6266,6 +6413,9 @@ function handlePtyInput(h, args) {
6266
6413
  function handlePtyResize(h, args) {
6267
6414
  const { cliType, cols, rows, force, targetSessionId } = args || {};
6268
6415
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
6416
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6417
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6418
+ }
6269
6419
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6270
6420
  if (!adapter || typeof adapter.resize !== "function") {
6271
6421
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -8673,6 +8823,7 @@ var DaemonCommandRouter = class {
8673
8823
  // ─── CLI / ACP commands ───
8674
8824
  case "launch_cli":
8675
8825
  case "stop_cli":
8826
+ case "set_cli_view_mode":
8676
8827
  case "agent_command": {
8677
8828
  return this.deps.cliManager.handleCliCommand(cmd, args);
8678
8829
  }
@@ -9017,6 +9168,20 @@ var DaemonStatusReporter = class {
9017
9168
  ts() {
9018
9169
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
9019
9170
  }
9171
+ summarizeLargePayloadSessions(payload) {
9172
+ const sessions = Array.isArray(payload.sessions) ? payload.sessions : [];
9173
+ return sessions.map((session) => ({
9174
+ id: String(session?.id || ""),
9175
+ providerType: String(session?.providerType || ""),
9176
+ bytes: (() => {
9177
+ try {
9178
+ return JSON.stringify(session).length;
9179
+ } catch {
9180
+ return 0;
9181
+ }
9182
+ })()
9183
+ })).sort((a, b) => b.bytes - a.bytes).slice(0, 3).map((session) => `${session.providerType || "unknown"}:${session.id}=${session.bytes}b`).join(", ");
9184
+ }
9020
9185
  async sendUnifiedStatusReport(opts) {
9021
9186
  const { serverConn, p2p } = this.deps;
9022
9187
  if (!serverConn?.isConnected()) return;
@@ -9069,9 +9234,16 @@ var DaemonStatusReporter = class {
9069
9234
  screenshotUsage: this.deps.getScreenshotUsage?.() || null,
9070
9235
  connectedExtensions: []
9071
9236
  };
9237
+ const payloadBytes = JSON.stringify(payload).length;
9072
9238
  const p2pSent = this.sendP2PPayload(payload);
9073
9239
  if (p2pSent) {
9074
- LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
9240
+ LOG.debug("P2P", `sent (${payloadBytes} bytes)`);
9241
+ if (payloadBytes > 256 * 1024) {
9242
+ LOG.warn(
9243
+ "P2P",
9244
+ `large status payload (${payloadBytes} bytes) top sessions: ${this.summarizeLargePayloadSessions(payload) || "n/a"}`
9245
+ );
9246
+ }
9075
9247
  }
9076
9248
  if (opts?.p2pOnly) return;
9077
9249
  const wsPayload = {
@@ -9101,7 +9273,9 @@ var DaemonStatusReporter = class {
9101
9273
  acpModes: session.acpModes
9102
9274
  })),
9103
9275
  p2p: payload.p2p,
9104
- timestamp: now
9276
+ timestamp: now,
9277
+ detectedIdes: payload.detectedIdes,
9278
+ availableProviders: payload.availableProviders
9105
9279
  };
9106
9280
  serverConn.sendMessage("status_report", wsPayload);
9107
9281
  LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
@@ -9147,14 +9321,13 @@ var crypto3 = __toESM(require("crypto"));
9147
9321
  init_provider_cli_adapter();
9148
9322
  init_logger();
9149
9323
  var CliProviderInstance = class {
9150
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
9324
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
9151
9325
  this.provider = provider;
9152
9326
  this.workingDir = workingDir;
9153
9327
  this.cliArgs = cliArgs;
9154
9328
  this.type = provider.type;
9155
9329
  this.instanceId = instanceId || crypto3.randomUUID();
9156
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
9157
- this.resolvedOutputFormat = this.resolveOutputFormat();
9330
+ this.presentationMode = "chat";
9158
9331
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
9159
9332
  this.monitor = new StatusMonitor();
9160
9333
  this.historyWriter = new ChatHistoryWriter();
@@ -9173,26 +9346,7 @@ var CliProviderInstance = class {
9173
9346
  lastApprovalEventAt = 0;
9174
9347
  historyWriter;
9175
9348
  instanceId;
9176
- launchMode;
9177
- resolvedOutputFormat;
9178
- /**
9179
- * Determine output rendering format from:
9180
- * 1. launchMode.outputFormat (explicit override)
9181
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
9182
- * 3. Default: 'terminal'
9183
- */
9184
- resolveOutputFormat() {
9185
- if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
9186
- if (this.provider.launchOptions?.length) {
9187
- for (const opt of this.provider.launchOptions) {
9188
- if (!opt.outputFormatMap) continue;
9189
- for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
9190
- if (this.cliArgs.includes(val)) return fmt;
9191
- }
9192
- }
9193
- }
9194
- return "terminal";
9195
- }
9349
+ presentationMode;
9196
9350
  // ─── Lifecycle ─────────────────────────────────
9197
9351
  async init(context) {
9198
9352
  this.context = context;
@@ -9217,30 +9371,21 @@ var CliProviderInstance = class {
9217
9371
  }
9218
9372
  getState() {
9219
9373
  const adapterStatus = this.adapter.getStatus();
9374
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9220
9375
  const runtime = this.adapter.getRuntimeMetadata();
9221
9376
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9222
- if (adapterStatus.terminalHistory?.trim()) {
9223
- this.historyWriter.appendTerminalHistory(
9224
- this.type,
9225
- adapterStatus.terminalHistory,
9226
- `${this.provider.name} \xB7 ${dirName}`,
9227
- this.instanceId
9228
- );
9229
- }
9230
9377
  return {
9231
9378
  type: this.type,
9232
9379
  name: this.provider.name,
9233
9380
  category: "cli",
9234
9381
  status: adapterStatus.status,
9235
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
9236
- launchMode: this.launchMode?.id,
9382
+ mode: this.presentationMode,
9237
9383
  activeChat: {
9238
9384
  id: `${this.type}_${this.workingDir}`,
9239
- title: `${this.provider.name} \xB7 ${dirName}`,
9240
- status: adapterStatus.status,
9241
- messages: [],
9242
- activeModal: adapterStatus.activeModal,
9243
- terminalHistory: adapterStatus.terminalHistory,
9385
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
9386
+ status: parsedStatus?.status || adapterStatus.status,
9387
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
9388
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
9244
9389
  inputContent: ""
9245
9390
  },
9246
9391
  workspace: this.workingDir,
@@ -9262,6 +9407,13 @@ var CliProviderInstance = class {
9262
9407
  providerControls: this.provider.controls
9263
9408
  };
9264
9409
  }
9410
+ setPresentationMode(mode) {
9411
+ if (this.presentationMode === mode) return;
9412
+ this.presentationMode = mode;
9413
+ }
9414
+ getPresentationMode() {
9415
+ return this.presentationMode;
9416
+ }
9265
9417
  onEvent(event, data) {
9266
9418
  if (event === "send_message" && data?.text) {
9267
9419
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -10320,6 +10472,15 @@ var DaemonCliManager = class {
10320
10472
  const hash = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
10321
10473
  return `${cliType}_${hash}`;
10322
10474
  }
10475
+ getSessionPresentationMode(sessionId) {
10476
+ if (!sessionId) return null;
10477
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
10478
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
10479
+ return mode === "chat" || mode === "terminal" ? mode : null;
10480
+ }
10481
+ isTerminalSession(sessionId) {
10482
+ return this.getSessionPresentationMode(sessionId) === "terminal";
10483
+ }
10323
10484
  persistRecentActivity(entry) {
10324
10485
  try {
10325
10486
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -10375,12 +10536,12 @@ var DaemonCliManager = class {
10375
10536
  }
10376
10537
  }, 3e3);
10377
10538
  }
10378
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
10539
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
10379
10540
  const instanceManager = this.deps.getInstanceManager();
10380
10541
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
10381
10542
  if (!instanceManager) throw new Error("InstanceManager not available");
10382
10543
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
10383
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
10544
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
10384
10545
  try {
10385
10546
  await instanceManager.addInstance(key, cliInstance, {
10386
10547
  serverConn: this.deps.getServerConn(),
@@ -10406,7 +10567,7 @@ var DaemonCliManager = class {
10406
10567
  this.startCliExitMonitor(key, cliType);
10407
10568
  }
10408
10569
  // ─── Session start/management ──────────────────────────────
10409
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
10570
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
10410
10571
  const trimmed = (workingDir || "").trim();
10411
10572
  if (!trimmed) throw new Error("working directory required");
10412
10573
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -10498,29 +10659,7 @@ ${installInfo}`
10498
10659
  if (provider) {
10499
10660
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
10500
10661
  }
10501
- let resolvedCliArgs = cliArgs;
10502
- let resolvedLaunchMode = launchMode;
10503
- const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
10504
- if (activeMode) {
10505
- resolvedLaunchMode = activeMode.id;
10506
- }
10507
- if (provider?.launchArgBuilder) {
10508
- const defaults = {};
10509
- for (const opt of provider.launchOptions || []) {
10510
- if (opt.default !== void 0) defaults[opt.id] = opt.default;
10511
- }
10512
- const modeOptions = activeMode?.options || {};
10513
- const userOptions = launchOptionValues || {};
10514
- const merged = { ...defaults, ...modeOptions, ...userOptions };
10515
- const extraArgs = provider.launchArgBuilder(merged);
10516
- if (extraArgs.length) {
10517
- resolvedCliArgs = [...cliArgs || [], ...extraArgs];
10518
- console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
10519
- }
10520
- } else if (activeMode?.extraArgs?.length) {
10521
- resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
10522
- console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
10523
- }
10662
+ const resolvedCliArgs = cliArgs;
10524
10663
  const instanceManager = this.deps.getInstanceManager();
10525
10664
  if (provider && instanceManager) {
10526
10665
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -10532,8 +10671,7 @@ ${installInfo}`
10532
10671
  resolvedCliArgs,
10533
10672
  resolvedProvider,
10534
10673
  {},
10535
- false,
10536
- resolvedLaunchMode
10674
+ false
10537
10675
  );
10538
10676
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
10539
10677
  } else {
@@ -10645,8 +10783,7 @@ ${installInfo}`
10645
10783
  record.cliArgs,
10646
10784
  resolvedProvider,
10647
10785
  {},
10648
- true,
10649
- record.launchMode
10786
+ true
10650
10787
  );
10651
10788
  restored += 1;
10652
10789
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record.runtimeKey || record.runtimeId} (${record.displayName || record.workspace})`);
@@ -10688,6 +10825,14 @@ ${installInfo}`
10688
10825
  }
10689
10826
  return null;
10690
10827
  }
10828
+ findAdapterBySessionId(instanceKey) {
10829
+ if (!instanceKey) return null;
10830
+ let ik = instanceKey;
10831
+ const colonIdx = ik.lastIndexOf(":");
10832
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
10833
+ const adapter = this.adapters.get(ik);
10834
+ return adapter ? { adapter, key: ik } : null;
10835
+ }
10691
10836
  // ─── CLI command handling ────────────────────────────
10692
10837
  async handleCliCommand(cmd, args) {
10693
10838
  switch (cmd) {
@@ -10716,7 +10861,7 @@ ${installInfo}`
10716
10861
  const dir = resolved.path;
10717
10862
  const launchSource = resolved.source;
10718
10863
  if (!cliType) throw new Error("cliType required");
10719
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
10864
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
10720
10865
  let newKey = null;
10721
10866
  for (const [k, adapter] of this.adapters) {
10722
10867
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -10738,6 +10883,23 @@ ${installInfo}`
10738
10883
  }
10739
10884
  return { success: true, cliType, dir, stopped: true, mode };
10740
10885
  }
10886
+ case "set_cli_view_mode": {
10887
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
10888
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
10889
+ const cliType = args?.cliType || args?.agentType || "";
10890
+ const dir = args?.dir || "";
10891
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
10892
+ if (!found) {
10893
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
10894
+ }
10895
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
10896
+ if (!(instance instanceof CliProviderInstance)) {
10897
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
10898
+ }
10899
+ instance.setPresentationMode(mode);
10900
+ this.deps.onStatusChange();
10901
+ return { success: true, id: found.key, mode };
10902
+ }
10741
10903
  case "restart_session": {
10742
10904
  const cliType = args?.cliType || args?.agentType || args?.ideType;
10743
10905
  const cfg = loadConfig();
@@ -11356,7 +11518,12 @@ var AgentStreamPoller = class {
11356
11518
  } catch {
11357
11519
  }
11358
11520
  }
11359
- if (!resolvedActiveSessionId || !parentSessionId) continue;
11521
+ if (!resolvedActiveSessionId || !parentSessionId) {
11522
+ if (parentSessionId) {
11523
+ this.deps.onStreamsUpdated?.(ideType, []);
11524
+ }
11525
+ continue;
11526
+ }
11360
11527
  try {
11361
11528
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
11362
11529
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -11371,7 +11538,11 @@ var AgentStreamPoller = class {
11371
11538
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11372
11539
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
11373
11540
  if (!ideInstance?.onEvent) return;
11541
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
11374
11542
  for (const stream of streams) {
11543
+ if (typeof stream.agentType === "string" && stream.agentType) {
11544
+ seenExtensionTypes.add(stream.agentType);
11545
+ }
11375
11546
  ideInstance.onEvent("stream_update", {
11376
11547
  extensionType: stream.agentType,
11377
11548
  streams: [stream],
@@ -11388,6 +11559,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11388
11559
  inputContent: stream.inputContent || ""
11389
11560
  });
11390
11561
  }
11562
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
11563
+ if (streams.length === 0) {
11564
+ ideInstance.onEvent("stream_reset_all");
11565
+ return;
11566
+ }
11567
+ for (const extensionType of extensionTypes) {
11568
+ if (!seenExtensionTypes.has(extensionType)) {
11569
+ ideInstance.onEvent("stream_reset", { extensionType });
11570
+ }
11571
+ }
11391
11572
  }
11392
11573
 
11393
11574
  // src/providers/provider-instance-manager.ts
@@ -15788,6 +15969,7 @@ var SessionHostRuntimeTransport = class {
15788
15969
  this.ready = this.boot();
15789
15970
  }
15790
15971
  ready;
15972
+ terminalQueriesHandled = true;
15791
15973
  client;
15792
15974
  dataCallbacks = /* @__PURE__ */ new Set();
15793
15975
  exitCallbacks = /* @__PURE__ */ new Set();