@adhdev/daemon-standalone 0.7.41 → 0.7.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -18296,7 +18296,6 @@ var __copyProps2 = (to, from, except, desc) => {
18296
18296
  var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
18297
18297
  var config_exports = {};
18298
18298
  __export2(config_exports, {
18299
- generateConnectionToken: () => generateConnectionToken,
18300
18299
  generateMachineId: () => generateMachineId,
18301
18300
  getConfigDir: () => getConfigDir,
18302
18301
  isSetupComplete: () => isSetupComplete,
@@ -18307,6 +18306,57 @@ __export2(config_exports, {
18307
18306
  saveConfig: () => saveConfig,
18308
18307
  updateConfig: () => updateConfig
18309
18308
  });
18309
+ function isPlainObject2(value) {
18310
+ return !!value && typeof value === "object" && !Array.isArray(value);
18311
+ }
18312
+ function asStringArray(value) {
18313
+ if (!Array.isArray(value)) return [];
18314
+ return value.filter((item) => typeof item === "string");
18315
+ }
18316
+ function asNullableString(value) {
18317
+ return typeof value === "string" ? value : null;
18318
+ }
18319
+ function asOptionalString(value) {
18320
+ return typeof value === "string" && value.trim() ? value : void 0;
18321
+ }
18322
+ function asBoolean(value, fallback) {
18323
+ return typeof value === "boolean" ? value : fallback;
18324
+ }
18325
+ function normalizeConfig(raw) {
18326
+ const parsed = isPlainObject2(raw) ? raw : {};
18327
+ const legacySessionReads = isPlainObject2(parsed.recentSessionReads) ? parsed.recentSessionReads : {};
18328
+ const sessionReads = isPlainObject2(parsed.sessionReads) ? parsed.sessionReads : {};
18329
+ const mergedSessionReads = Object.fromEntries(
18330
+ Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
18331
+ );
18332
+ const sessionReadMarkers = Object.fromEntries(
18333
+ Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
18334
+ );
18335
+ return {
18336
+ serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
18337
+ selectedIde: asNullableString(parsed.selectedIde),
18338
+ configuredIdes: asStringArray(parsed.configuredIdes),
18339
+ installedExtensions: asStringArray(parsed.installedExtensions),
18340
+ userEmail: asNullableString(parsed.userEmail),
18341
+ userName: asNullableString(parsed.userName),
18342
+ setupCompleted: asBoolean(parsed.setupCompleted, DEFAULT_CONFIG.setupCompleted),
18343
+ setupDate: asNullableString(parsed.setupDate),
18344
+ enabledIdes: asStringArray(parsed.enabledIdes),
18345
+ workspaces: Array.isArray(parsed.workspaces) ? parsed.workspaces : [],
18346
+ defaultWorkspaceId: asNullableString(parsed.defaultWorkspaceId) ?? asNullableString(parsed.activeWorkspaceId),
18347
+ recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
18348
+ sessionReads: mergedSessionReads,
18349
+ sessionReadMarkers,
18350
+ machineNickname: asNullableString(parsed.machineNickname),
18351
+ machineId: asOptionalString(parsed.machineId),
18352
+ machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
18353
+ registeredMachineId: asOptionalString(parsed.registeredMachineId),
18354
+ providerSettings: isPlainObject2(parsed.providerSettings) ? parsed.providerSettings : {},
18355
+ ideSettings: isPlainObject2(parsed.ideSettings) ? parsed.ideSettings : {},
18356
+ disableUpstream: asBoolean(parsed.disableUpstream, DEFAULT_CONFIG.disableUpstream ?? false),
18357
+ providerDir: asOptionalString(parsed.providerDir)
18358
+ };
18359
+ }
18310
18360
  function generateMachineId() {
18311
18361
  return `${MACHINE_ID_PREFIX}${(0, import_crypto2.randomUUID)().replace(/-/g, "")}`;
18312
18362
  }
@@ -18350,14 +18400,10 @@ function loadConfig() {
18350
18400
  try {
18351
18401
  const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
18352
18402
  const parsed = JSON.parse(raw);
18353
- const merged = { ...DEFAULT_CONFIG, ...parsed };
18354
- if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
18355
- merged.defaultWorkspaceId = merged.activeWorkspaceId;
18356
- }
18357
- delete merged.activeWorkspaceId;
18358
- const ensured = ensureMachineId(merged);
18403
+ const normalizedInput = normalizeConfig(parsed);
18404
+ const ensured = ensureMachineId(normalizedInput);
18359
18405
  const normalized = ensured.config;
18360
- if (ensured.changed) {
18406
+ if (ensured.changed || JSON.stringify(parsed) !== JSON.stringify(normalized)) {
18361
18407
  try {
18362
18408
  saveConfig(normalized);
18363
18409
  } catch {
@@ -18372,10 +18418,11 @@ function loadConfig() {
18372
18418
  function saveConfig(config2) {
18373
18419
  const configPath = getConfigPath();
18374
18420
  const dir = getConfigDir();
18421
+ const normalized = normalizeConfig(config2);
18375
18422
  if (!(0, import_fs.existsSync)(dir)) {
18376
18423
  (0, import_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
18377
18424
  }
18378
- (0, import_fs.writeFileSync)(configPath, JSON.stringify(config2, null, 2), { encoding: "utf-8", mode: 384 });
18425
+ (0, import_fs.writeFileSync)(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
18379
18426
  try {
18380
18427
  (0, import_fs.chmodSync)(configPath, 384);
18381
18428
  } catch {
@@ -18404,14 +18451,6 @@ function isSetupComplete() {
18404
18451
  function resetConfig() {
18405
18452
  saveConfig({ ...DEFAULT_CONFIG });
18406
18453
  }
18407
- function generateConnectionToken() {
18408
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
18409
- let token = "db_";
18410
- for (let i = 0; i < 32; i++) {
18411
- token += chars.charAt(Math.floor(Math.random() * chars.length));
18412
- }
18413
- return token;
18414
- }
18415
18454
  var DEFAULT_CONFIG;
18416
18455
  var MACHINE_ID_PREFIX;
18417
18456
  var init_config = __esm2({
@@ -18419,18 +18458,13 @@ var init_config = __esm2({
18419
18458
  "use strict";
18420
18459
  DEFAULT_CONFIG = {
18421
18460
  serverUrl: "https://api.adhf.dev",
18422
- apiToken: null,
18423
- connectionToken: null,
18424
18461
  selectedIde: null,
18425
18462
  configuredIdes: [],
18426
18463
  installedExtensions: [],
18427
- autoConnect: true,
18428
- notifications: true,
18429
18464
  userEmail: null,
18430
18465
  userName: null,
18431
18466
  setupCompleted: false,
18432
18467
  setupDate: null,
18433
- configuredCLIs: [],
18434
18468
  enabledIdes: [],
18435
18469
  workspaces: [],
18436
18470
  defaultWorkspaceId: null,
@@ -18751,6 +18785,9 @@ var init_ghostty_vt_backend = __esm2({
18751
18785
  getText() {
18752
18786
  return this.terminal.formatPlainText({ trim: true }) || "";
18753
18787
  }
18788
+ getCursorPosition() {
18789
+ return this.terminal.getCursorPosition();
18790
+ }
18754
18791
  dispose() {
18755
18792
  this.terminal.dispose();
18756
18793
  }
@@ -18807,6 +18844,13 @@ var init_xterm_backend = __esm2({
18807
18844
  while (last > first && !lines[last - 1]?.trim()) last--;
18808
18845
  return lines.slice(first, last).join("\n");
18809
18846
  }
18847
+ getCursorPosition() {
18848
+ const buffer = this.terminal.buffer.active;
18849
+ return {
18850
+ col: Math.max(0, buffer.cursorX || 0),
18851
+ row: Math.max(0, buffer.cursorY || 0)
18852
+ };
18853
+ }
18810
18854
  dispose() {
18811
18855
  this.terminal.dispose();
18812
18856
  }
@@ -18893,6 +18937,9 @@ var init_terminal_screen = __esm2({
18893
18937
  getText() {
18894
18938
  return this.terminal.getText();
18895
18939
  }
18940
+ getCursorPosition() {
18941
+ return this.terminal.getCursorPosition();
18942
+ }
18896
18943
  dispose() {
18897
18944
  this.terminal.dispose();
18898
18945
  }
@@ -18922,6 +18969,7 @@ var init_pty_transport = __esm2({
18922
18969
  this.handle = handle;
18923
18970
  }
18924
18971
  ready = Promise.resolve();
18972
+ terminalQueriesHandled = false;
18925
18973
  get pid() {
18926
18974
  return this.handle.pid;
18927
18975
  }
@@ -18973,6 +19021,32 @@ function stripTerminalNoise(str) {
18973
19021
  function sanitizeTerminalText(str) {
18974
19022
  return stripTerminalNoise(stripAnsi(str));
18975
19023
  }
19024
+ function buildCliSpawnEnv(baseEnv, overrides) {
19025
+ const env = {};
19026
+ const source = { ...baseEnv, ...overrides || {} };
19027
+ for (const [key, value] of Object.entries(source)) {
19028
+ if (typeof value !== "string") continue;
19029
+ env[key] = value;
19030
+ }
19031
+ for (const key of Object.keys(env)) {
19032
+ 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_")) {
19033
+ delete env[key];
19034
+ }
19035
+ }
19036
+ return env;
19037
+ }
19038
+ function computeTerminalQueryTail(buffer) {
19039
+ const prefixes = ["\x1B[6n", "\x1B[?6n"];
19040
+ const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
19041
+ const start = Math.max(0, buffer.length - maxLength);
19042
+ for (let i = start; i < buffer.length; i++) {
19043
+ const suffix = buffer.slice(i);
19044
+ if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {
19045
+ return suffix;
19046
+ }
19047
+ }
19048
+ return "";
19049
+ }
18976
19050
  function findBinary(name) {
18977
19051
  const isWin = os12.platform() === "win32";
18978
19052
  try {
@@ -19059,36 +19133,6 @@ function promptLikelyVisible(screenText, promptSnippet) {
19059
19133
  ).length;
19060
19134
  return matched >= required2;
19061
19135
  }
19062
- function splitHistoryLines(text) {
19063
- return String(text || "").split("\n").map((line) => line.replace(/\s+$/, ""));
19064
- }
19065
- function normalizeHistoryLine(line) {
19066
- return String(line || "").replace(/\s+/g, " ").trim();
19067
- }
19068
- function mergeTerminalHistory(existing, snapshot) {
19069
- const next = String(snapshot || "").trim();
19070
- if (!next) return existing;
19071
- const prev = String(existing || "").trim();
19072
- if (!prev) return next;
19073
- if (prev === next || prev.endsWith(next)) return prev;
19074
- const prevLines = splitHistoryLines(prev);
19075
- const nextLines = splitHistoryLines(next);
19076
- const prevNorm = prevLines.map(normalizeHistoryLine);
19077
- const nextNorm = nextLines.map(normalizeHistoryLine);
19078
- const maxOverlap = Math.min(prevLines.length, nextLines.length);
19079
- for (let overlap = maxOverlap; overlap >= 1; overlap -= 1) {
19080
- const prevTail = prevNorm.slice(prevNorm.length - overlap);
19081
- const nextHead = nextNorm.slice(0, overlap);
19082
- if (prevTail.every((line, index) => line === nextHead[index])) {
19083
- return [...prevLines, ...nextLines.slice(overlap)].join("\n").trim();
19084
- }
19085
- }
19086
- const compactPrev = prevNorm.join("\n");
19087
- const compactNext = nextNorm.join("\n");
19088
- if (compactPrev.includes(compactNext)) return prev;
19089
- return `${prev}
19090
- ${next}`.trim();
19091
- }
19092
19136
  function parsePatternEntry(x) {
19093
19137
  if (x instanceof RegExp) return x;
19094
19138
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -19201,6 +19245,7 @@ var init_provider_cli_adapter = __esm2({
19201
19245
  pendingOutputParseTimer = null;
19202
19246
  ptyOutputBuffer = "";
19203
19247
  ptyOutputFlushTimer = null;
19248
+ pendingTerminalQueryTail = "";
19204
19249
  // Server log forwarding
19205
19250
  serverConn = null;
19206
19251
  logBuffer = [];
@@ -19232,9 +19277,7 @@ var init_provider_cli_adapter = __esm2({
19232
19277
  /** Full accumulated raw PTY output (with ANSI) */
19233
19278
  accumulatedRawBuffer = "";
19234
19279
  /** Current visible terminal screen snapshot */
19235
- terminalScreen = new TerminalScreen(40, 120);
19236
- /** Rolling append-only terminal transcript built from screen snapshots */
19237
- terminalHistory = "";
19280
+ terminalScreen = new TerminalScreen(30, 100);
19238
19281
  /** Max accumulated buffer size (last 50KB) */
19239
19282
  static MAX_ACCUMULATED_BUFFER = 5e4;
19240
19283
  currentTurnScope = null;
@@ -19242,6 +19285,13 @@ var init_provider_cli_adapter = __esm2({
19242
19285
  this.messages = [...this.committedMessages];
19243
19286
  this.structuredMessages = [...this.committedMessages];
19244
19287
  }
19288
+ normalizeParsedMessages(parsedMessages) {
19289
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
19290
+ role: message.role,
19291
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
19292
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
19293
+ }));
19294
+ }
19245
19295
  sliceFromOffset(text, start) {
19246
19296
  if (!text) return "";
19247
19297
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -19249,15 +19299,13 @@ var init_provider_cli_adapter = __esm2({
19249
19299
  return text.slice(start);
19250
19300
  }
19251
19301
  buildParseInput(baseMessages, partialResponse, scope) {
19252
- const buffer = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
19302
+ const buffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
19253
19303
  const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
19254
- const terminalHistory = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.terminalHistory : this.terminalHistory;
19255
19304
  return {
19256
19305
  buffer,
19257
19306
  rawBuffer,
19258
19307
  recentBuffer: buffer.slice(-1e3) || this.recentOutputBuffer,
19259
19308
  screenText: this.terminalScreen.getText(),
19260
- terminalHistory,
19261
19309
  messages: [...baseMessages],
19262
19310
  partialResponse
19263
19311
  };
@@ -19335,13 +19383,10 @@ var init_provider_cli_adapter = __esm2({
19335
19383
  shellArgs = allArgs;
19336
19384
  }
19337
19385
  const ptyOpts = {
19338
- cols: 120,
19339
- rows: 40,
19386
+ cols: 100,
19387
+ rows: 30,
19340
19388
  cwd: this.workingDir,
19341
- env: {
19342
- ...process.env,
19343
- ...spawnConfig.env
19344
- }
19389
+ env: buildCliSpawnEnv(process.env, spawnConfig.env)
19345
19390
  };
19346
19391
  try {
19347
19392
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
@@ -19359,8 +19404,8 @@ var init_provider_cli_adapter = __esm2({
19359
19404
  }
19360
19405
  this.ptyProcess.onData((data) => {
19361
19406
  if (Date.now() < this.resizeSuppressUntil) return;
19362
- if (data.includes("\x1B[6n") || data.includes("\x1B[?6n")) {
19363
- this.ptyProcess?.write("\x1B[1;1R");
19407
+ if (!this.ptyProcess?.terminalQueriesHandled) {
19408
+ this.respondToTerminalQueries(data);
19364
19409
  }
19365
19410
  this.pendingOutputParseBuffer += data;
19366
19411
  if (!this.pendingOutputParseTimer) {
@@ -19395,8 +19440,8 @@ var init_provider_cli_adapter = __esm2({
19395
19440
  this.spawnAt = Date.now();
19396
19441
  this.startupParseGate = true;
19397
19442
  this.startupBuffer = "";
19398
- this.terminalScreen.reset(40, 120);
19399
- this.terminalHistory = "";
19443
+ this.terminalScreen.reset(30, 100);
19444
+ this.pendingTerminalQueryTail = "";
19400
19445
  this.currentTurnScope = null;
19401
19446
  this.ready = false;
19402
19447
  await this.ptyProcess.ready;
@@ -19406,7 +19451,6 @@ var init_provider_cli_adapter = __esm2({
19406
19451
  // ─── Output Handling ────────────────────────────
19407
19452
  handleOutput(rawData) {
19408
19453
  this.terminalScreen.write(rawData);
19409
- this.terminalHistory = mergeTerminalHistory(this.terminalHistory, this.terminalScreen.getText());
19410
19454
  const cleanData = sanitizeTerminalText(rawData);
19411
19455
  if (this.isWaitingForResponse && cleanData) {
19412
19456
  this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
@@ -19638,6 +19682,15 @@ var init_provider_cli_adapter = __esm2({
19638
19682
  this.onStatusChange?.();
19639
19683
  }
19640
19684
  commitCurrentTranscript() {
19685
+ const parsed = this.parseCurrentTranscript(
19686
+ this.committedMessages,
19687
+ this.responseBuffer,
19688
+ this.currentTurnScope
19689
+ );
19690
+ if (parsed && Array.isArray(parsed.messages)) {
19691
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
19692
+ this.syncMessageViews();
19693
+ }
19641
19694
  }
19642
19695
  // ─── Script Execution ──────────────────────────
19643
19696
  runDetectStatus(text) {
@@ -19673,8 +19726,7 @@ var init_provider_cli_adapter = __esm2({
19673
19726
  status: this.currentStatus,
19674
19727
  messages: [...this.committedMessages],
19675
19728
  workingDir: this.workingDir,
19676
- activeModal: this.activeModal,
19677
- terminalHistory: this.terminalHistory
19729
+ activeModal: this.activeModal
19678
19730
  };
19679
19731
  }
19680
19732
  /**
@@ -19682,12 +19734,25 @@ var init_provider_cli_adapter = __esm2({
19682
19734
  * Called by command handler / dashboard for rich content rendering.
19683
19735
  */
19684
19736
  getScriptParsedStatus() {
19737
+ const parsed = this.parseCurrentTranscript(
19738
+ this.committedMessages,
19739
+ this.responseBuffer,
19740
+ this.currentTurnScope
19741
+ );
19742
+ if (parsed && Array.isArray(parsed.messages)) {
19743
+ return {
19744
+ id: parsed.id || "cli_session",
19745
+ status: parsed.status || this.currentStatus,
19746
+ title: parsed.title || this.cliName,
19747
+ messages: parsed.messages,
19748
+ activeModal: parsed.activeModal ?? this.activeModal
19749
+ };
19750
+ }
19685
19751
  const messages = [...this.committedMessages];
19686
19752
  return {
19687
19753
  id: "cli_session",
19688
19754
  status: this.currentStatus,
19689
19755
  title: this.cliName,
19690
- terminalHistory: this.terminalHistory,
19691
19756
  messages: messages.slice(-50).map((message, index) => ({
19692
19757
  id: `msg_${index}`,
19693
19758
  role: message.role,
@@ -19755,10 +19820,9 @@ ${data.message || ""}`.trim();
19755
19820
  prompt: text,
19756
19821
  startedAt: Date.now(),
19757
19822
  bufferStart: this.accumulatedBuffer.length,
19758
- rawBufferStart: this.accumulatedRawBuffer.length,
19759
- terminalHistoryStart: this.terminalHistory.length
19823
+ rawBufferStart: this.accumulatedRawBuffer.length
19760
19824
  };
19761
- 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)}`);
19825
+ LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
19762
19826
  this.submitRetryUsed = false;
19763
19827
  this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
19764
19828
  const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
@@ -19943,6 +20007,7 @@ ${data.message || ""}`.trim();
19943
20007
  this.pendingOutputParseTimer = null;
19944
20008
  }
19945
20009
  this.pendingOutputParseBuffer = "";
20010
+ this.pendingTerminalQueryTail = "";
19946
20011
  if (this.ptyOutputFlushTimer) {
19947
20012
  clearTimeout(this.ptyOutputFlushTimer);
19948
20013
  this.ptyOutputFlushTimer = null;
@@ -19982,6 +20047,7 @@ ${data.message || ""}`.trim();
19982
20047
  this.pendingOutputParseTimer = null;
19983
20048
  }
19984
20049
  this.pendingOutputParseBuffer = "";
20050
+ this.pendingTerminalQueryTail = "";
19985
20051
  if (this.ptyOutputFlushTimer) {
19986
20052
  clearTimeout(this.ptyOutputFlushTimer);
19987
20053
  this.ptyOutputFlushTimer = null;
@@ -20008,7 +20074,6 @@ ${data.message || ""}`.trim();
20008
20074
  this.syncMessageViews();
20009
20075
  this.accumulatedBuffer = "";
20010
20076
  this.accumulatedRawBuffer = "";
20011
- this.terminalHistory = "";
20012
20077
  this.currentTurnScope = null;
20013
20078
  this.submitRetryUsed = false;
20014
20079
  this.submitRetryPromptSnippet = "";
@@ -20017,6 +20082,7 @@ ${data.message || ""}`.trim();
20017
20082
  this.pendingOutputParseTimer = null;
20018
20083
  }
20019
20084
  this.pendingOutputParseBuffer = "";
20085
+ this.pendingTerminalQueryTail = "";
20020
20086
  if (this.ptyOutputFlushTimer) {
20021
20087
  clearTimeout(this.ptyOutputFlushTimer);
20022
20088
  this.ptyOutputFlushTimer = null;
@@ -20078,7 +20144,6 @@ ${data.message || ""}`.trim();
20078
20144
  structuredMessages: this.structuredMessages.slice(-20),
20079
20145
  messageCount: this.committedMessages.length,
20080
20146
  screenText: sanitizeTerminalText(this.terminalScreen.getText()).slice(-4e3),
20081
- terminalHistory: this.terminalHistory.slice(-8e3),
20082
20147
  currentTurnScope: this.currentTurnScope,
20083
20148
  startupBuffer: this.startupBuffer.slice(-4e3),
20084
20149
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
@@ -20106,6 +20171,20 @@ ${data.message || ""}`.trim();
20106
20171
  ptyAlive: !!this.ptyProcess
20107
20172
  };
20108
20173
  }
20174
+ respondToTerminalQueries(data) {
20175
+ if (!this.ptyProcess || !data) return;
20176
+ const combined = this.pendingTerminalQueryTail + data;
20177
+ const regex = /\x1b\[(\?)?6n/g;
20178
+ let match;
20179
+ while ((match = regex.exec(combined)) !== null) {
20180
+ const cursor = this.terminalScreen.getCursorPosition();
20181
+ const row = Math.max(1, (cursor.row | 0) + 1);
20182
+ const col = Math.max(1, (cursor.col | 0) + 1);
20183
+ const response = match[1] ? `\x1B[?${row};${col}R` : `\x1B[${row};${col}R`;
20184
+ this.ptyProcess.write(response);
20185
+ }
20186
+ this.pendingTerminalQueryTail = computeTerminalQueryTail(combined);
20187
+ }
20109
20188
  };
20110
20189
  }
20111
20190
  });
@@ -21971,6 +22050,8 @@ var ExtensionProviderInstance = class {
21971
22050
  this.detectTransition(newStatus, data);
21972
22051
  this.currentStatus = newStatus;
21973
22052
  }
22053
+ } else if (event === "stream_reset") {
22054
+ this.resetStreamState();
21974
22055
  } else if (event === "extension_connected") {
21975
22056
  this.ideType = data?.ideType || "";
21976
22057
  }
@@ -22050,6 +22131,30 @@ var ExtensionProviderInstance = class {
22050
22131
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
22051
22132
  return title || this.agentName || this.provider.name;
22052
22133
  }
22134
+ resetStreamState() {
22135
+ if (this.currentStatus !== "idle") {
22136
+ this.detectTransition("idle", {
22137
+ title: this.chatTitle,
22138
+ agentName: this.agentName,
22139
+ extensionId: this.extensionId,
22140
+ messages: this.messages
22141
+ });
22142
+ }
22143
+ this.agentStreams = [];
22144
+ this.messages = [];
22145
+ this.activeModal = null;
22146
+ this.currentModel = "";
22147
+ this.currentMode = "";
22148
+ this.controlValues = {};
22149
+ this.currentStatus = "idle";
22150
+ this.chatId = null;
22151
+ this.chatTitle = null;
22152
+ this.agentName = "";
22153
+ this.extensionId = "";
22154
+ this.lastAgentStatus = "idle";
22155
+ this.generatingStartedAt = 0;
22156
+ this.monitor.reset();
22157
+ }
22053
22158
  };
22054
22159
  var HISTORY_DIR = path4.join(os5.homedir(), ".adhdev", "history");
22055
22160
  var RETAIN_DAYS = 30;
@@ -22058,8 +22163,6 @@ var ChatHistoryWriter = class {
22058
22163
  lastSeenCounts = /* @__PURE__ */ new Map();
22059
22164
  /** Last seen message hash per agent (deduplication) */
22060
22165
  lastSeenHashes = /* @__PURE__ */ new Map();
22061
- /** Last seen append-only terminal transcript per agent */
22062
- lastSeenTerminal = /* @__PURE__ */ new Map();
22063
22166
  rotated = false;
22064
22167
  /**
22065
22168
  * Append new messages to history
@@ -22117,51 +22220,10 @@ var ChatHistoryWriter = class {
22117
22220
  } catch {
22118
22221
  }
22119
22222
  }
22120
- appendTerminalHistory(agentType, terminalHistory, sessionTitle, instanceId) {
22121
- const next = String(terminalHistory || "");
22122
- if (!next.trim()) return;
22123
- try {
22124
- const dedupKey = instanceId ? `${agentType}:${instanceId}:terminal` : `${agentType}:terminal`;
22125
- const prev = this.lastSeenTerminal.get(dedupKey) || "";
22126
- if (prev === next) return;
22127
- let delta = "";
22128
- if (!prev) {
22129
- delta = next;
22130
- } else if (next.startsWith(prev)) {
22131
- delta = next.slice(prev.length);
22132
- } else if (prev.includes(next)) {
22133
- this.lastSeenTerminal.set(dedupKey, next);
22134
- return;
22135
- } else {
22136
- delta = `
22137
-
22138
- [terminal snapshot reset ${(/* @__PURE__ */ new Date()).toISOString()} | ${sessionTitle || agentType}]
22139
- ${next}`;
22140
- }
22141
- if (!delta) {
22142
- this.lastSeenTerminal.set(dedupKey, next);
22143
- return;
22144
- }
22145
- const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
22146
- fs3.mkdirSync(dir, { recursive: true });
22147
- const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
22148
- const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
22149
- const filePath = path4.join(dir, `${filePrefix}${date5}.terminal.log`);
22150
- fs3.appendFileSync(filePath, delta, "utf-8");
22151
- this.lastSeenTerminal.set(dedupKey, next);
22152
- if (!this.rotated) {
22153
- this.rotated = true;
22154
- this.rotateOldFiles().catch(() => {
22155
- });
22156
- }
22157
- } catch {
22158
- }
22159
- }
22160
22223
  /** Called when agent session is explicitly changed */
22161
22224
  onSessionChange(agentType) {
22162
22225
  this.lastSeenHashes.delete(agentType);
22163
22226
  this.lastSeenCounts.delete(agentType);
22164
- this.lastSeenTerminal.delete(`${agentType}:terminal`);
22165
22227
  }
22166
22228
  /** Delete history files older than 30 days */
22167
22229
  async rotateOldFiles() {
@@ -22325,11 +22387,23 @@ var IdeProviderInstance = class {
22325
22387
  } else if (event === "cdp_disconnected") {
22326
22388
  this.cachedChat = null;
22327
22389
  this.currentStatus = "idle";
22390
+ for (const ext of this.extensions.values()) {
22391
+ ext.onEvent("stream_reset");
22392
+ }
22328
22393
  } else if (event === "stream_update") {
22329
22394
  const extType = data?.extensionType;
22330
22395
  if (extType && this.extensions.has(extType)) {
22331
22396
  this.extensions.get(extType).onEvent("stream_update", data);
22332
22397
  }
22398
+ } else if (event === "stream_reset") {
22399
+ const extType = data?.extensionType;
22400
+ if (extType && this.extensions.has(extType)) {
22401
+ this.extensions.get(extType).onEvent("stream_reset");
22402
+ }
22403
+ } else if (event === "stream_reset_all") {
22404
+ for (const ext of this.extensions.values()) {
22405
+ ext.onEvent("stream_reset");
22406
+ }
22333
22407
  }
22334
22408
  }
22335
22409
  dispose() {
@@ -22836,6 +22910,57 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
22836
22910
  "thinking",
22837
22911
  "active"
22838
22912
  ]);
22913
+ var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
22914
+ var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
22915
+ var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
22916
+ var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
22917
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
22918
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
22919
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
22920
+ function truncateString(value, maxChars) {
22921
+ if (value.length <= maxChars) return value;
22922
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
22923
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
22924
+ }
22925
+ function trimStructuredStrings(value, maxChars) {
22926
+ if (typeof value === "string") return truncateString(value, maxChars);
22927
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
22928
+ if (!value || typeof value !== "object") return value;
22929
+ return Object.fromEntries(
22930
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
22931
+ );
22932
+ }
22933
+ function estimateBytes(value) {
22934
+ try {
22935
+ return JSON.stringify(value).length;
22936
+ } catch {
22937
+ return String(value ?? "").length;
22938
+ }
22939
+ }
22940
+ function trimMessageForStatus(message, stringLimit) {
22941
+ if (!message || typeof message !== "object") return message;
22942
+ return trimStructuredStrings(message, stringLimit);
22943
+ }
22944
+ function trimMessagesForStatus(messages) {
22945
+ if (!Array.isArray(messages) || messages.length === 0) return [];
22946
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
22947
+ const kept = [];
22948
+ let totalBytes = 0;
22949
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
22950
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
22951
+ let size = estimateBytes(normalized);
22952
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
22953
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
22954
+ size = estimateBytes(normalized);
22955
+ }
22956
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
22957
+ continue;
22958
+ }
22959
+ kept.push(normalized);
22960
+ totalBytes += size;
22961
+ }
22962
+ return kept.reverse();
22963
+ }
22839
22964
  function hasApprovalButtons(activeModal) {
22840
22965
  return (activeModal?.buttons?.length ?? 0) > 0;
22841
22966
  }
@@ -22856,7 +22981,15 @@ function normalizeActiveChatData(activeChat) {
22856
22981
  if (!activeChat) return activeChat;
22857
22982
  return {
22858
22983
  ...activeChat,
22859
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
22984
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
22985
+ messages: trimMessagesForStatus(activeChat.messages),
22986
+ activeModal: activeChat.activeModal ? {
22987
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
22988
+ buttons: (activeChat.activeModal.buttons || []).map(
22989
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
22990
+ )
22991
+ } : activeChat.activeModal,
22992
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
22860
22993
  };
22861
22994
  }
22862
22995
  function findCdpManager(cdpManagers, key) {
@@ -22944,6 +23077,11 @@ var PTY_SESSION_CAPABILITIES = [
22944
23077
  "terminal_io",
22945
23078
  "resize_terminal"
22946
23079
  ];
23080
+ var CLI_CHAT_SESSION_CAPABILITIES = [
23081
+ "read_chat",
23082
+ "send_message",
23083
+ "resolve_action"
23084
+ ];
22947
23085
  var ACP_SESSION_CAPABILITIES = [
22948
23086
  "read_chat",
22949
23087
  "send_message",
@@ -23033,11 +23171,10 @@ function buildCliSession(state) {
23033
23171
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
23034
23172
  runtimeWriteOwner: state.runtime?.writeOwner || null,
23035
23173
  runtimeAttachedClients: state.runtime?.attachedClients || [],
23036
- launchMode: state.launchMode,
23037
23174
  mode: state.mode,
23038
23175
  resume: state.resume,
23039
23176
  activeChat,
23040
- capabilities: PTY_SESSION_CAPABILITIES,
23177
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
23041
23178
  controlValues: state.controlValues,
23042
23179
  providerControls: buildFallbackControls(
23043
23180
  state.providerControls
@@ -24200,6 +24337,13 @@ async function handleFileListBrowse(h, args) {
24200
24337
  return handleFileList(h, args);
24201
24338
  }
24202
24339
  init_logger();
24340
+ function getCliPresentationMode(h, targetSessionId) {
24341
+ if (!targetSessionId) return null;
24342
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
24343
+ if (instance?.category !== "cli") return null;
24344
+ const mode = instance.getPresentationMode?.();
24345
+ return mode === "chat" || mode === "terminal" ? mode : null;
24346
+ }
24203
24347
  async function handleFocusSession(h, args) {
24204
24348
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
24205
24349
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -24210,6 +24354,9 @@ async function handleFocusSession(h, args) {
24210
24354
  function handlePtyInput(h, args) {
24211
24355
  const { cliType, data, targetSessionId } = args || {};
24212
24356
  if (!data) return { success: false, error: "data required" };
24357
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
24358
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
24359
+ }
24213
24360
  const adapter = h.getCliAdapter(targetSessionId || cliType);
24214
24361
  if (!adapter || typeof adapter.writeRaw !== "function") {
24215
24362
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -24220,6 +24367,9 @@ function handlePtyInput(h, args) {
24220
24367
  function handlePtyResize(h, args) {
24221
24368
  const { cliType, cols, rows, force, targetSessionId } = args || {};
24222
24369
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
24370
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
24371
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
24372
+ }
24223
24373
  const adapter = h.getCliAdapter(targetSessionId || cliType);
24224
24374
  if (!adapter || typeof adapter.resize !== "function") {
24225
24375
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -26566,6 +26716,7 @@ var DaemonCommandRouter = class {
26566
26716
  // ─── CLI / ACP commands ───
26567
26717
  case "launch_cli":
26568
26718
  case "stop_cli":
26719
+ case "set_cli_view_mode":
26569
26720
  case "agent_command": {
26570
26721
  return this.deps.cliManager.handleCliCommand(cmd, args);
26571
26722
  }
@@ -26840,14 +26991,13 @@ init_config();
26840
26991
  init_provider_cli_adapter();
26841
26992
  init_logger();
26842
26993
  var CliProviderInstance = class {
26843
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
26994
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
26844
26995
  this.provider = provider;
26845
26996
  this.workingDir = workingDir;
26846
26997
  this.cliArgs = cliArgs;
26847
26998
  this.type = provider.type;
26848
26999
  this.instanceId = instanceId || crypto3.randomUUID();
26849
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
26850
- this.resolvedOutputFormat = this.resolveOutputFormat();
27000
+ this.presentationMode = "chat";
26851
27001
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
26852
27002
  this.monitor = new StatusMonitor();
26853
27003
  this.historyWriter = new ChatHistoryWriter();
@@ -26866,26 +27016,7 @@ var CliProviderInstance = class {
26866
27016
  lastApprovalEventAt = 0;
26867
27017
  historyWriter;
26868
27018
  instanceId;
26869
- launchMode;
26870
- resolvedOutputFormat;
26871
- /**
26872
- * Determine output rendering format from:
26873
- * 1. launchMode.outputFormat (explicit override)
26874
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
26875
- * 3. Default: 'terminal'
26876
- */
26877
- resolveOutputFormat() {
26878
- if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
26879
- if (this.provider.launchOptions?.length) {
26880
- for (const opt of this.provider.launchOptions) {
26881
- if (!opt.outputFormatMap) continue;
26882
- for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
26883
- if (this.cliArgs.includes(val)) return fmt;
26884
- }
26885
- }
26886
- }
26887
- return "terminal";
26888
- }
27019
+ presentationMode;
26889
27020
  // ─── Lifecycle ─────────────────────────────────
26890
27021
  async init(context) {
26891
27022
  this.context = context;
@@ -26910,30 +27041,21 @@ var CliProviderInstance = class {
26910
27041
  }
26911
27042
  getState() {
26912
27043
  const adapterStatus = this.adapter.getStatus();
27044
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
26913
27045
  const runtime = this.adapter.getRuntimeMetadata();
26914
27046
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
26915
- if (adapterStatus.terminalHistory?.trim()) {
26916
- this.historyWriter.appendTerminalHistory(
26917
- this.type,
26918
- adapterStatus.terminalHistory,
26919
- `${this.provider.name} \xB7 ${dirName}`,
26920
- this.instanceId
26921
- );
26922
- }
26923
27047
  return {
26924
27048
  type: this.type,
26925
27049
  name: this.provider.name,
26926
27050
  category: "cli",
26927
27051
  status: adapterStatus.status,
26928
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
26929
- launchMode: this.launchMode?.id,
27052
+ mode: this.presentationMode,
26930
27053
  activeChat: {
26931
27054
  id: `${this.type}_${this.workingDir}`,
26932
- title: `${this.provider.name} \xB7 ${dirName}`,
26933
- status: adapterStatus.status,
26934
- messages: [],
26935
- activeModal: adapterStatus.activeModal,
26936
- terminalHistory: adapterStatus.terminalHistory,
27055
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
27056
+ status: parsedStatus?.status || adapterStatus.status,
27057
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
27058
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
26937
27059
  inputContent: ""
26938
27060
  },
26939
27061
  workspace: this.workingDir,
@@ -26955,6 +27077,13 @@ var CliProviderInstance = class {
26955
27077
  providerControls: this.provider.controls
26956
27078
  };
26957
27079
  }
27080
+ setPresentationMode(mode) {
27081
+ if (this.presentationMode === mode) return;
27082
+ this.presentationMode = mode;
27083
+ }
27084
+ getPresentationMode() {
27085
+ return this.presentationMode;
27086
+ }
26958
27087
  onEvent(event, data) {
26959
27088
  if (event === "send_message" && data?.text) {
26960
27089
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -28002,6 +28131,15 @@ var DaemonCliManager = class {
28002
28131
  const hash2 = __require("crypto").createHash("md5").update(__require("path").resolve(dir)).digest("hex").slice(0, 8);
28003
28132
  return `${cliType}_${hash2}`;
28004
28133
  }
28134
+ getSessionPresentationMode(sessionId) {
28135
+ if (!sessionId) return null;
28136
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
28137
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
28138
+ return mode === "chat" || mode === "terminal" ? mode : null;
28139
+ }
28140
+ isTerminalSession(sessionId) {
28141
+ return this.getSessionPresentationMode(sessionId) === "terminal";
28142
+ }
28005
28143
  persistRecentActivity(entry) {
28006
28144
  try {
28007
28145
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -28057,12 +28195,12 @@ var DaemonCliManager = class {
28057
28195
  }
28058
28196
  }, 3e3);
28059
28197
  }
28060
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
28198
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
28061
28199
  const instanceManager = this.deps.getInstanceManager();
28062
28200
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
28063
28201
  if (!instanceManager) throw new Error("InstanceManager not available");
28064
28202
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
28065
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
28203
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
28066
28204
  try {
28067
28205
  await instanceManager.addInstance(key, cliInstance, {
28068
28206
  serverConn: this.deps.getServerConn(),
@@ -28088,7 +28226,7 @@ var DaemonCliManager = class {
28088
28226
  this.startCliExitMonitor(key, cliType);
28089
28227
  }
28090
28228
  // ─── Session start/management ──────────────────────────────
28091
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
28229
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
28092
28230
  const trimmed = (workingDir || "").trim();
28093
28231
  if (!trimmed) throw new Error("working directory required");
28094
28232
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -28180,29 +28318,7 @@ ${installInfo}`
28180
28318
  if (provider) {
28181
28319
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
28182
28320
  }
28183
- let resolvedCliArgs = cliArgs;
28184
- let resolvedLaunchMode = launchMode;
28185
- const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
28186
- if (activeMode) {
28187
- resolvedLaunchMode = activeMode.id;
28188
- }
28189
- if (provider?.launchArgBuilder) {
28190
- const defaults = {};
28191
- for (const opt of provider.launchOptions || []) {
28192
- if (opt.default !== void 0) defaults[opt.id] = opt.default;
28193
- }
28194
- const modeOptions = activeMode?.options || {};
28195
- const userOptions = launchOptionValues || {};
28196
- const merged = { ...defaults, ...modeOptions, ...userOptions };
28197
- const extraArgs = provider.launchArgBuilder(merged);
28198
- if (extraArgs.length) {
28199
- resolvedCliArgs = [...cliArgs || [], ...extraArgs];
28200
- console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
28201
- }
28202
- } else if (activeMode?.extraArgs?.length) {
28203
- resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
28204
- console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
28205
- }
28321
+ const resolvedCliArgs = cliArgs;
28206
28322
  const instanceManager = this.deps.getInstanceManager();
28207
28323
  if (provider && instanceManager) {
28208
28324
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -28214,8 +28330,7 @@ ${installInfo}`
28214
28330
  resolvedCliArgs,
28215
28331
  resolvedProvider,
28216
28332
  {},
28217
- false,
28218
- resolvedLaunchMode
28333
+ false
28219
28334
  );
28220
28335
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
28221
28336
  } else {
@@ -28327,8 +28442,7 @@ ${installInfo}`
28327
28442
  record2.cliArgs,
28328
28443
  resolvedProvider,
28329
28444
  {},
28330
- true,
28331
- record2.launchMode
28445
+ true
28332
28446
  );
28333
28447
  restored += 1;
28334
28448
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record2.runtimeKey || record2.runtimeId} (${record2.displayName || record2.workspace})`);
@@ -28370,6 +28484,14 @@ ${installInfo}`
28370
28484
  }
28371
28485
  return null;
28372
28486
  }
28487
+ findAdapterBySessionId(instanceKey) {
28488
+ if (!instanceKey) return null;
28489
+ let ik = instanceKey;
28490
+ const colonIdx = ik.lastIndexOf(":");
28491
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
28492
+ const adapter = this.adapters.get(ik);
28493
+ return adapter ? { adapter, key: ik } : null;
28494
+ }
28373
28495
  // ─── CLI command handling ────────────────────────────
28374
28496
  async handleCliCommand(cmd, args) {
28375
28497
  switch (cmd) {
@@ -28398,7 +28520,7 @@ ${installInfo}`
28398
28520
  const dir = resolved.path;
28399
28521
  const launchSource = resolved.source;
28400
28522
  if (!cliType) throw new Error("cliType required");
28401
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
28523
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
28402
28524
  let newKey = null;
28403
28525
  for (const [k, adapter] of this.adapters) {
28404
28526
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -28420,6 +28542,23 @@ ${installInfo}`
28420
28542
  }
28421
28543
  return { success: true, cliType, dir, stopped: true, mode };
28422
28544
  }
28545
+ case "set_cli_view_mode": {
28546
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
28547
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
28548
+ const cliType = args?.cliType || args?.agentType || "";
28549
+ const dir = args?.dir || "";
28550
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
28551
+ if (!found) {
28552
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
28553
+ }
28554
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
28555
+ if (!(instance instanceof CliProviderInstance)) {
28556
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
28557
+ }
28558
+ instance.setPresentationMode(mode);
28559
+ this.deps.onStatusChange();
28560
+ return { success: true, id: found.key, mode };
28561
+ }
28423
28562
  case "restart_session": {
28424
28563
  const cliType = args?.cliType || args?.agentType || args?.ideType;
28425
28564
  const cfg = loadConfig();
@@ -29028,7 +29167,12 @@ var AgentStreamPoller = class {
29028
29167
  } catch {
29029
29168
  }
29030
29169
  }
29031
- if (!resolvedActiveSessionId || !parentSessionId) continue;
29170
+ if (!resolvedActiveSessionId || !parentSessionId) {
29171
+ if (parentSessionId) {
29172
+ this.deps.onStreamsUpdated?.(ideType, []);
29173
+ }
29174
+ continue;
29175
+ }
29032
29176
  try {
29033
29177
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
29034
29178
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -29041,7 +29185,11 @@ var AgentStreamPoller = class {
29041
29185
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
29042
29186
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
29043
29187
  if (!ideInstance?.onEvent) return;
29188
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
29044
29189
  for (const stream of streams) {
29190
+ if (typeof stream.agentType === "string" && stream.agentType) {
29191
+ seenExtensionTypes.add(stream.agentType);
29192
+ }
29045
29193
  ideInstance.onEvent("stream_update", {
29046
29194
  extensionType: stream.agentType,
29047
29195
  streams: [stream],
@@ -29058,6 +29206,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
29058
29206
  inputContent: stream.inputContent || ""
29059
29207
  });
29060
29208
  }
29209
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
29210
+ if (streams.length === 0) {
29211
+ ideInstance.onEvent("stream_reset_all");
29212
+ return;
29213
+ }
29214
+ for (const extensionType of extensionTypes) {
29215
+ if (!seenExtensionTypes.has(extensionType)) {
29216
+ ideInstance.onEvent("stream_reset", { extensionType });
29217
+ }
29218
+ }
29061
29219
  }
29062
29220
  init_logger();
29063
29221
  var ProviderInstanceManager = class {
@@ -33422,6 +33580,7 @@ var SessionHostRuntimeTransport = class {
33422
33580
  this.ready = this.boot();
33423
33581
  }
33424
33582
  ready;
33583
+ terminalQueriesHandled = true;
33425
33584
  client;
33426
33585
  dataCallbacks = /* @__PURE__ */ new Set();
33427
33586
  exitCallbacks = /* @__PURE__ */ new Set();
@@ -34052,6 +34211,20 @@ async function shutdownDaemonComponents(components) {
34052
34211
  var import_child_process8 = require("child_process");
34053
34212
  var path15 = __toESM(require("path"));
34054
34213
  var SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
34214
+ function buildSessionHostEnv(baseEnv) {
34215
+ const env = {};
34216
+ for (const [key, value] of Object.entries(baseEnv)) {
34217
+ if (typeof value !== "string") continue;
34218
+ env[key] = value;
34219
+ }
34220
+ for (const key of Object.keys(env)) {
34221
+ 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_")) {
34222
+ delete env[key];
34223
+ }
34224
+ }
34225
+ env.ADHDEV_SESSION_HOST_NAME = SESSION_HOST_APP_NAME;
34226
+ return env;
34227
+ }
34055
34228
  function resolveSessionHostEntry() {
34056
34229
  const localCandidates = [
34057
34230
  path15.resolve(__dirname, "../vendor/session-host-daemon/index.js"),
@@ -34068,10 +34241,7 @@ async function runSessionHostCli(args) {
34068
34241
  const entry = resolveSessionHostEntry();
34069
34242
  const child = (0, import_child_process8.spawn)(process.execPath, [entry, ...args], {
34070
34243
  stdio: "inherit",
34071
- env: {
34072
- ...process.env,
34073
- ADHDEV_SESSION_HOST_NAME: SESSION_HOST_APP_NAME
34074
- }
34244
+ env: buildSessionHostEnv(process.env)
34075
34245
  });
34076
34246
  return await new Promise((resolve12, reject) => {
34077
34247
  child.on("error", reject);
@@ -34087,10 +34257,7 @@ async function ensureSessionHostReady2() {
34087
34257
  detached: true,
34088
34258
  stdio: "ignore",
34089
34259
  windowsHide: true,
34090
- env: {
34091
- ...process.env,
34092
- ADHDEV_SESSION_HOST_NAME: SESSION_HOST_APP_NAME
34093
- }
34260
+ env: buildSessionHostEnv(process.env)
34094
34261
  });
34095
34262
  child.unref();
34096
34263
  }
@@ -34333,6 +34500,16 @@ var StandaloneServer = class {
34333
34500
  await client.connect();
34334
34501
  return client;
34335
34502
  }
34503
+ getCliPresentationMode(sessionId) {
34504
+ if (!sessionId || !this.components) return null;
34505
+ const instance = this.components.instanceManager.getInstance(sessionId);
34506
+ if (instance?.category !== "cli") return null;
34507
+ const mode = instance.getPresentationMode?.();
34508
+ return mode === "chat" || mode === "terminal" ? mode : null;
34509
+ }
34510
+ isTerminalCliSession(sessionId) {
34511
+ return this.getCliPresentationMode(sessionId) === "terminal";
34512
+ }
34336
34513
  async start(options = {}) {
34337
34514
  const port = options.port || DEFAULT_PORT;
34338
34515
  const host = options.host || "127.0.0.1";
@@ -34344,8 +34521,8 @@ var StandaloneServer = class {
34344
34521
  getServerConn: () => null,
34345
34522
  getP2p: () => ({
34346
34523
  broadcastPtyOutput: (key, data) => {
34347
- if (this.clients.size === 0) return;
34348
- const msg = JSON.stringify({ type: "pty_output", cliId: key, data });
34524
+ if (this.clients.size === 0 || !this.isTerminalCliSession(key)) return;
34525
+ const msg = JSON.stringify({ type: "pty_output", sessionId: key, data });
34349
34526
  for (const client of this.clients) {
34350
34527
  if (client.readyState === 1) {
34351
34528
  client.send(msg);
@@ -34559,6 +34736,11 @@ var StandaloneServer = class {
34559
34736
  return;
34560
34737
  }
34561
34738
  if (action === "snapshot" && method === "GET") {
34739
+ if (!this.isTerminalCliSession(sessionId)) {
34740
+ res.writeHead(409, { "Content-Type": "application/json" });
34741
+ res.end(JSON.stringify({ error: "CLI session is not in terminal mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" }));
34742
+ return;
34743
+ }
34562
34744
  void (async () => {
34563
34745
  const client = await this.createSessionHostClient();
34564
34746
  try {
@@ -34680,6 +34862,11 @@ var StandaloneServer = class {
34680
34862
  req.on("aborted", cleanup);
34681
34863
  }
34682
34864
  async handleRuntimeEvents(req, res, sessionId) {
34865
+ if (!this.isTerminalCliSession(sessionId)) {
34866
+ res.writeHead(409, { "Content-Type": "application/json" });
34867
+ res.end(JSON.stringify({ error: "CLI session is not in terminal mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" }));
34868
+ return;
34869
+ }
34683
34870
  const client = await this.createSessionHostClient();
34684
34871
  res.writeHead(200, {
34685
34872
  "Content-Type": "text/event-stream",
@@ -34699,6 +34886,7 @@ var StandaloneServer = class {
34699
34886
  }
34700
34887
  const writeEvent = (event) => {
34701
34888
  if (event.sessionId !== sessionId) return;
34889
+ if (!this.isTerminalCliSession(sessionId)) return;
34702
34890
  res.write(`event: ${event.type}
34703
34891
  `);
34704
34892
  res.write(`data: ${JSON.stringify(event)}
@@ -34786,7 +34974,7 @@ var StandaloneServer = class {
34786
34974
  const states = this.components.instanceManager.collectAllStates();
34787
34975
  for (const state of states) {
34788
34976
  const sessionId = typeof state?.instanceId === "string" ? state.instanceId : "";
34789
- if (!sessionId || state?.category !== "cli") continue;
34977
+ if (!sessionId || state?.category !== "cli" || state?.mode !== "terminal") continue;
34790
34978
  const snapshot = await client.request({
34791
34979
  type: "get_snapshot",
34792
34980
  payload: { sessionId }