@adhdev/daemon-core 0.7.40 → 0.7.42

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.mjs CHANGED
@@ -28,7 +28,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
28
28
  // src/config/config.ts
29
29
  var config_exports = {};
30
30
  __export(config_exports, {
31
- generateConnectionToken: () => generateConnectionToken,
32
31
  generateMachineId: () => generateMachineId,
33
32
  getConfigDir: () => getConfigDir,
34
33
  isSetupComplete: () => isSetupComplete,
@@ -43,6 +42,57 @@ import { homedir } from "os";
43
42
  import { join } from "path";
44
43
  import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
45
44
  import { randomUUID } from "crypto";
45
+ function isPlainObject(value) {
46
+ return !!value && typeof value === "object" && !Array.isArray(value);
47
+ }
48
+ function asStringArray(value) {
49
+ if (!Array.isArray(value)) return [];
50
+ return value.filter((item) => typeof item === "string");
51
+ }
52
+ function asNullableString(value) {
53
+ return typeof value === "string" ? value : null;
54
+ }
55
+ function asOptionalString(value) {
56
+ return typeof value === "string" && value.trim() ? value : void 0;
57
+ }
58
+ function asBoolean(value, fallback) {
59
+ return typeof value === "boolean" ? value : fallback;
60
+ }
61
+ function normalizeConfig(raw) {
62
+ const parsed = isPlainObject(raw) ? raw : {};
63
+ const legacySessionReads = isPlainObject(parsed.recentSessionReads) ? parsed.recentSessionReads : {};
64
+ const sessionReads = isPlainObject(parsed.sessionReads) ? parsed.sessionReads : {};
65
+ const mergedSessionReads = Object.fromEntries(
66
+ Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
67
+ );
68
+ const sessionReadMarkers = Object.fromEntries(
69
+ Object.entries(isPlainObject(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
70
+ );
71
+ return {
72
+ serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
73
+ selectedIde: asNullableString(parsed.selectedIde),
74
+ configuredIdes: asStringArray(parsed.configuredIdes),
75
+ installedExtensions: asStringArray(parsed.installedExtensions),
76
+ userEmail: asNullableString(parsed.userEmail),
77
+ userName: asNullableString(parsed.userName),
78
+ setupCompleted: asBoolean(parsed.setupCompleted, DEFAULT_CONFIG.setupCompleted),
79
+ setupDate: asNullableString(parsed.setupDate),
80
+ enabledIdes: asStringArray(parsed.enabledIdes),
81
+ workspaces: Array.isArray(parsed.workspaces) ? parsed.workspaces : [],
82
+ defaultWorkspaceId: asNullableString(parsed.defaultWorkspaceId) ?? asNullableString(parsed.activeWorkspaceId),
83
+ recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
84
+ sessionReads: mergedSessionReads,
85
+ sessionReadMarkers,
86
+ machineNickname: asNullableString(parsed.machineNickname),
87
+ machineId: asOptionalString(parsed.machineId),
88
+ machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
89
+ registeredMachineId: asOptionalString(parsed.registeredMachineId),
90
+ providerSettings: isPlainObject(parsed.providerSettings) ? parsed.providerSettings : {},
91
+ ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
92
+ disableUpstream: asBoolean(parsed.disableUpstream, DEFAULT_CONFIG.disableUpstream ?? false),
93
+ providerDir: asOptionalString(parsed.providerDir)
94
+ };
95
+ }
46
96
  function generateMachineId() {
47
97
  return `${MACHINE_ID_PREFIX}${randomUUID().replace(/-/g, "")}`;
48
98
  }
@@ -86,14 +136,10 @@ function loadConfig() {
86
136
  try {
87
137
  const raw = readFileSync(configPath, "utf-8");
88
138
  const parsed = JSON.parse(raw);
89
- const merged = { ...DEFAULT_CONFIG, ...parsed };
90
- if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
91
- merged.defaultWorkspaceId = merged.activeWorkspaceId;
92
- }
93
- delete merged.activeWorkspaceId;
94
- const ensured = ensureMachineId(merged);
139
+ const normalizedInput = normalizeConfig(parsed);
140
+ const ensured = ensureMachineId(normalizedInput);
95
141
  const normalized = ensured.config;
96
- if (ensured.changed) {
142
+ if (ensured.changed || JSON.stringify(parsed) !== JSON.stringify(normalized)) {
97
143
  try {
98
144
  saveConfig(normalized);
99
145
  } catch {
@@ -108,10 +154,11 @@ function loadConfig() {
108
154
  function saveConfig(config) {
109
155
  const configPath = getConfigPath();
110
156
  const dir = getConfigDir();
157
+ const normalized = normalizeConfig(config);
111
158
  if (!existsSync(dir)) {
112
159
  mkdirSync(dir, { recursive: true, mode: 448 });
113
160
  }
114
- writeFileSync(configPath, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
161
+ writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
115
162
  try {
116
163
  chmodSync(configPath, 384);
117
164
  } catch {
@@ -140,32 +187,19 @@ function isSetupComplete() {
140
187
  function resetConfig() {
141
188
  saveConfig({ ...DEFAULT_CONFIG });
142
189
  }
143
- function generateConnectionToken() {
144
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
145
- let token = "db_";
146
- for (let i = 0; i < 32; i++) {
147
- token += chars.charAt(Math.floor(Math.random() * chars.length));
148
- }
149
- return token;
150
- }
151
190
  var DEFAULT_CONFIG, MACHINE_ID_PREFIX;
152
191
  var init_config = __esm({
153
192
  "src/config/config.ts"() {
154
193
  "use strict";
155
194
  DEFAULT_CONFIG = {
156
195
  serverUrl: "https://api.adhf.dev",
157
- apiToken: null,
158
- connectionToken: null,
159
196
  selectedIde: null,
160
197
  configuredIdes: [],
161
198
  installedExtensions: [],
162
- autoConnect: true,
163
- notifications: true,
164
199
  userEmail: null,
165
200
  userName: null,
166
201
  setupCompleted: false,
167
202
  setupDate: null,
168
- configuredCLIs: [],
169
203
  enabledIdes: [],
170
204
  workspaces: [],
171
205
  defaultWorkspaceId: null,
@@ -978,6 +1012,13 @@ var init_provider_cli_adapter = __esm({
978
1012
  this.messages = [...this.committedMessages];
979
1013
  this.structuredMessages = [...this.committedMessages];
980
1014
  }
1015
+ normalizeParsedMessages(parsedMessages) {
1016
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
1017
+ role: message.role,
1018
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
1019
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
1020
+ }));
1021
+ }
981
1022
  sliceFromOffset(text, start) {
982
1023
  if (!text) return "";
983
1024
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -1374,6 +1415,15 @@ var init_provider_cli_adapter = __esm({
1374
1415
  this.onStatusChange?.();
1375
1416
  }
1376
1417
  commitCurrentTranscript() {
1418
+ const parsed = this.parseCurrentTranscript(
1419
+ this.committedMessages,
1420
+ this.responseBuffer,
1421
+ this.currentTurnScope
1422
+ );
1423
+ if (parsed && Array.isArray(parsed.messages)) {
1424
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
1425
+ this.syncMessageViews();
1426
+ }
1377
1427
  }
1378
1428
  // ─── Script Execution ──────────────────────────
1379
1429
  runDetectStatus(text) {
@@ -1418,6 +1468,21 @@ var init_provider_cli_adapter = __esm({
1418
1468
  * Called by command handler / dashboard for rich content rendering.
1419
1469
  */
1420
1470
  getScriptParsedStatus() {
1471
+ const parsed = this.parseCurrentTranscript(
1472
+ this.committedMessages,
1473
+ this.responseBuffer,
1474
+ this.currentTurnScope
1475
+ );
1476
+ if (parsed && Array.isArray(parsed.messages)) {
1477
+ return {
1478
+ id: parsed.id || "cli_session",
1479
+ status: parsed.status || this.currentStatus,
1480
+ title: parsed.title || this.cliName,
1481
+ terminalHistory: this.terminalHistory,
1482
+ messages: parsed.messages,
1483
+ activeModal: parsed.activeModal ?? this.activeModal
1484
+ };
1485
+ }
1421
1486
  const messages = [...this.committedMessages];
1422
1487
  return {
1423
1488
  id: "cli_session",
@@ -3744,6 +3809,8 @@ var ExtensionProviderInstance = class {
3744
3809
  this.detectTransition(newStatus, data);
3745
3810
  this.currentStatus = newStatus;
3746
3811
  }
3812
+ } else if (event === "stream_reset") {
3813
+ this.resetStreamState();
3747
3814
  } else if (event === "extension_connected") {
3748
3815
  this.ideType = data?.ideType || "";
3749
3816
  }
@@ -3823,6 +3890,30 @@ var ExtensionProviderInstance = class {
3823
3890
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
3824
3891
  return title || this.agentName || this.provider.name;
3825
3892
  }
3893
+ resetStreamState() {
3894
+ if (this.currentStatus !== "idle") {
3895
+ this.detectTransition("idle", {
3896
+ title: this.chatTitle,
3897
+ agentName: this.agentName,
3898
+ extensionId: this.extensionId,
3899
+ messages: this.messages
3900
+ });
3901
+ }
3902
+ this.agentStreams = [];
3903
+ this.messages = [];
3904
+ this.activeModal = null;
3905
+ this.currentModel = "";
3906
+ this.currentMode = "";
3907
+ this.controlValues = {};
3908
+ this.currentStatus = "idle";
3909
+ this.chatId = null;
3910
+ this.chatTitle = null;
3911
+ this.agentName = "";
3912
+ this.extensionId = "";
3913
+ this.lastAgentStatus = "idle";
3914
+ this.generatingStartedAt = 0;
3915
+ this.monitor.reset();
3916
+ }
3826
3917
  };
3827
3918
 
3828
3919
  // src/config/chat-history.ts
@@ -4105,11 +4196,23 @@ var IdeProviderInstance = class {
4105
4196
  } else if (event === "cdp_disconnected") {
4106
4197
  this.cachedChat = null;
4107
4198
  this.currentStatus = "idle";
4199
+ for (const ext of this.extensions.values()) {
4200
+ ext.onEvent("stream_reset");
4201
+ }
4108
4202
  } else if (event === "stream_update") {
4109
4203
  const extType = data?.extensionType;
4110
4204
  if (extType && this.extensions.has(extType)) {
4111
4205
  this.extensions.get(extType).onEvent("stream_update", data);
4112
4206
  }
4207
+ } else if (event === "stream_reset") {
4208
+ const extType = data?.extensionType;
4209
+ if (extType && this.extensions.has(extType)) {
4210
+ this.extensions.get(extType).onEvent("stream_reset");
4211
+ }
4212
+ } else if (event === "stream_reset_all") {
4213
+ for (const ext of this.extensions.values()) {
4214
+ ext.onEvent("stream_reset");
4215
+ }
4113
4216
  }
4114
4217
  }
4115
4218
  dispose() {
@@ -4776,6 +4879,63 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
4776
4879
  "thinking",
4777
4880
  "active"
4778
4881
  ]);
4882
+ var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
4883
+ var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
4884
+ var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
4885
+ var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
4886
+ var STATUS_TERMINAL_HISTORY_LIMIT = 8 * 1024;
4887
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
4888
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
4889
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
4890
+ function truncateString(value, maxChars) {
4891
+ if (value.length <= maxChars) return value;
4892
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
4893
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
4894
+ }
4895
+ function truncateStringTail(value, maxChars) {
4896
+ if (value.length <= maxChars) return value;
4897
+ if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));
4898
+ return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;
4899
+ }
4900
+ function trimStructuredStrings(value, maxChars) {
4901
+ if (typeof value === "string") return truncateString(value, maxChars);
4902
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
4903
+ if (!value || typeof value !== "object") return value;
4904
+ return Object.fromEntries(
4905
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
4906
+ );
4907
+ }
4908
+ function estimateBytes(value) {
4909
+ try {
4910
+ return JSON.stringify(value).length;
4911
+ } catch {
4912
+ return String(value ?? "").length;
4913
+ }
4914
+ }
4915
+ function trimMessageForStatus(message, stringLimit) {
4916
+ if (!message || typeof message !== "object") return message;
4917
+ return trimStructuredStrings(message, stringLimit);
4918
+ }
4919
+ function trimMessagesForStatus(messages) {
4920
+ if (!Array.isArray(messages) || messages.length === 0) return [];
4921
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
4922
+ const kept = [];
4923
+ let totalBytes = 0;
4924
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
4925
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
4926
+ let size = estimateBytes(normalized);
4927
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
4928
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
4929
+ size = estimateBytes(normalized);
4930
+ }
4931
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
4932
+ continue;
4933
+ }
4934
+ kept.push(normalized);
4935
+ totalBytes += size;
4936
+ }
4937
+ return kept.reverse();
4938
+ }
4779
4939
  function hasApprovalButtons(activeModal) {
4780
4940
  return (activeModal?.buttons?.length ?? 0) > 0;
4781
4941
  }
@@ -4802,7 +4962,16 @@ function normalizeActiveChatData(activeChat) {
4802
4962
  if (!activeChat) return activeChat;
4803
4963
  return {
4804
4964
  ...activeChat,
4805
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
4965
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
4966
+ messages: trimMessagesForStatus(activeChat.messages),
4967
+ activeModal: activeChat.activeModal ? {
4968
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
4969
+ buttons: (activeChat.activeModal.buttons || []).map(
4970
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
4971
+ )
4972
+ } : activeChat.activeModal,
4973
+ terminalHistory: activeChat.terminalHistory ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT) : activeChat.terminalHistory,
4974
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
4806
4975
  };
4807
4976
  }
4808
4977
 
@@ -4900,6 +5069,11 @@ var PTY_SESSION_CAPABILITIES = [
4900
5069
  "terminal_io",
4901
5070
  "resize_terminal"
4902
5071
  ];
5072
+ var CLI_CHAT_SESSION_CAPABILITIES = [
5073
+ "read_chat",
5074
+ "send_message",
5075
+ "resolve_action"
5076
+ ];
4903
5077
  var ACP_SESSION_CAPABILITIES = [
4904
5078
  "read_chat",
4905
5079
  "send_message",
@@ -4989,9 +5163,10 @@ function buildCliSession(state) {
4989
5163
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
4990
5164
  runtimeWriteOwner: state.runtime?.writeOwner || null,
4991
5165
  runtimeAttachedClients: state.runtime?.attachedClients || [],
5166
+ mode: state.mode,
4992
5167
  resume: state.resume,
4993
5168
  activeChat,
4994
- capabilities: PTY_SESSION_CAPABILITIES,
5169
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
4995
5170
  controlValues: state.controlValues,
4996
5171
  providerControls: buildFallbackControls(
4997
5172
  state.providerControls
@@ -6165,6 +6340,13 @@ async function handleFileListBrowse(h, args) {
6165
6340
 
6166
6341
  // src/commands/stream-commands.ts
6167
6342
  init_logger();
6343
+ function getCliPresentationMode(h, targetSessionId) {
6344
+ if (!targetSessionId) return null;
6345
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
6346
+ if (instance?.category !== "cli") return null;
6347
+ const mode = instance.getPresentationMode?.();
6348
+ return mode === "chat" || mode === "terminal" ? mode : null;
6349
+ }
6168
6350
  async function handleFocusSession(h, args) {
6169
6351
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
6170
6352
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -6175,6 +6357,9 @@ async function handleFocusSession(h, args) {
6175
6357
  function handlePtyInput(h, args) {
6176
6358
  const { cliType, data, targetSessionId } = args || {};
6177
6359
  if (!data) return { success: false, error: "data required" };
6360
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6361
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6362
+ }
6178
6363
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6179
6364
  if (!adapter || typeof adapter.writeRaw !== "function") {
6180
6365
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -6185,6 +6370,9 @@ function handlePtyInput(h, args) {
6185
6370
  function handlePtyResize(h, args) {
6186
6371
  const { cliType, cols, rows, force, targetSessionId } = args || {};
6187
6372
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
6373
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6374
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6375
+ }
6188
6376
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6189
6377
  if (!adapter || typeof adapter.resize !== "function") {
6190
6378
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -8592,6 +8780,7 @@ var DaemonCommandRouter = class {
8592
8780
  // ─── CLI / ACP commands ───
8593
8781
  case "launch_cli":
8594
8782
  case "stop_cli":
8783
+ case "set_cli_view_mode":
8595
8784
  case "agent_command": {
8596
8785
  return this.deps.cliManager.handleCliCommand(cmd, args);
8597
8786
  }
@@ -8936,6 +9125,20 @@ var DaemonStatusReporter = class {
8936
9125
  ts() {
8937
9126
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
8938
9127
  }
9128
+ summarizeLargePayloadSessions(payload) {
9129
+ const sessions = Array.isArray(payload.sessions) ? payload.sessions : [];
9130
+ return sessions.map((session) => ({
9131
+ id: String(session?.id || ""),
9132
+ providerType: String(session?.providerType || ""),
9133
+ bytes: (() => {
9134
+ try {
9135
+ return JSON.stringify(session).length;
9136
+ } catch {
9137
+ return 0;
9138
+ }
9139
+ })()
9140
+ })).sort((a, b) => b.bytes - a.bytes).slice(0, 3).map((session) => `${session.providerType || "unknown"}:${session.id}=${session.bytes}b`).join(", ");
9141
+ }
8939
9142
  async sendUnifiedStatusReport(opts) {
8940
9143
  const { serverConn, p2p } = this.deps;
8941
9144
  if (!serverConn?.isConnected()) return;
@@ -8988,9 +9191,16 @@ var DaemonStatusReporter = class {
8988
9191
  screenshotUsage: this.deps.getScreenshotUsage?.() || null,
8989
9192
  connectedExtensions: []
8990
9193
  };
9194
+ const payloadBytes = JSON.stringify(payload).length;
8991
9195
  const p2pSent = this.sendP2PPayload(payload);
8992
9196
  if (p2pSent) {
8993
- LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
9197
+ LOG.debug("P2P", `sent (${payloadBytes} bytes)`);
9198
+ if (payloadBytes > 256 * 1024) {
9199
+ LOG.warn(
9200
+ "P2P",
9201
+ `large status payload (${payloadBytes} bytes) top sessions: ${this.summarizeLargePayloadSessions(payload) || "n/a"}`
9202
+ );
9203
+ }
8994
9204
  }
8995
9205
  if (opts?.p2pOnly) return;
8996
9206
  const wsPayload = {
@@ -9020,7 +9230,9 @@ var DaemonStatusReporter = class {
9020
9230
  acpModes: session.acpModes
9021
9231
  })),
9022
9232
  p2p: payload.p2p,
9023
- timestamp: now
9233
+ timestamp: now,
9234
+ detectedIdes: payload.detectedIdes,
9235
+ availableProviders: payload.availableProviders
9024
9236
  };
9025
9237
  serverConn.sendMessage("status_report", wsPayload);
9026
9238
  LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
@@ -9072,6 +9284,7 @@ var CliProviderInstance = class {
9072
9284
  this.cliArgs = cliArgs;
9073
9285
  this.type = provider.type;
9074
9286
  this.instanceId = instanceId || crypto3.randomUUID();
9287
+ this.presentationMode = "terminal";
9075
9288
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
9076
9289
  this.monitor = new StatusMonitor();
9077
9290
  this.historyWriter = new ChatHistoryWriter();
@@ -9090,6 +9303,7 @@ var CliProviderInstance = class {
9090
9303
  lastApprovalEventAt = 0;
9091
9304
  historyWriter;
9092
9305
  instanceId;
9306
+ presentationMode;
9093
9307
  // ─── Lifecycle ─────────────────────────────────
9094
9308
  async init(context) {
9095
9309
  this.context = context;
@@ -9114,6 +9328,7 @@ var CliProviderInstance = class {
9114
9328
  }
9115
9329
  getState() {
9116
9330
  const adapterStatus = this.adapter.getStatus();
9331
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9117
9332
  const runtime = this.adapter.getRuntimeMetadata();
9118
9333
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9119
9334
  if (adapterStatus.terminalHistory?.trim()) {
@@ -9129,13 +9344,13 @@ var CliProviderInstance = class {
9129
9344
  name: this.provider.name,
9130
9345
  category: "cli",
9131
9346
  status: adapterStatus.status,
9132
- mode: "terminal",
9347
+ mode: this.presentationMode,
9133
9348
  activeChat: {
9134
9349
  id: `${this.type}_${this.workingDir}`,
9135
- title: `${this.provider.name} \xB7 ${dirName}`,
9136
- status: adapterStatus.status,
9137
- messages: [],
9138
- activeModal: adapterStatus.activeModal,
9350
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
9351
+ status: parsedStatus?.status || adapterStatus.status,
9352
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
9353
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
9139
9354
  terminalHistory: adapterStatus.terminalHistory,
9140
9355
  inputContent: ""
9141
9356
  },
@@ -9158,6 +9373,13 @@ var CliProviderInstance = class {
9158
9373
  providerControls: this.provider.controls
9159
9374
  };
9160
9375
  }
9376
+ setPresentationMode(mode) {
9377
+ if (this.presentationMode === mode) return;
9378
+ this.presentationMode = mode;
9379
+ }
9380
+ getPresentationMode() {
9381
+ return this.presentationMode;
9382
+ }
9161
9383
  onEvent(event, data) {
9162
9384
  if (event === "send_message" && data?.text) {
9163
9385
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -10221,6 +10443,15 @@ var DaemonCliManager = class {
10221
10443
  const hash = __require("crypto").createHash("md5").update(__require("path").resolve(dir)).digest("hex").slice(0, 8);
10222
10444
  return `${cliType}_${hash}`;
10223
10445
  }
10446
+ getSessionPresentationMode(sessionId) {
10447
+ if (!sessionId) return null;
10448
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
10449
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
10450
+ return mode === "chat" || mode === "terminal" ? mode : null;
10451
+ }
10452
+ isTerminalSession(sessionId) {
10453
+ return this.getSessionPresentationMode(sessionId) === "terminal";
10454
+ }
10224
10455
  persistRecentActivity(entry) {
10225
10456
  try {
10226
10457
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -10399,6 +10630,7 @@ ${installInfo}`
10399
10630
  if (provider) {
10400
10631
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
10401
10632
  }
10633
+ const resolvedCliArgs = cliArgs;
10402
10634
  const instanceManager = this.deps.getInstanceManager();
10403
10635
  if (provider && instanceManager) {
10404
10636
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -10407,14 +10639,14 @@ ${installInfo}`
10407
10639
  normalizedType,
10408
10640
  cliType,
10409
10641
  resolvedDir,
10410
- cliArgs,
10642
+ resolvedCliArgs,
10411
10643
  resolvedProvider,
10412
10644
  {},
10413
10645
  false
10414
10646
  );
10415
10647
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
10416
10648
  } else {
10417
- const adapter = this.createAdapter(cliType, resolvedDir, cliArgs, key, false);
10649
+ const adapter = this.createAdapter(cliType, resolvedDir, resolvedCliArgs, key, false);
10418
10650
  try {
10419
10651
  await adapter.spawn();
10420
10652
  } catch (spawnErr) {
@@ -10564,6 +10796,14 @@ ${installInfo}`
10564
10796
  }
10565
10797
  return null;
10566
10798
  }
10799
+ findAdapterBySessionId(instanceKey) {
10800
+ if (!instanceKey) return null;
10801
+ let ik = instanceKey;
10802
+ const colonIdx = ik.lastIndexOf(":");
10803
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
10804
+ const adapter = this.adapters.get(ik);
10805
+ return adapter ? { adapter, key: ik } : null;
10806
+ }
10567
10807
  // ─── CLI command handling ────────────────────────────
10568
10808
  async handleCliCommand(cmd, args) {
10569
10809
  switch (cmd) {
@@ -10614,6 +10854,23 @@ ${installInfo}`
10614
10854
  }
10615
10855
  return { success: true, cliType, dir, stopped: true, mode };
10616
10856
  }
10857
+ case "set_cli_view_mode": {
10858
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
10859
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
10860
+ const cliType = args?.cliType || args?.agentType || "";
10861
+ const dir = args?.dir || "";
10862
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
10863
+ if (!found) {
10864
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
10865
+ }
10866
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
10867
+ if (!(instance instanceof CliProviderInstance)) {
10868
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
10869
+ }
10870
+ instance.setPresentationMode(mode);
10871
+ this.deps.onStatusChange();
10872
+ return { success: true, id: found.key, mode };
10873
+ }
10617
10874
  case "restart_session": {
10618
10875
  const cliType = args?.cliType || args?.agentType || args?.ideType;
10619
10876
  const cfg = loadConfig();
@@ -11232,7 +11489,12 @@ var AgentStreamPoller = class {
11232
11489
  } catch {
11233
11490
  }
11234
11491
  }
11235
- if (!resolvedActiveSessionId || !parentSessionId) continue;
11492
+ if (!resolvedActiveSessionId || !parentSessionId) {
11493
+ if (parentSessionId) {
11494
+ this.deps.onStreamsUpdated?.(ideType, []);
11495
+ }
11496
+ continue;
11497
+ }
11236
11498
  try {
11237
11499
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
11238
11500
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -11247,7 +11509,11 @@ var AgentStreamPoller = class {
11247
11509
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11248
11510
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
11249
11511
  if (!ideInstance?.onEvent) return;
11512
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
11250
11513
  for (const stream of streams) {
11514
+ if (typeof stream.agentType === "string" && stream.agentType) {
11515
+ seenExtensionTypes.add(stream.agentType);
11516
+ }
11251
11517
  ideInstance.onEvent("stream_update", {
11252
11518
  extensionType: stream.agentType,
11253
11519
  streams: [stream],
@@ -11264,6 +11530,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11264
11530
  inputContent: stream.inputContent || ""
11265
11531
  });
11266
11532
  }
11533
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
11534
+ if (streams.length === 0) {
11535
+ ideInstance.onEvent("stream_reset_all");
11536
+ return;
11537
+ }
11538
+ for (const extensionType of extensionTypes) {
11539
+ if (!seenExtensionTypes.has(extensionType)) {
11540
+ ideInstance.onEvent("stream_reset", { extensionType });
11541
+ }
11542
+ }
11267
11543
  }
11268
11544
 
11269
11545
  // src/providers/provider-instance-manager.ts