@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.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,11 +5163,10 @@ function buildCliSession(state) {
4989
5163
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
4990
5164
  runtimeWriteOwner: state.runtime?.writeOwner || null,
4991
5165
  runtimeAttachedClients: state.runtime?.attachedClients || [],
4992
- launchMode: state.launchMode,
4993
5166
  mode: state.mode,
4994
5167
  resume: state.resume,
4995
5168
  activeChat,
4996
- capabilities: PTY_SESSION_CAPABILITIES,
5169
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
4997
5170
  controlValues: state.controlValues,
4998
5171
  providerControls: buildFallbackControls(
4999
5172
  state.providerControls
@@ -6167,6 +6340,13 @@ async function handleFileListBrowse(h, args) {
6167
6340
 
6168
6341
  // src/commands/stream-commands.ts
6169
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
+ }
6170
6350
  async function handleFocusSession(h, args) {
6171
6351
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
6172
6352
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -6177,6 +6357,9 @@ async function handleFocusSession(h, args) {
6177
6357
  function handlePtyInput(h, args) {
6178
6358
  const { cliType, data, targetSessionId } = args || {};
6179
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
+ }
6180
6363
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6181
6364
  if (!adapter || typeof adapter.writeRaw !== "function") {
6182
6365
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -6187,6 +6370,9 @@ function handlePtyInput(h, args) {
6187
6370
  function handlePtyResize(h, args) {
6188
6371
  const { cliType, cols, rows, force, targetSessionId } = args || {};
6189
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
+ }
6190
6376
  const adapter = h.getCliAdapter(targetSessionId || cliType);
6191
6377
  if (!adapter || typeof adapter.resize !== "function") {
6192
6378
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -8594,6 +8780,7 @@ var DaemonCommandRouter = class {
8594
8780
  // ─── CLI / ACP commands ───
8595
8781
  case "launch_cli":
8596
8782
  case "stop_cli":
8783
+ case "set_cli_view_mode":
8597
8784
  case "agent_command": {
8598
8785
  return this.deps.cliManager.handleCliCommand(cmd, args);
8599
8786
  }
@@ -8938,6 +9125,20 @@ var DaemonStatusReporter = class {
8938
9125
  ts() {
8939
9126
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
8940
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
+ }
8941
9142
  async sendUnifiedStatusReport(opts) {
8942
9143
  const { serverConn, p2p } = this.deps;
8943
9144
  if (!serverConn?.isConnected()) return;
@@ -8990,9 +9191,16 @@ var DaemonStatusReporter = class {
8990
9191
  screenshotUsage: this.deps.getScreenshotUsage?.() || null,
8991
9192
  connectedExtensions: []
8992
9193
  };
9194
+ const payloadBytes = JSON.stringify(payload).length;
8993
9195
  const p2pSent = this.sendP2PPayload(payload);
8994
9196
  if (p2pSent) {
8995
- 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
+ }
8996
9204
  }
8997
9205
  if (opts?.p2pOnly) return;
8998
9206
  const wsPayload = {
@@ -9022,7 +9230,9 @@ var DaemonStatusReporter = class {
9022
9230
  acpModes: session.acpModes
9023
9231
  })),
9024
9232
  p2p: payload.p2p,
9025
- timestamp: now
9233
+ timestamp: now,
9234
+ detectedIdes: payload.detectedIdes,
9235
+ availableProviders: payload.availableProviders
9026
9236
  };
9027
9237
  serverConn.sendMessage("status_report", wsPayload);
9028
9238
  LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
@@ -9068,14 +9278,13 @@ init_provider_cli_adapter();
9068
9278
  import * as crypto3 from "crypto";
9069
9279
  init_logger();
9070
9280
  var CliProviderInstance = class {
9071
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
9281
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
9072
9282
  this.provider = provider;
9073
9283
  this.workingDir = workingDir;
9074
9284
  this.cliArgs = cliArgs;
9075
9285
  this.type = provider.type;
9076
9286
  this.instanceId = instanceId || crypto3.randomUUID();
9077
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
9078
- this.resolvedOutputFormat = this.resolveOutputFormat();
9287
+ this.presentationMode = "terminal";
9079
9288
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
9080
9289
  this.monitor = new StatusMonitor();
9081
9290
  this.historyWriter = new ChatHistoryWriter();
@@ -9094,26 +9303,7 @@ var CliProviderInstance = class {
9094
9303
  lastApprovalEventAt = 0;
9095
9304
  historyWriter;
9096
9305
  instanceId;
9097
- launchMode;
9098
- resolvedOutputFormat;
9099
- /**
9100
- * Determine output rendering format from:
9101
- * 1. launchMode.outputFormat (explicit override)
9102
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
9103
- * 3. Default: 'terminal'
9104
- */
9105
- resolveOutputFormat() {
9106
- if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
9107
- if (this.provider.launchOptions?.length) {
9108
- for (const opt of this.provider.launchOptions) {
9109
- if (!opt.outputFormatMap) continue;
9110
- for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
9111
- if (this.cliArgs.includes(val)) return fmt;
9112
- }
9113
- }
9114
- }
9115
- return "terminal";
9116
- }
9306
+ presentationMode;
9117
9307
  // ─── Lifecycle ─────────────────────────────────
9118
9308
  async init(context) {
9119
9309
  this.context = context;
@@ -9138,6 +9328,7 @@ var CliProviderInstance = class {
9138
9328
  }
9139
9329
  getState() {
9140
9330
  const adapterStatus = this.adapter.getStatus();
9331
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9141
9332
  const runtime = this.adapter.getRuntimeMetadata();
9142
9333
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9143
9334
  if (adapterStatus.terminalHistory?.trim()) {
@@ -9153,14 +9344,13 @@ var CliProviderInstance = class {
9153
9344
  name: this.provider.name,
9154
9345
  category: "cli",
9155
9346
  status: adapterStatus.status,
9156
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
9157
- launchMode: this.launchMode?.id,
9347
+ mode: this.presentationMode,
9158
9348
  activeChat: {
9159
9349
  id: `${this.type}_${this.workingDir}`,
9160
- title: `${this.provider.name} \xB7 ${dirName}`,
9161
- status: adapterStatus.status,
9162
- messages: [],
9163
- 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,
9164
9354
  terminalHistory: adapterStatus.terminalHistory,
9165
9355
  inputContent: ""
9166
9356
  },
@@ -9183,6 +9373,13 @@ var CliProviderInstance = class {
9183
9373
  providerControls: this.provider.controls
9184
9374
  };
9185
9375
  }
9376
+ setPresentationMode(mode) {
9377
+ if (this.presentationMode === mode) return;
9378
+ this.presentationMode = mode;
9379
+ }
9380
+ getPresentationMode() {
9381
+ return this.presentationMode;
9382
+ }
9186
9383
  onEvent(event, data) {
9187
9384
  if (event === "send_message" && data?.text) {
9188
9385
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -10246,6 +10443,15 @@ var DaemonCliManager = class {
10246
10443
  const hash = __require("crypto").createHash("md5").update(__require("path").resolve(dir)).digest("hex").slice(0, 8);
10247
10444
  return `${cliType}_${hash}`;
10248
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
+ }
10249
10455
  persistRecentActivity(entry) {
10250
10456
  try {
10251
10457
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -10301,12 +10507,12 @@ var DaemonCliManager = class {
10301
10507
  }
10302
10508
  }, 3e3);
10303
10509
  }
10304
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
10510
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
10305
10511
  const instanceManager = this.deps.getInstanceManager();
10306
10512
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
10307
10513
  if (!instanceManager) throw new Error("InstanceManager not available");
10308
10514
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
10309
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
10515
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
10310
10516
  try {
10311
10517
  await instanceManager.addInstance(key, cliInstance, {
10312
10518
  serverConn: this.deps.getServerConn(),
@@ -10332,7 +10538,7 @@ var DaemonCliManager = class {
10332
10538
  this.startCliExitMonitor(key, cliType);
10333
10539
  }
10334
10540
  // ─── Session start/management ──────────────────────────────
10335
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
10541
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
10336
10542
  const trimmed = (workingDir || "").trim();
10337
10543
  if (!trimmed) throw new Error("working directory required");
10338
10544
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -10424,29 +10630,7 @@ ${installInfo}`
10424
10630
  if (provider) {
10425
10631
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
10426
10632
  }
10427
- let resolvedCliArgs = cliArgs;
10428
- let resolvedLaunchMode = launchMode;
10429
- const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
10430
- if (activeMode) {
10431
- resolvedLaunchMode = activeMode.id;
10432
- }
10433
- if (provider?.launchArgBuilder) {
10434
- const defaults = {};
10435
- for (const opt of provider.launchOptions || []) {
10436
- if (opt.default !== void 0) defaults[opt.id] = opt.default;
10437
- }
10438
- const modeOptions = activeMode?.options || {};
10439
- const userOptions = launchOptionValues || {};
10440
- const merged = { ...defaults, ...modeOptions, ...userOptions };
10441
- const extraArgs = provider.launchArgBuilder(merged);
10442
- if (extraArgs.length) {
10443
- resolvedCliArgs = [...cliArgs || [], ...extraArgs];
10444
- console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
10445
- }
10446
- } else if (activeMode?.extraArgs?.length) {
10447
- resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
10448
- console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
10449
- }
10633
+ const resolvedCliArgs = cliArgs;
10450
10634
  const instanceManager = this.deps.getInstanceManager();
10451
10635
  if (provider && instanceManager) {
10452
10636
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -10458,8 +10642,7 @@ ${installInfo}`
10458
10642
  resolvedCliArgs,
10459
10643
  resolvedProvider,
10460
10644
  {},
10461
- false,
10462
- resolvedLaunchMode
10645
+ false
10463
10646
  );
10464
10647
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
10465
10648
  } else {
@@ -10571,8 +10754,7 @@ ${installInfo}`
10571
10754
  record.cliArgs,
10572
10755
  resolvedProvider,
10573
10756
  {},
10574
- true,
10575
- record.launchMode
10757
+ true
10576
10758
  );
10577
10759
  restored += 1;
10578
10760
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record.runtimeKey || record.runtimeId} (${record.displayName || record.workspace})`);
@@ -10614,6 +10796,14 @@ ${installInfo}`
10614
10796
  }
10615
10797
  return null;
10616
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
+ }
10617
10807
  // ─── CLI command handling ────────────────────────────
10618
10808
  async handleCliCommand(cmd, args) {
10619
10809
  switch (cmd) {
@@ -10642,7 +10832,7 @@ ${installInfo}`
10642
10832
  const dir = resolved.path;
10643
10833
  const launchSource = resolved.source;
10644
10834
  if (!cliType) throw new Error("cliType required");
10645
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
10835
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
10646
10836
  let newKey = null;
10647
10837
  for (const [k, adapter] of this.adapters) {
10648
10838
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -10664,6 +10854,23 @@ ${installInfo}`
10664
10854
  }
10665
10855
  return { success: true, cliType, dir, stopped: true, mode };
10666
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
+ }
10667
10874
  case "restart_session": {
10668
10875
  const cliType = args?.cliType || args?.agentType || args?.ideType;
10669
10876
  const cfg = loadConfig();
@@ -11282,7 +11489,12 @@ var AgentStreamPoller = class {
11282
11489
  } catch {
11283
11490
  }
11284
11491
  }
11285
- if (!resolvedActiveSessionId || !parentSessionId) continue;
11492
+ if (!resolvedActiveSessionId || !parentSessionId) {
11493
+ if (parentSessionId) {
11494
+ this.deps.onStreamsUpdated?.(ideType, []);
11495
+ }
11496
+ continue;
11497
+ }
11286
11498
  try {
11287
11499
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
11288
11500
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -11297,7 +11509,11 @@ var AgentStreamPoller = class {
11297
11509
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11298
11510
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
11299
11511
  if (!ideInstance?.onEvent) return;
11512
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
11300
11513
  for (const stream of streams) {
11514
+ if (typeof stream.agentType === "string" && stream.agentType) {
11515
+ seenExtensionTypes.add(stream.agentType);
11516
+ }
11301
11517
  ideInstance.onEvent("stream_update", {
11302
11518
  extensionType: stream.agentType,
11303
11519
  streams: [stream],
@@ -11314,6 +11530,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
11314
11530
  inputContent: stream.inputContent || ""
11315
11531
  });
11316
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
+ }
11317
11543
  }
11318
11544
 
11319
11545
  // src/providers/provider-instance-manager.ts