@adhdev/daemon-standalone 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.
package/dist/index.js CHANGED
@@ -18296,7 +18296,6 @@ var __copyProps2 = (to, from, except, desc) => {
18296
18296
  var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
18297
18297
  var config_exports = {};
18298
18298
  __export2(config_exports, {
18299
- generateConnectionToken: () => generateConnectionToken,
18300
18299
  generateMachineId: () => generateMachineId,
18301
18300
  getConfigDir: () => getConfigDir,
18302
18301
  isSetupComplete: () => isSetupComplete,
@@ -18307,6 +18306,57 @@ __export2(config_exports, {
18307
18306
  saveConfig: () => saveConfig,
18308
18307
  updateConfig: () => updateConfig
18309
18308
  });
18309
+ function isPlainObject2(value) {
18310
+ return !!value && typeof value === "object" && !Array.isArray(value);
18311
+ }
18312
+ function asStringArray(value) {
18313
+ if (!Array.isArray(value)) return [];
18314
+ return value.filter((item) => typeof item === "string");
18315
+ }
18316
+ function asNullableString(value) {
18317
+ return typeof value === "string" ? value : null;
18318
+ }
18319
+ function asOptionalString(value) {
18320
+ return typeof value === "string" && value.trim() ? value : void 0;
18321
+ }
18322
+ function asBoolean(value, fallback) {
18323
+ return typeof value === "boolean" ? value : fallback;
18324
+ }
18325
+ function normalizeConfig(raw) {
18326
+ const parsed = isPlainObject2(raw) ? raw : {};
18327
+ const legacySessionReads = isPlainObject2(parsed.recentSessionReads) ? parsed.recentSessionReads : {};
18328
+ const sessionReads = isPlainObject2(parsed.sessionReads) ? parsed.sessionReads : {};
18329
+ const mergedSessionReads = Object.fromEntries(
18330
+ Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
18331
+ );
18332
+ const sessionReadMarkers = Object.fromEntries(
18333
+ Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
18334
+ );
18335
+ return {
18336
+ serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
18337
+ selectedIde: asNullableString(parsed.selectedIde),
18338
+ configuredIdes: asStringArray(parsed.configuredIdes),
18339
+ installedExtensions: asStringArray(parsed.installedExtensions),
18340
+ userEmail: asNullableString(parsed.userEmail),
18341
+ userName: asNullableString(parsed.userName),
18342
+ setupCompleted: asBoolean(parsed.setupCompleted, DEFAULT_CONFIG.setupCompleted),
18343
+ setupDate: asNullableString(parsed.setupDate),
18344
+ enabledIdes: asStringArray(parsed.enabledIdes),
18345
+ workspaces: Array.isArray(parsed.workspaces) ? parsed.workspaces : [],
18346
+ defaultWorkspaceId: asNullableString(parsed.defaultWorkspaceId) ?? asNullableString(parsed.activeWorkspaceId),
18347
+ recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
18348
+ sessionReads: mergedSessionReads,
18349
+ sessionReadMarkers,
18350
+ machineNickname: asNullableString(parsed.machineNickname),
18351
+ machineId: asOptionalString(parsed.machineId),
18352
+ machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
18353
+ registeredMachineId: asOptionalString(parsed.registeredMachineId),
18354
+ providerSettings: isPlainObject2(parsed.providerSettings) ? parsed.providerSettings : {},
18355
+ ideSettings: isPlainObject2(parsed.ideSettings) ? parsed.ideSettings : {},
18356
+ disableUpstream: asBoolean(parsed.disableUpstream, DEFAULT_CONFIG.disableUpstream ?? false),
18357
+ providerDir: asOptionalString(parsed.providerDir)
18358
+ };
18359
+ }
18310
18360
  function generateMachineId() {
18311
18361
  return `${MACHINE_ID_PREFIX}${(0, import_crypto2.randomUUID)().replace(/-/g, "")}`;
18312
18362
  }
@@ -18350,14 +18400,10 @@ function loadConfig() {
18350
18400
  try {
18351
18401
  const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
18352
18402
  const parsed = JSON.parse(raw);
18353
- const merged = { ...DEFAULT_CONFIG, ...parsed };
18354
- if (merged.defaultWorkspaceId == null && merged.activeWorkspaceId != null) {
18355
- merged.defaultWorkspaceId = merged.activeWorkspaceId;
18356
- }
18357
- delete merged.activeWorkspaceId;
18358
- const ensured = ensureMachineId(merged);
18403
+ const normalizedInput = normalizeConfig(parsed);
18404
+ const ensured = ensureMachineId(normalizedInput);
18359
18405
  const normalized = ensured.config;
18360
- if (ensured.changed) {
18406
+ if (ensured.changed || JSON.stringify(parsed) !== JSON.stringify(normalized)) {
18361
18407
  try {
18362
18408
  saveConfig(normalized);
18363
18409
  } catch {
@@ -18372,10 +18418,11 @@ function loadConfig() {
18372
18418
  function saveConfig(config2) {
18373
18419
  const configPath = getConfigPath();
18374
18420
  const dir = getConfigDir();
18421
+ const normalized = normalizeConfig(config2);
18375
18422
  if (!(0, import_fs.existsSync)(dir)) {
18376
18423
  (0, import_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
18377
18424
  }
18378
- (0, import_fs.writeFileSync)(configPath, JSON.stringify(config2, null, 2), { encoding: "utf-8", mode: 384 });
18425
+ (0, import_fs.writeFileSync)(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
18379
18426
  try {
18380
18427
  (0, import_fs.chmodSync)(configPath, 384);
18381
18428
  } catch {
@@ -18404,14 +18451,6 @@ function isSetupComplete() {
18404
18451
  function resetConfig() {
18405
18452
  saveConfig({ ...DEFAULT_CONFIG });
18406
18453
  }
18407
- function generateConnectionToken() {
18408
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
18409
- let token = "db_";
18410
- for (let i = 0; i < 32; i++) {
18411
- token += chars.charAt(Math.floor(Math.random() * chars.length));
18412
- }
18413
- return token;
18414
- }
18415
18454
  var DEFAULT_CONFIG;
18416
18455
  var MACHINE_ID_PREFIX;
18417
18456
  var init_config = __esm2({
@@ -18419,18 +18458,13 @@ var init_config = __esm2({
18419
18458
  "use strict";
18420
18459
  DEFAULT_CONFIG = {
18421
18460
  serverUrl: "https://api.adhf.dev",
18422
- apiToken: null,
18423
- connectionToken: null,
18424
18461
  selectedIde: null,
18425
18462
  configuredIdes: [],
18426
18463
  installedExtensions: [],
18427
- autoConnect: true,
18428
- notifications: true,
18429
18464
  userEmail: null,
18430
18465
  userName: null,
18431
18466
  setupCompleted: false,
18432
18467
  setupDate: null,
18433
- configuredCLIs: [],
18434
18468
  enabledIdes: [],
18435
18469
  workspaces: [],
18436
18470
  defaultWorkspaceId: null,
@@ -19242,6 +19276,13 @@ var init_provider_cli_adapter = __esm2({
19242
19276
  this.messages = [...this.committedMessages];
19243
19277
  this.structuredMessages = [...this.committedMessages];
19244
19278
  }
19279
+ normalizeParsedMessages(parsedMessages) {
19280
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
19281
+ role: message.role,
19282
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
19283
+ timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
19284
+ }));
19285
+ }
19245
19286
  sliceFromOffset(text, start) {
19246
19287
  if (!text) return "";
19247
19288
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -19638,6 +19679,15 @@ var init_provider_cli_adapter = __esm2({
19638
19679
  this.onStatusChange?.();
19639
19680
  }
19640
19681
  commitCurrentTranscript() {
19682
+ const parsed = this.parseCurrentTranscript(
19683
+ this.committedMessages,
19684
+ this.responseBuffer,
19685
+ this.currentTurnScope
19686
+ );
19687
+ if (parsed && Array.isArray(parsed.messages)) {
19688
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
19689
+ this.syncMessageViews();
19690
+ }
19641
19691
  }
19642
19692
  // ─── Script Execution ──────────────────────────
19643
19693
  runDetectStatus(text) {
@@ -19682,6 +19732,21 @@ var init_provider_cli_adapter = __esm2({
19682
19732
  * Called by command handler / dashboard for rich content rendering.
19683
19733
  */
19684
19734
  getScriptParsedStatus() {
19735
+ const parsed = this.parseCurrentTranscript(
19736
+ this.committedMessages,
19737
+ this.responseBuffer,
19738
+ this.currentTurnScope
19739
+ );
19740
+ if (parsed && Array.isArray(parsed.messages)) {
19741
+ return {
19742
+ id: parsed.id || "cli_session",
19743
+ status: parsed.status || this.currentStatus,
19744
+ title: parsed.title || this.cliName,
19745
+ terminalHistory: this.terminalHistory,
19746
+ messages: parsed.messages,
19747
+ activeModal: parsed.activeModal ?? this.activeModal
19748
+ };
19749
+ }
19685
19750
  const messages = [...this.committedMessages];
19686
19751
  return {
19687
19752
  id: "cli_session",
@@ -21971,6 +22036,8 @@ var ExtensionProviderInstance = class {
21971
22036
  this.detectTransition(newStatus, data);
21972
22037
  this.currentStatus = newStatus;
21973
22038
  }
22039
+ } else if (event === "stream_reset") {
22040
+ this.resetStreamState();
21974
22041
  } else if (event === "extension_connected") {
21975
22042
  this.ideType = data?.ideType || "";
21976
22043
  }
@@ -22050,6 +22117,30 @@ var ExtensionProviderInstance = class {
22050
22117
  const title = typeof data?.title === "string" && data.title.trim() ? data.title.trim() : this.chatTitle;
22051
22118
  return title || this.agentName || this.provider.name;
22052
22119
  }
22120
+ resetStreamState() {
22121
+ if (this.currentStatus !== "idle") {
22122
+ this.detectTransition("idle", {
22123
+ title: this.chatTitle,
22124
+ agentName: this.agentName,
22125
+ extensionId: this.extensionId,
22126
+ messages: this.messages
22127
+ });
22128
+ }
22129
+ this.agentStreams = [];
22130
+ this.messages = [];
22131
+ this.activeModal = null;
22132
+ this.currentModel = "";
22133
+ this.currentMode = "";
22134
+ this.controlValues = {};
22135
+ this.currentStatus = "idle";
22136
+ this.chatId = null;
22137
+ this.chatTitle = null;
22138
+ this.agentName = "";
22139
+ this.extensionId = "";
22140
+ this.lastAgentStatus = "idle";
22141
+ this.generatingStartedAt = 0;
22142
+ this.monitor.reset();
22143
+ }
22053
22144
  };
22054
22145
  var HISTORY_DIR = path4.join(os5.homedir(), ".adhdev", "history");
22055
22146
  var RETAIN_DAYS = 30;
@@ -22325,11 +22416,23 @@ var IdeProviderInstance = class {
22325
22416
  } else if (event === "cdp_disconnected") {
22326
22417
  this.cachedChat = null;
22327
22418
  this.currentStatus = "idle";
22419
+ for (const ext of this.extensions.values()) {
22420
+ ext.onEvent("stream_reset");
22421
+ }
22328
22422
  } else if (event === "stream_update") {
22329
22423
  const extType = data?.extensionType;
22330
22424
  if (extType && this.extensions.has(extType)) {
22331
22425
  this.extensions.get(extType).onEvent("stream_update", data);
22332
22426
  }
22427
+ } else if (event === "stream_reset") {
22428
+ const extType = data?.extensionType;
22429
+ if (extType && this.extensions.has(extType)) {
22430
+ this.extensions.get(extType).onEvent("stream_reset");
22431
+ }
22432
+ } else if (event === "stream_reset_all") {
22433
+ for (const ext of this.extensions.values()) {
22434
+ ext.onEvent("stream_reset");
22435
+ }
22333
22436
  }
22334
22437
  }
22335
22438
  dispose() {
@@ -22836,6 +22939,63 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
22836
22939
  "thinking",
22837
22940
  "active"
22838
22941
  ]);
22942
+ var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
22943
+ var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
22944
+ var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
22945
+ var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
22946
+ var STATUS_TERMINAL_HISTORY_LIMIT = 8 * 1024;
22947
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
22948
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
22949
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
22950
+ function truncateString(value, maxChars) {
22951
+ if (value.length <= maxChars) return value;
22952
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
22953
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
22954
+ }
22955
+ function truncateStringTail(value, maxChars) {
22956
+ if (value.length <= maxChars) return value;
22957
+ if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));
22958
+ return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;
22959
+ }
22960
+ function trimStructuredStrings(value, maxChars) {
22961
+ if (typeof value === "string") return truncateString(value, maxChars);
22962
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
22963
+ if (!value || typeof value !== "object") return value;
22964
+ return Object.fromEntries(
22965
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
22966
+ );
22967
+ }
22968
+ function estimateBytes(value) {
22969
+ try {
22970
+ return JSON.stringify(value).length;
22971
+ } catch {
22972
+ return String(value ?? "").length;
22973
+ }
22974
+ }
22975
+ function trimMessageForStatus(message, stringLimit) {
22976
+ if (!message || typeof message !== "object") return message;
22977
+ return trimStructuredStrings(message, stringLimit);
22978
+ }
22979
+ function trimMessagesForStatus(messages) {
22980
+ if (!Array.isArray(messages) || messages.length === 0) return [];
22981
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
22982
+ const kept = [];
22983
+ let totalBytes = 0;
22984
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
22985
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
22986
+ let size = estimateBytes(normalized);
22987
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
22988
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
22989
+ size = estimateBytes(normalized);
22990
+ }
22991
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
22992
+ continue;
22993
+ }
22994
+ kept.push(normalized);
22995
+ totalBytes += size;
22996
+ }
22997
+ return kept.reverse();
22998
+ }
22839
22999
  function hasApprovalButtons(activeModal) {
22840
23000
  return (activeModal?.buttons?.length ?? 0) > 0;
22841
23001
  }
@@ -22856,7 +23016,16 @@ function normalizeActiveChatData(activeChat) {
22856
23016
  if (!activeChat) return activeChat;
22857
23017
  return {
22858
23018
  ...activeChat,
22859
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
23019
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
23020
+ messages: trimMessagesForStatus(activeChat.messages),
23021
+ activeModal: activeChat.activeModal ? {
23022
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
23023
+ buttons: (activeChat.activeModal.buttons || []).map(
23024
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
23025
+ )
23026
+ } : activeChat.activeModal,
23027
+ terminalHistory: activeChat.terminalHistory ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT) : activeChat.terminalHistory,
23028
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
22860
23029
  };
22861
23030
  }
22862
23031
  function findCdpManager(cdpManagers, key) {
@@ -22944,6 +23113,11 @@ var PTY_SESSION_CAPABILITIES = [
22944
23113
  "terminal_io",
22945
23114
  "resize_terminal"
22946
23115
  ];
23116
+ var CLI_CHAT_SESSION_CAPABILITIES = [
23117
+ "read_chat",
23118
+ "send_message",
23119
+ "resolve_action"
23120
+ ];
22947
23121
  var ACP_SESSION_CAPABILITIES = [
22948
23122
  "read_chat",
22949
23123
  "send_message",
@@ -23033,11 +23207,10 @@ function buildCliSession(state) {
23033
23207
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
23034
23208
  runtimeWriteOwner: state.runtime?.writeOwner || null,
23035
23209
  runtimeAttachedClients: state.runtime?.attachedClients || [],
23036
- launchMode: state.launchMode,
23037
23210
  mode: state.mode,
23038
23211
  resume: state.resume,
23039
23212
  activeChat,
23040
- capabilities: PTY_SESSION_CAPABILITIES,
23213
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
23041
23214
  controlValues: state.controlValues,
23042
23215
  providerControls: buildFallbackControls(
23043
23216
  state.providerControls
@@ -24200,6 +24373,13 @@ async function handleFileListBrowse(h, args) {
24200
24373
  return handleFileList(h, args);
24201
24374
  }
24202
24375
  init_logger();
24376
+ function getCliPresentationMode(h, targetSessionId) {
24377
+ if (!targetSessionId) return null;
24378
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
24379
+ if (instance?.category !== "cli") return null;
24380
+ const mode = instance.getPresentationMode?.();
24381
+ return mode === "chat" || mode === "terminal" ? mode : null;
24382
+ }
24203
24383
  async function handleFocusSession(h, args) {
24204
24384
  if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
24205
24385
  const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
@@ -24210,6 +24390,9 @@ async function handleFocusSession(h, args) {
24210
24390
  function handlePtyInput(h, args) {
24211
24391
  const { cliType, data, targetSessionId } = args || {};
24212
24392
  if (!data) return { success: false, error: "data required" };
24393
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
24394
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
24395
+ }
24213
24396
  const adapter = h.getCliAdapter(targetSessionId || cliType);
24214
24397
  if (!adapter || typeof adapter.writeRaw !== "function") {
24215
24398
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -24220,6 +24403,9 @@ function handlePtyInput(h, args) {
24220
24403
  function handlePtyResize(h, args) {
24221
24404
  const { cliType, cols, rows, force, targetSessionId } = args || {};
24222
24405
  if (!cols || !rows) return { success: false, error: "cols and rows required" };
24406
+ if (getCliPresentationMode(h, targetSessionId) === "chat") {
24407
+ return { success: false, error: "CLI session is in chat mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" };
24408
+ }
24223
24409
  const adapter = h.getCliAdapter(targetSessionId || cliType);
24224
24410
  if (!adapter || typeof adapter.resize !== "function") {
24225
24411
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
@@ -26566,6 +26752,7 @@ var DaemonCommandRouter = class {
26566
26752
  // ─── CLI / ACP commands ───
26567
26753
  case "launch_cli":
26568
26754
  case "stop_cli":
26755
+ case "set_cli_view_mode":
26569
26756
  case "agent_command": {
26570
26757
  return this.deps.cliManager.handleCliCommand(cmd, args);
26571
26758
  }
@@ -26840,14 +27027,13 @@ init_config();
26840
27027
  init_provider_cli_adapter();
26841
27028
  init_logger();
26842
27029
  var CliProviderInstance = class {
26843
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
27030
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
26844
27031
  this.provider = provider;
26845
27032
  this.workingDir = workingDir;
26846
27033
  this.cliArgs = cliArgs;
26847
27034
  this.type = provider.type;
26848
27035
  this.instanceId = instanceId || crypto3.randomUUID();
26849
- this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
26850
- this.resolvedOutputFormat = this.resolveOutputFormat();
27036
+ this.presentationMode = "terminal";
26851
27037
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
26852
27038
  this.monitor = new StatusMonitor();
26853
27039
  this.historyWriter = new ChatHistoryWriter();
@@ -26866,26 +27052,7 @@ var CliProviderInstance = class {
26866
27052
  lastApprovalEventAt = 0;
26867
27053
  historyWriter;
26868
27054
  instanceId;
26869
- launchMode;
26870
- resolvedOutputFormat;
26871
- /**
26872
- * Determine output rendering format from:
26873
- * 1. launchMode.outputFormat (explicit override)
26874
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
26875
- * 3. Default: 'terminal'
26876
- */
26877
- resolveOutputFormat() {
26878
- if (this.launchMode?.outputFormat) return this.launchMode.outputFormat;
26879
- if (this.provider.launchOptions?.length) {
26880
- for (const opt of this.provider.launchOptions) {
26881
- if (!opt.outputFormatMap) continue;
26882
- for (const [val, fmt] of Object.entries(opt.outputFormatMap)) {
26883
- if (this.cliArgs.includes(val)) return fmt;
26884
- }
26885
- }
26886
- }
26887
- return "terminal";
26888
- }
27055
+ presentationMode;
26889
27056
  // ─── Lifecycle ─────────────────────────────────
26890
27057
  async init(context) {
26891
27058
  this.context = context;
@@ -26910,6 +27077,7 @@ var CliProviderInstance = class {
26910
27077
  }
26911
27078
  getState() {
26912
27079
  const adapterStatus = this.adapter.getStatus();
27080
+ const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
26913
27081
  const runtime = this.adapter.getRuntimeMetadata();
26914
27082
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
26915
27083
  if (adapterStatus.terminalHistory?.trim()) {
@@ -26925,14 +27093,13 @@ var CliProviderInstance = class {
26925
27093
  name: this.provider.name,
26926
27094
  category: "cli",
26927
27095
  status: adapterStatus.status,
26928
- mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
26929
- launchMode: this.launchMode?.id,
27096
+ mode: this.presentationMode,
26930
27097
  activeChat: {
26931
27098
  id: `${this.type}_${this.workingDir}`,
26932
- title: `${this.provider.name} \xB7 ${dirName}`,
26933
- status: adapterStatus.status,
26934
- messages: [],
26935
- activeModal: adapterStatus.activeModal,
27099
+ title: parsedStatus?.title || `${this.provider.name} \xB7 ${dirName}`,
27100
+ status: parsedStatus?.status || adapterStatus.status,
27101
+ messages: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [],
27102
+ activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
26936
27103
  terminalHistory: adapterStatus.terminalHistory,
26937
27104
  inputContent: ""
26938
27105
  },
@@ -26955,6 +27122,13 @@ var CliProviderInstance = class {
26955
27122
  providerControls: this.provider.controls
26956
27123
  };
26957
27124
  }
27125
+ setPresentationMode(mode) {
27126
+ if (this.presentationMode === mode) return;
27127
+ this.presentationMode = mode;
27128
+ }
27129
+ getPresentationMode() {
27130
+ return this.presentationMode;
27131
+ }
26958
27132
  onEvent(event, data) {
26959
27133
  if (event === "send_message" && data?.text) {
26960
27134
  void this.adapter.sendMessage(data.text).catch((e) => {
@@ -28002,6 +28176,15 @@ var DaemonCliManager = class {
28002
28176
  const hash2 = __require("crypto").createHash("md5").update(__require("path").resolve(dir)).digest("hex").slice(0, 8);
28003
28177
  return `${cliType}_${hash2}`;
28004
28178
  }
28179
+ getSessionPresentationMode(sessionId) {
28180
+ if (!sessionId) return null;
28181
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId);
28182
+ const mode = instance?.category === "cli" ? instance.getPresentationMode?.() : null;
28183
+ return mode === "chat" || mode === "terminal" ? mode : null;
28184
+ }
28185
+ isTerminalSession(sessionId) {
28186
+ return this.getSessionPresentationMode(sessionId) === "terminal";
28187
+ }
28005
28188
  persistRecentActivity(entry) {
28006
28189
  try {
28007
28190
  saveConfig(appendRecentActivity(loadConfig(), entry));
@@ -28057,12 +28240,12 @@ var DaemonCliManager = class {
28057
28240
  }
28058
28241
  }, 3e3);
28059
28242
  }
28060
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
28243
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
28061
28244
  const instanceManager = this.deps.getInstanceManager();
28062
28245
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
28063
28246
  if (!instanceManager) throw new Error("InstanceManager not available");
28064
28247
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
28065
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
28248
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
28066
28249
  try {
28067
28250
  await instanceManager.addInstance(key, cliInstance, {
28068
28251
  serverConn: this.deps.getServerConn(),
@@ -28088,7 +28271,7 @@ var DaemonCliManager = class {
28088
28271
  this.startCliExitMonitor(key, cliType);
28089
28272
  }
28090
28273
  // ─── Session start/management ──────────────────────────────
28091
- async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
28274
+ async startSession(cliType, workingDir, cliArgs, initialModel) {
28092
28275
  const trimmed = (workingDir || "").trim();
28093
28276
  if (!trimmed) throw new Error("working directory required");
28094
28277
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -28180,29 +28363,7 @@ ${installInfo}`
28180
28363
  if (provider) {
28181
28364
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
28182
28365
  }
28183
- let resolvedCliArgs = cliArgs;
28184
- let resolvedLaunchMode = launchMode;
28185
- const activeMode = provider?.launchModes?.length ? launchMode ? provider.launchModes.find((m) => m.id === launchMode) : provider.launchModes.find((m) => m.default) : void 0;
28186
- if (activeMode) {
28187
- resolvedLaunchMode = activeMode.id;
28188
- }
28189
- if (provider?.launchArgBuilder) {
28190
- const defaults = {};
28191
- for (const opt of provider.launchOptions || []) {
28192
- if (opt.default !== void 0) defaults[opt.id] = opt.default;
28193
- }
28194
- const modeOptions = activeMode?.options || {};
28195
- const userOptions = launchOptionValues || {};
28196
- const merged = { ...defaults, ...modeOptions, ...userOptions };
28197
- const extraArgs = provider.launchArgBuilder(merged);
28198
- if (extraArgs.length) {
28199
- resolvedCliArgs = [...cliArgs || [], ...extraArgs];
28200
- console.log(colorize("cyan", ` \u{1F680} Launch options applied: ${extraArgs.join(" ")}`));
28201
- }
28202
- } else if (activeMode?.extraArgs?.length) {
28203
- resolvedCliArgs = [...cliArgs || [], ...activeMode.extraArgs];
28204
- console.log(colorize("cyan", ` \u{1F680} Launch mode '${activeMode.name}': appending args ${activeMode.extraArgs.join(" ")}`));
28205
- }
28366
+ const resolvedCliArgs = cliArgs;
28206
28367
  const instanceManager = this.deps.getInstanceManager();
28207
28368
  if (provider && instanceManager) {
28208
28369
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -28214,8 +28375,7 @@ ${installInfo}`
28214
28375
  resolvedCliArgs,
28215
28376
  resolvedProvider,
28216
28377
  {},
28217
- false,
28218
- resolvedLaunchMode
28378
+ false
28219
28379
  );
28220
28380
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
28221
28381
  } else {
@@ -28327,8 +28487,7 @@ ${installInfo}`
28327
28487
  record2.cliArgs,
28328
28488
  resolvedProvider,
28329
28489
  {},
28330
- true,
28331
- record2.launchMode
28490
+ true
28332
28491
  );
28333
28492
  restored += 1;
28334
28493
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record2.runtimeKey || record2.runtimeId} (${record2.displayName || record2.workspace})`);
@@ -28370,6 +28529,14 @@ ${installInfo}`
28370
28529
  }
28371
28530
  return null;
28372
28531
  }
28532
+ findAdapterBySessionId(instanceKey) {
28533
+ if (!instanceKey) return null;
28534
+ let ik = instanceKey;
28535
+ const colonIdx = ik.lastIndexOf(":");
28536
+ if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
28537
+ const adapter = this.adapters.get(ik);
28538
+ return adapter ? { adapter, key: ik } : null;
28539
+ }
28373
28540
  // ─── CLI command handling ────────────────────────────
28374
28541
  async handleCliCommand(cmd, args) {
28375
28542
  switch (cmd) {
@@ -28398,7 +28565,7 @@ ${installInfo}`
28398
28565
  const dir = resolved.path;
28399
28566
  const launchSource = resolved.source;
28400
28567
  if (!cliType) throw new Error("cliType required");
28401
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
28568
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
28402
28569
  let newKey = null;
28403
28570
  for (const [k, adapter] of this.adapters) {
28404
28571
  if (adapter.cliType === cliType && adapter.workingDir === dir) {
@@ -28420,6 +28587,23 @@ ${installInfo}`
28420
28587
  }
28421
28588
  return { success: true, cliType, dir, stopped: true, mode };
28422
28589
  }
28590
+ case "set_cli_view_mode": {
28591
+ const mode = args?.mode === "chat" ? "chat" : "terminal";
28592
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId : "";
28593
+ const cliType = args?.cliType || args?.agentType || "";
28594
+ const dir = args?.dir || "";
28595
+ const found = this.findAdapterBySessionId(targetSessionId) || (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
28596
+ if (!found) {
28597
+ return { success: false, error: "CLI session not found", code: "CLI_SESSION_NOT_FOUND" };
28598
+ }
28599
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
28600
+ if (!(instance instanceof CliProviderInstance)) {
28601
+ return { success: false, error: "CLI instance not found", code: "CLI_INSTANCE_NOT_FOUND" };
28602
+ }
28603
+ instance.setPresentationMode(mode);
28604
+ this.deps.onStatusChange();
28605
+ return { success: true, id: found.key, mode };
28606
+ }
28423
28607
  case "restart_session": {
28424
28608
  const cliType = args?.cliType || args?.agentType || args?.ideType;
28425
28609
  const cfg = loadConfig();
@@ -29028,7 +29212,12 @@ var AgentStreamPoller = class {
29028
29212
  } catch {
29029
29213
  }
29030
29214
  }
29031
- if (!resolvedActiveSessionId || !parentSessionId) continue;
29215
+ if (!resolvedActiveSessionId || !parentSessionId) {
29216
+ if (parentSessionId) {
29217
+ this.deps.onStreamsUpdated?.(ideType, []);
29218
+ }
29219
+ continue;
29220
+ }
29032
29221
  try {
29033
29222
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
29034
29223
  const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
@@ -29041,7 +29230,11 @@ var AgentStreamPoller = class {
29041
29230
  function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
29042
29231
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
29043
29232
  if (!ideInstance?.onEvent) return;
29233
+ const seenExtensionTypes = /* @__PURE__ */ new Set();
29044
29234
  for (const stream of streams) {
29235
+ if (typeof stream.agentType === "string" && stream.agentType) {
29236
+ seenExtensionTypes.add(stream.agentType);
29237
+ }
29045
29238
  ideInstance.onEvent("stream_update", {
29046
29239
  extensionType: stream.agentType,
29047
29240
  streams: [stream],
@@ -29058,6 +29251,16 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
29058
29251
  inputContent: stream.inputContent || ""
29059
29252
  });
29060
29253
  }
29254
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
29255
+ if (streams.length === 0) {
29256
+ ideInstance.onEvent("stream_reset_all");
29257
+ return;
29258
+ }
29259
+ for (const extensionType of extensionTypes) {
29260
+ if (!seenExtensionTypes.has(extensionType)) {
29261
+ ideInstance.onEvent("stream_reset", { extensionType });
29262
+ }
29263
+ }
29061
29264
  }
29062
29265
  init_logger();
29063
29266
  var ProviderInstanceManager = class {
@@ -34333,6 +34536,16 @@ var StandaloneServer = class {
34333
34536
  await client.connect();
34334
34537
  return client;
34335
34538
  }
34539
+ getCliPresentationMode(sessionId) {
34540
+ if (!sessionId || !this.components) return null;
34541
+ const instance = this.components.instanceManager.getInstance(sessionId);
34542
+ if (instance?.category !== "cli") return null;
34543
+ const mode = instance.getPresentationMode?.();
34544
+ return mode === "chat" || mode === "terminal" ? mode : null;
34545
+ }
34546
+ isTerminalCliSession(sessionId) {
34547
+ return this.getCliPresentationMode(sessionId) === "terminal";
34548
+ }
34336
34549
  async start(options = {}) {
34337
34550
  const port = options.port || DEFAULT_PORT;
34338
34551
  const host = options.host || "127.0.0.1";
@@ -34344,8 +34557,8 @@ var StandaloneServer = class {
34344
34557
  getServerConn: () => null,
34345
34558
  getP2p: () => ({
34346
34559
  broadcastPtyOutput: (key, data) => {
34347
- if (this.clients.size === 0) return;
34348
- const msg = JSON.stringify({ type: "pty_output", cliId: key, data });
34560
+ if (this.clients.size === 0 || !this.isTerminalCliSession(key)) return;
34561
+ const msg = JSON.stringify({ type: "pty_output", sessionId: key, data });
34349
34562
  for (const client of this.clients) {
34350
34563
  if (client.readyState === 1) {
34351
34564
  client.send(msg);
@@ -34559,6 +34772,11 @@ var StandaloneServer = class {
34559
34772
  return;
34560
34773
  }
34561
34774
  if (action === "snapshot" && method === "GET") {
34775
+ if (!this.isTerminalCliSession(sessionId)) {
34776
+ res.writeHead(409, { "Content-Type": "application/json" });
34777
+ res.end(JSON.stringify({ error: "CLI session is not in terminal mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" }));
34778
+ return;
34779
+ }
34562
34780
  void (async () => {
34563
34781
  const client = await this.createSessionHostClient();
34564
34782
  try {
@@ -34680,6 +34898,11 @@ var StandaloneServer = class {
34680
34898
  req.on("aborted", cleanup);
34681
34899
  }
34682
34900
  async handleRuntimeEvents(req, res, sessionId) {
34901
+ if (!this.isTerminalCliSession(sessionId)) {
34902
+ res.writeHead(409, { "Content-Type": "application/json" });
34903
+ res.end(JSON.stringify({ error: "CLI session is not in terminal mode", code: "CLI_VIEW_MODE_NOT_TERMINAL" }));
34904
+ return;
34905
+ }
34683
34906
  const client = await this.createSessionHostClient();
34684
34907
  res.writeHead(200, {
34685
34908
  "Content-Type": "text/event-stream",
@@ -34699,6 +34922,7 @@ var StandaloneServer = class {
34699
34922
  }
34700
34923
  const writeEvent = (event) => {
34701
34924
  if (event.sessionId !== sessionId) return;
34925
+ if (!this.isTerminalCliSession(sessionId)) return;
34702
34926
  res.write(`event: ${event.type}
34703
34927
  `);
34704
34928
  res.write(`data: ${JSON.stringify(event)}
@@ -34786,7 +35010,7 @@ var StandaloneServer = class {
34786
35010
  const states = this.components.instanceManager.collectAllStates();
34787
35011
  for (const state of states) {
34788
35012
  const sessionId = typeof state?.instanceId === "string" ? state.instanceId : "";
34789
- if (!sessionId || state?.category !== "cli") continue;
35013
+ if (!sessionId || state?.category !== "cli" || state?.mode !== "terminal") continue;
34790
35014
  const snapshot = await client.request({
34791
35015
  type: "get_snapshot",
34792
35016
  payload: { sessionId }