@adhdev/daemon-core 0.7.41 → 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.
Files changed (37) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +1 -0
  2. package/dist/commands/cli-manager.d.ts +4 -2
  3. package/dist/config/config.d.ts +2 -22
  4. package/dist/index.js +314 -88
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +314 -88
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/providers/cli-provider-instance.d.ts +4 -10
  9. package/dist/providers/contracts.d.ts +0 -79
  10. package/dist/providers/extension-provider-instance.d.ts +1 -0
  11. package/dist/providers/provider-instance.d.ts +0 -2
  12. package/dist/shared-types.d.ts +1 -3
  13. package/dist/status/normalize.js +67 -1
  14. package/dist/status/normalize.js.map +1 -1
  15. package/dist/status/normalize.mjs +67 -1
  16. package/dist/status/normalize.mjs.map +1 -1
  17. package/dist/status/reporter.d.ts +1 -0
  18. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  19. package/package.json +1 -1
  20. package/src/agent-stream/forward.ts +21 -1
  21. package/src/agent-stream/poller.ts +6 -1
  22. package/src/cli-adapters/provider-cli-adapter.ts +37 -2
  23. package/src/commands/cli-manager.ts +44 -39
  24. package/src/commands/router.ts +1 -0
  25. package/src/commands/stream-commands.ts +14 -0
  26. package/src/config/config.d.ts +5 -50
  27. package/src/config/config.ts +71 -49
  28. package/src/config/workspaces.d.ts +1 -4
  29. package/src/providers/cli-provider-instance.ts +18 -32
  30. package/src/providers/contracts.ts +0 -81
  31. package/src/providers/extension-provider-instance.ts +27 -0
  32. package/src/providers/ide-provider-instance.ts +12 -0
  33. package/src/providers/provider-instance.ts +0 -2
  34. package/src/shared-types.ts +1 -3
  35. package/src/status/builders.ts +7 -2
  36. package/src/status/normalize.ts +85 -0
  37. 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,
@@ -983,6 +1017,13 @@ var init_provider_cli_adapter = __esm({
983
1017
  this.messages = [...this.committedMessages];
984
1018
  this.structuredMessages = [...this.committedMessages];
985
1019
  }
1020
+ normalizeParsedMessages(parsedMessages) {
1021
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
1022
+ role: message.role,
1023
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
1024
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
1025
+ }));
1026
+ }
986
1027
  sliceFromOffset(text, start) {
987
1028
  if (!text) return "";
988
1029
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -1379,6 +1420,15 @@ var init_provider_cli_adapter = __esm({
1379
1420
  this.onStatusChange?.();
1380
1421
  }
1381
1422
  commitCurrentTranscript() {
1423
+ const parsed = this.parseCurrentTranscript(
1424
+ this.committedMessages,
1425
+ this.responseBuffer,
1426
+ this.currentTurnScope
1427
+ );
1428
+ if (parsed && Array.isArray(parsed.messages)) {
1429
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
1430
+ this.syncMessageViews();
1431
+ }
1382
1432
  }
1383
1433
  // ─── Script Execution ──────────────────────────
1384
1434
  runDetectStatus(text) {
@@ -1423,6 +1473,21 @@ var init_provider_cli_adapter = __esm({
1423
1473
  * Called by command handler / dashboard for rich content rendering.
1424
1474
  */
1425
1475
  getScriptParsedStatus() {
1476
+ const parsed = this.parseCurrentTranscript(
1477
+ this.committedMessages,
1478
+ this.responseBuffer,
1479
+ this.currentTurnScope
1480
+ );
1481
+ if (parsed && Array.isArray(parsed.messages)) {
1482
+ return {
1483
+ id: parsed.id || "cli_session",
1484
+ status: parsed.status || this.currentStatus,
1485
+ title: parsed.title || this.cliName,
1486
+ terminalHistory: this.terminalHistory,
1487
+ messages: parsed.messages,
1488
+ activeModal: parsed.activeModal ?? this.activeModal
1489
+ };
1490
+ }
1426
1491
  const messages = [...this.committedMessages];
1427
1492
  return {
1428
1493
  id: "cli_session",
@@ -3823,6 +3888,8 @@ var ExtensionProviderInstance = class {
3823
3888
  this.detectTransition(newStatus, data);
3824
3889
  this.currentStatus = newStatus;
3825
3890
  }
3891
+ } else if (event === "stream_reset") {
3892
+ this.resetStreamState();
3826
3893
  } else if (event === "extension_connected") {
3827
3894
  this.ideType = data?.ideType || "";
3828
3895
  }
@@ -3902,6 +3969,30 @@ var ExtensionProviderInstance = class {
3902
3969
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
3903
3970
  return title || this.agentName || this.provider.name;
3904
3971
  }
3972
+ resetStreamState() {
3973
+ if (this.currentStatus !== "idle") {
3974
+ this.detectTransition("idle", {
3975
+ title: this.chatTitle,
3976
+ agentName: this.agentName,
3977
+ extensionId: this.extensionId,
3978
+ messages: this.messages
3979
+ });
3980
+ }
3981
+ this.agentStreams = [];
3982
+ this.messages = [];
3983
+ this.activeModal = null;
3984
+ this.currentModel = "";
3985
+ this.currentMode = "";
3986
+ this.controlValues = {};
3987
+ this.currentStatus = "idle";
3988
+ this.chatId = null;
3989
+ this.chatTitle = null;
3990
+ this.agentName = "";
3991
+ this.extensionId = "";
3992
+ this.lastAgentStatus = "idle";
3993
+ this.generatingStartedAt = 0;
3994
+ this.monitor.reset();
3995
+ }
3905
3996
  };
3906
3997
 
3907
3998
  // src/config/chat-history.ts
@@ -4184,11 +4275,23 @@ var IdeProviderInstance = class {
4184
4275
  } else if (event === "cdp_disconnected") {
4185
4276
  this.cachedChat = null;
4186
4277
  this.currentStatus = "idle";
4278
+ for (const ext of this.extensions.values()) {
4279
+ ext.onEvent("stream_reset");
4280
+ }
4187
4281
  } else if (event === "stream_update") {
4188
4282
  const extType = data?.extensionType;
4189
4283
  if (extType && this.extensions.has(extType)) {
4190
4284
  this.extensions.get(extType).onEvent("stream_update", data);
4191
4285
  }
4286
+ } else if (event === "stream_reset") {
4287
+ const extType = data?.extensionType;
4288
+ if (extType && this.extensions.has(extType)) {
4289
+ this.extensions.get(extType).onEvent("stream_reset");
4290
+ }
4291
+ } else if (event === "stream_reset_all") {
4292
+ for (const ext of this.extensions.values()) {
4293
+ ext.onEvent("stream_reset");
4294
+ }
4192
4295
  }
4193
4296
  }
4194
4297
  dispose() {
@@ -4855,6 +4958,63 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
4855
4958
  "thinking",
4856
4959
  "active"
4857
4960
  ]);
4961
+ var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
4962
+ var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
4963
+ var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
4964
+ var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
4965
+ var STATUS_TERMINAL_HISTORY_LIMIT = 8 * 1024;
4966
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
4967
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
4968
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
4969
+ function truncateString(value, maxChars) {
4970
+ if (value.length <= maxChars) return value;
4971
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
4972
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
4973
+ }
4974
+ function truncateStringTail(value, maxChars) {
4975
+ if (value.length <= maxChars) return value;
4976
+ if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));
4977
+ return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;
4978
+ }
4979
+ function trimStructuredStrings(value, maxChars) {
4980
+ if (typeof value === "string") return truncateString(value, maxChars);
4981
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
4982
+ if (!value || typeof value !== "object") return value;
4983
+ return Object.fromEntries(
4984
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
4985
+ );
4986
+ }
4987
+ function estimateBytes(value) {
4988
+ try {
4989
+ return JSON.stringify(value).length;
4990
+ } catch {
4991
+ return String(value ?? "").length;
4992
+ }
4993
+ }
4994
+ function trimMessageForStatus(message, stringLimit) {
4995
+ if (!message || typeof message !== "object") return message;
4996
+ return trimStructuredStrings(message, stringLimit);
4997
+ }
4998
+ function trimMessagesForStatus(messages) {
4999
+ if (!Array.isArray(messages) || messages.length === 0) return [];
5000
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
5001
+ const kept = [];
5002
+ let totalBytes = 0;
5003
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
5004
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
5005
+ let size = estimateBytes(normalized);
5006
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
5007
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
5008
+ size = estimateBytes(normalized);
5009
+ }
5010
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
5011
+ continue;
5012
+ }
5013
+ kept.push(normalized);
5014
+ totalBytes += size;
5015
+ }
5016
+ return kept.reverse();
5017
+ }
4858
5018
  function hasApprovalButtons(activeModal) {
4859
5019
  return (activeModal?.buttons?.length ?? 0) > 0;
4860
5020
  }
@@ -4881,7 +5041,16 @@ function normalizeActiveChatData(activeChat) {
4881
5041
  if (!activeChat) return activeChat;
4882
5042
  return {
4883
5043
  ...activeChat,
4884
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
5044
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
5045
+ messages: trimMessagesForStatus(activeChat.messages),
5046
+ activeModal: activeChat.activeModal ? {
5047
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
5048
+ buttons: (activeChat.activeModal.buttons || []).map(
5049
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
5050
+ )
5051
+ } : activeChat.activeModal,
5052
+ terminalHistory: activeChat.terminalHistory ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT) : activeChat.terminalHistory,
5053
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
4885
5054
  };
4886
5055
  }
4887
5056
 
@@ -4979,6 +5148,11 @@ var PTY_SESSION_CAPABILITIES = [
4979
5148
  "terminal_io",
4980
5149
  "resize_terminal"
4981
5150
  ];
5151
+ var CLI_CHAT_SESSION_CAPABILITIES = [
5152
+ "read_chat",
5153
+ "send_message",
5154
+ "resolve_action"
5155
+ ];
4982
5156
  var ACP_SESSION_CAPABILITIES = [
4983
5157
  "read_chat",
4984
5158
  "send_message",
@@ -5068,11 +5242,10 @@ function buildCliSession(state) {
5068
5242
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
5069
5243
  runtimeWriteOwner: state.runtime?.writeOwner || null,
5070
5244
  runtimeAttachedClients: state.runtime?.attachedClients || [],
5071
- launchMode: state.launchMode,
5072
5245
  mode: state.mode,
5073
5246
  resume: state.resume,
5074
5247
  activeChat,
5075
- capabilities: PTY_SESSION_CAPABILITIES,
5248
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
5076
5249
  controlValues: state.controlValues,
5077
5250
  providerControls: buildFallbackControls(
5078
5251
  state.providerControls
@@ -6246,6 +6419,13 @@ async function handleFileListBrowse(h, args) {
6246
6419
 
6247
6420
  // src/commands/stream-commands.ts
6248
6421
  init_logger();
6422
+ function getCliPresentationMode(h, targetSessionId) {
6423
+ if (!targetSessionId) return null;
6424
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
6425
+ if (instance?.category !== "cli") return null;
6426
+ const mode = instance.getPresentationMode?.();
6427
+ return mode === "chat" || mode === "terminal" ? mode : null;
6428
+ }
6249
6429
  async function handleFocusSession(h, args) {
6250
6430
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
6251
6431
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -6256,6 +6436,9 @@ async function handleFocusSession(h, args) {
6256
6436
  function handlePtyInput(h, args) {
6257
6437
  const { cliType, data, targetSessionId } = args || {};
6258
6438
  if (!data) return { success: false, error: "data required" };
6439
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6440
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6441
+ }
6259
6442
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6260
6443
  if (!adapter || typeof adapter.writeRaw !== "function") {
6261
6444
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -6266,6 +6449,9 @@ function handlePtyInput(h, args) {
6266
6449
  function handlePtyResize(h, args) {
6267
6450
  const { cliType, cols, rows, force, targetSessionId } = args || {};
6268
6451
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
6452
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
6453
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
6454
+ }
6269
6455
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6270
6456
  if (!adapter || typeof adapter.resize !== "function") {
6271
6457
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -8673,6 +8859,7 @@ var DaemonCommandRouter = class {
8673
8859
  // ─── CLI / ACP commands ───
8674
8860
  case "launch_cli":
8675
8861
  case "stop_cli":
8862
+ case "set_cli_view_mode":
8676
8863
  case "agent_command": {
8677
8864
  return this.deps.cliManager.handleCliCommand(cmd, args);
8678
8865
  }
@@ -9017,6 +9204,20 @@ var DaemonStatusReporter = class {
9017
9204
  ts() {
9018
9205
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
9019
9206
  }
9207
+ summarizeLargePayloadSessions(payload) {
9208
+ const sessions = Array.isArray(payload.sessions) ? payload.sessions : [];
9209
+ return sessions.map((session) => ({
9210
+ id: String(session?.id || ""),
9211
+ providerType: String(session?.providerType || ""),
9212
+ bytes: (() => {
9213
+ try {
9214
+ return JSON.stringify(session).length;
9215
+ } catch {
9216
+ return 0;
9217
+ }
9218
+ })()
9219
+ })).sort((a, b) => b.bytes - a.bytes).slice(0, 3).map((session) => `${session.providerType || "unknown"}:${session.id}=${session.bytes}b`).join(", ");
9220
+ }
9020
9221
  async sendUnifiedStatusReport(opts) {
9021
9222
  const { serverConn, p2p } = this.deps;
9022
9223
  if (!serverConn?.isConnected()) return;
@@ -9069,9 +9270,16 @@ var DaemonStatusReporter = class {
9069
9270
  screenshotUsage: this.deps.getScreenshotUsage?.() || null,
9070
9271
  connectedExtensions: []
9071
9272
  };
9273
+ const payloadBytes = JSON.stringify(payload).length;
9072
9274
  const p2pSent = this.sendP2PPayload(payload);
9073
9275
  if (p2pSent) {
9074
- LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
9276
+ LOG.debug("P2P", `sent (${payloadBytes} bytes)`);
9277
+ if (payloadBytes > 256 * 1024) {
9278
+ LOG.warn(
9279
+ "P2P",
9280
+ `large status payload (${payloadBytes} bytes) top sessions: ${this.summarizeLargePayloadSessions(payload) || "n/a"}`
9281
+ );
9282
+ }
9075
9283
  }
9076
9284
  if (opts?.p2pOnly) return;
9077
9285
  const wsPayload = {
@@ -9101,7 +9309,9 @@ var DaemonStatusReporter = class {
9101
9309
  acpModes: session.acpModes
9102
9310
  })),
9103
9311
  p2p: payload.p2p,
9104
- timestamp: now
9312
+ timestamp: now,
9313
+ detectedIdes: payload.detectedIdes,
9314
+ availableProviders: payload.availableProviders
9105
9315
  };
9106
9316
  serverConn.sendMessage("status_report", wsPayload);
9107
9317
  LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
@@ -9147,14 +9357,13 @@ var crypto3 = __toESM(require("crypto"));
9147
9357
  init_provider_cli_adapter();
9148
9358
  init_logger();
9149
9359
  var CliProviderInstance = class {
9150
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
9360
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
9151
9361
  this.provider = provider;
9152
9362
  this.workingDir = workingDir;
9153
9363
  this.cliArgs = cliArgs;
9154
9364
  this.type = provider.type;
9155
9365
  this.instanceId = instanceId || crypto3.randomUUID();
9156
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
9157
- this.resolvedOutputFormat = this.resolveOutputFormat();
9366
+ this.presentationMode = "terminal";
9158
9367
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
9159
9368
  this.monitor = new StatusMonitor();
9160
9369
  this.historyWriter = new ChatHistoryWriter();
@@ -9173,26 +9382,7 @@ var CliProviderInstance = class {
9173
9382
  lastApprovalEventAt = 0;
9174
9383
  historyWriter;
9175
9384
  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
- }
9385
+ presentationMode;
9196
9386
  // ─── Lifecycle ─────────────────────────────────
9197
9387
  async init(context) {
9198
9388
  this.context = context;
@@ -9217,6 +9407,7 @@ var CliProviderInstance = class {
9217
9407
  }
9218
9408
  getState() {
9219
9409
  const adapterStatus = this.adapter.getStatus();
9410
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9220
9411
  const runtime = this.adapter.getRuntimeMetadata();
9221
9412
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9222
9413
  if (adapterStatus.terminalHistory?.trim()) {
@@ -9232,14 +9423,13 @@ var CliProviderInstance = class {
9232
9423
  name: this.provider.name,
9233
9424
  category: "cli",
9234
9425
  status: adapterStatus.status,
9235
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
9236
- launchMode: this.launchMode?.id,
9426
+ mode: this.presentationMode,
9237
9427
  activeChat: {
9238
9428
  id: `${this.type}_${this.workingDir}`,
9239
- title: `${this.provider.name} \xB7 ${dirName}`,
9240
- status: adapterStatus.status,
9241
- messages: [],
9242
- activeModal: adapterStatus.activeModal,
9429
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
9430
+ status: parsedStatus?.status || adapterStatus.status,
9431
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
9432
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
9243
9433
  terminalHistory: adapterStatus.terminalHistory,
9244
9434
  inputContent: ""
9245
9435
  },
@@ -9262,6 +9452,13 @@ var CliProviderInstance = class {
9262
9452
  providerControls: this.provider.controls
9263
9453
  };
9264
9454
  }
9455
+ setPresentationMode(mode) {
9456
+ if (this.presentationMode === mode) return;
9457
+ this.presentationMode = mode;
9458
+ }
9459
+ getPresentationMode() {
9460
+ return this.presentationMode;
9461
+ }
9265
9462
  onEvent(event, data) {
9266
9463
  if (event === "send_message" && data?.text) {
9267
9464
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -10320,6 +10517,15 @@ var DaemonCliManager = class {
10320
10517
  const hash = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
10321
10518
  return `${cliType}_${hash}`;
10322
10519
  }
10520
+ getSessionPresentationMode(sessionId) {
10521
+ if (!sessionId) return null;
10522
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
10523
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
10524
+ return mode === "chat" || mode === "terminal" ? mode : null;
10525
+ }
10526
+ isTerminalSession(sessionId) {
10527
+ return this.getSessionPresentationMode(sessionId) === "terminal";
10528
+ }
10323
10529
  persistRecentActivity(entry) {
10324
10530
  try {
10325
10531
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -10375,12 +10581,12 @@ var DaemonCliManager = class {
10375
10581
  }
10376
10582
  }, 3e3);
10377
10583
  }
10378
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
10584
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
10379
10585
  const instanceManager = this.deps.getInstanceManager();
10380
10586
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
10381
10587
  if (!instanceManager) throw new Error("InstanceManager not available");
10382
10588
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
10383
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
10589
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
10384
10590
  try {
10385
10591
  await instanceManager.addInstance(key, cliInstance, {
10386
10592
  serverConn: this.deps.getServerConn(),
@@ -10406,7 +10612,7 @@ var DaemonCliManager = class {
10406
10612
  this.startCliExitMonitor(key, cliType);
10407
10613
  }
10408
10614
  // ─── Session start/management ──────────────────────────────
10409
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
10615
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
10410
10616
  const trimmed = (workingDir || "").trim();
10411
10617
  if (!trimmed) throw new Error("working directory required");
10412
10618
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -10498,29 +10704,7 @@ ${installInfo}`
10498
10704
  if (provider) {
10499
10705
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
10500
10706
  }
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
- }
10707
+ const resolvedCliArgs = cliArgs;
10524
10708
  const instanceManager = this.deps.getInstanceManager();
10525
10709
  if (provider && instanceManager) {
10526
10710
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -10532,8 +10716,7 @@ ${installInfo}`
10532
10716
  resolvedCliArgs,
10533
10717
  resolvedProvider,
10534
10718
  {},
10535
- false,
10536
- resolvedLaunchMode
10719
+ false
10537
10720
  );
10538
10721
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
10539
10722
  } else {
@@ -10645,8 +10828,7 @@ ${installInfo}`
10645
10828
  record.cliArgs,
10646
10829
  resolvedProvider,
10647
10830
  {},
10648
- true,
10649
- record.launchMode
10831
+ true
10650
10832
  );
10651
10833
  restored += 1;
10652
10834
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record.runtimeKey || record.runtimeId} (${record.displayName || record.workspace})`);
@@ -10688,6 +10870,14 @@ ${installInfo}`
10688
10870
  }
10689
10871
  return null;
10690
10872
  }
10873
+ findAdapterBySessionId(instanceKey) {
10874
+ if (!instanceKey) return null;
10875
+ let ik = instanceKey;
10876
+ const colonIdx = ik.lastIndexOf(":");
10877
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
10878
+ const adapter = this.adapters.get(ik);
10879
+ return adapter ? { adapter, key: ik } : null;
10880
+ }
10691
10881
  // ─── CLI command handling ────────────────────────────
10692
10882
  async handleCliCommand(cmd, args) {
10693
10883
  switch (cmd) {
@@ -10716,7 +10906,7 @@ ${installInfo}`
10716
10906
  const dir = resolved.path;
10717
10907
  const launchSource = resolved.source;
10718
10908
  if (!cliType) throw new Error("cliType required");
10719
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
10909
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
10720
10910
  let newKey = null;
10721
10911
  for (const [k, adapter] of this.adapters) {
10722
10912
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -10738,6 +10928,23 @@ ${installInfo}`
10738
10928
  }
10739
10929
  return { success: true, cliType, dir, stopped: true, mode };
10740
10930
  }
10931
+ case "set_cli_view_mode": {
10932
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
10933
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
10934
+ const cliType = args?.cliType || args?.agentType || "";
10935
+ const dir = args?.dir || "";
10936
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
10937
+ if (!found) {
10938
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
10939
+ }
10940
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
10941
+ if (!(instance instanceof CliProviderInstance)) {
10942
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
10943
+ }
10944
+ instance.setPresentationMode(mode);
10945
+ this.deps.onStatusChange();
10946
+ return { success: true, id: found.key, mode };
10947
+ }
10741
10948
  case "restart_session": {
10742
10949
  const cliType = args?.cliType || args?.agentType || args?.ideType;
10743
10950
  const cfg = loadConfig();
@@ -11356,7 +11563,12 @@ var AgentStreamPoller = class {
11356
11563
  } catch {
11357
11564
  }
11358
11565
  }
11359
- if (!resolvedActiveSessionId || !parentSessionId) continue;
11566
+ if (!resolvedActiveSessionId || !parentSessionId) {
11567
+ if (parentSessionId) {
11568
+ this.deps.onStreamsUpdated?.(ideType, []);
11569
+ }
11570
+ continue;
11571
+ }
11360
11572
  try {
11361
11573
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
11362
11574
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -11371,7 +11583,11 @@ var AgentStreamPoller = class {
11371
11583
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11372
11584
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
11373
11585
  if (!ideInstance?.onEvent) return;
11586
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
11374
11587
  for (const stream of streams) {
11588
+ if (typeof stream.agentType === "string" && stream.agentType) {
11589
+ seenExtensionTypes.add(stream.agentType);
11590
+ }
11375
11591
  ideInstance.onEvent("stream_update", {
11376
11592
  extensionType: stream.agentType,
11377
11593
  streams: [stream],
@@ -11388,6 +11604,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11388
11604
  inputContent: stream.inputContent || ""
11389
11605
  });
11390
11606
  }
11607
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
11608
+ if (streams.length === 0) {
11609
+ ideInstance.onEvent("stream_reset_all");
11610
+ return;
11611
+ }
11612
+ for (const extensionType of extensionTypes) {
11613
+ if (!seenExtensionTypes.has(extensionType)) {
11614
+ ideInstance.onEvent("stream_reset", { extensionType });
11615
+ }
11616
+ }
11391
11617
  }
11392
11618
 
11393
11619
  // src/providers/provider-instance-manager.ts