@adhdev/daemon-core 0.7.39 → 0.7.41

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
@@ -175,7 +175,8 @@ var init_config = __esm({
175
175
  workspaces: [],
176
176
  defaultWorkspaceId: null,
177
177
  recentActivity: [],
178
- recentSessionReads: {},
178
+ sessionReads: {},
179
+ sessionReadMarkers: {},
179
180
  machineNickname: null,
180
181
  machineId: void 0,
181
182
  machineSecret: null,
@@ -2123,18 +2124,27 @@ function appendRecentActivity(config, entry) {
2123
2124
  function getRecentActivity(config, limit = 20) {
2124
2125
  return [...config.recentActivity || []].sort((a, b) => b.lastUsedAt - a.lastUsedAt).slice(0, limit);
2125
2126
  }
2126
- function getRecentSessionSeenAt(config, recentKey) {
2127
- return config.recentSessionReads?.[recentKey] || 0;
2127
+ function getSessionSeenAt(config, sessionId) {
2128
+ return config.sessionReads?.[sessionId] || 0;
2128
2129
  }
2129
- function markRecentSessionSeen(config, recentKey, seenAt = Date.now()) {
2130
- const prev = config.recentSessionReads || {};
2131
- const nextSeenAt = Math.max(prev[recentKey] || 0, seenAt);
2130
+ function getSessionSeenMarker(config, sessionId) {
2131
+ return config.sessionReadMarkers?.[sessionId] || "";
2132
+ }
2133
+ function markSessionSeen(config, sessionId, seenAt = Date.now(), completionMarker) {
2134
+ const prev = config.sessionReads || {};
2135
+ const nextSeenAt = Math.max(prev[sessionId] || 0, seenAt);
2136
+ const prevMarkers = config.sessionReadMarkers || {};
2137
+ const nextMarker = typeof completionMarker === "string" ? completionMarker : "";
2132
2138
  return {
2133
2139
  ...config,
2134
- recentSessionReads: {
2140
+ sessionReads: {
2135
2141
  ...prev,
2136
- [recentKey]: nextSeenAt
2137
- }
2142
+ [sessionId]: nextSeenAt
2143
+ },
2144
+ sessionReadMarkers: nextMarker ? {
2145
+ ...prevMarkers,
2146
+ [sessionId]: nextMarker
2147
+ } : prevMarkers
2138
2148
  };
2139
2149
  }
2140
2150
 
@@ -5058,6 +5068,8 @@ function buildCliSession(state) {
5058
5068
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
5059
5069
  runtimeWriteOwner: state.runtime?.writeOwner || null,
5060
5070
  runtimeAttachedClients: state.runtime?.attachedClients || [],
5071
+ launchMode: state.launchMode,
5072
+ mode: state.mode,
5061
5073
  resume: state.resume,
5062
5074
  activeChat,
5063
5075
  capabilities: PTY_SESSION_CAPABILITIES,
@@ -8464,6 +8476,149 @@ cleanOldFiles();
8464
8476
 
8465
8477
  // src/commands/router.ts
8466
8478
  init_logger();
8479
+
8480
+ // src/status/snapshot.ts
8481
+ var os10 = __toESM(require("os"));
8482
+ init_config();
8483
+ init_terminal_screen();
8484
+ init_logger();
8485
+ var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
8486
+ function buildDetectedIdeInfos(detectedIdes, cdpManagers) {
8487
+ return detectedIdes.filter((ide) => ide.installed !== false).map((ide) => ({
8488
+ id: ide.id,
8489
+ type: ide.id,
8490
+ name: ide.displayName || ide.name || ide.id,
8491
+ running: isCdpConnected(cdpManagers, ide.id),
8492
+ ...ide.path ? { path: ide.path } : {}
8493
+ }));
8494
+ }
8495
+ function buildAvailableProviders(providerLoader) {
8496
+ return providerLoader.getAll().map((provider) => ({
8497
+ type: provider.type,
8498
+ name: provider.displayName || provider.type,
8499
+ displayName: provider.displayName || provider.type,
8500
+ icon: provider.icon || "\u{1F4BB}",
8501
+ category: provider.category
8502
+ }));
8503
+ }
8504
+ function parseMessageTime(value) {
8505
+ if (typeof value === "number" && Number.isFinite(value)) return value;
8506
+ if (typeof value === "string") {
8507
+ const parsed = Date.parse(value);
8508
+ if (Number.isFinite(parsed)) return parsed;
8509
+ }
8510
+ return 0;
8511
+ }
8512
+ function getSessionMessageUpdatedAt(session) {
8513
+ const lastMessage = session.activeChat?.messages?.at?.(-1);
8514
+ if (!lastMessage) return 0;
8515
+ return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
8516
+ }
8517
+ function getSessionCompletionMarker(session) {
8518
+ const lastMessage = session.activeChat?.messages?.at?.(-1);
8519
+ if (!lastMessage) return "";
8520
+ const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
8521
+ if (role === "user" || role === "human") return "";
8522
+ if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
8523
+ if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
8524
+ if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
8525
+ const timestamp = parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt);
8526
+ return timestamp > 0 ? `ts:${timestamp}` : "";
8527
+ }
8528
+ function getSessionLastUsedAt(session) {
8529
+ return getSessionMessageUpdatedAt(session) || session.lastUpdated || Date.now();
8530
+ }
8531
+ function getLastMessageRole(session) {
8532
+ const role = session.activeChat?.messages?.at?.(-1)?.role;
8533
+ return typeof role === "string" ? role : "";
8534
+ }
8535
+ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole, completionMarker, seenCompletionMarker) {
8536
+ if (status === "waiting_approval") {
8537
+ return { unread: false, inboxBucket: "needs_attention" };
8538
+ }
8539
+ if (status === "generating" || status === "starting") {
8540
+ return { unread: false, inboxBucket: "working" };
8541
+ }
8542
+ const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
8543
+ return { unread, inboxBucket: unread ? "task_complete" : "idle" };
8544
+ }
8545
+ function buildRecentLaunches(recentActivity) {
8546
+ return recentActivity.map((item) => ({
8547
+ id: item.id,
8548
+ providerType: item.providerType,
8549
+ providerName: item.providerName,
8550
+ kind: item.kind,
8551
+ title: item.title || item.providerName,
8552
+ workspace: item.workspace,
8553
+ currentModel: item.currentModel,
8554
+ lastLaunchedAt: item.lastUsedAt
8555
+ })).sort((a, b) => b.lastLaunchedAt - a.lastLaunchedAt).slice(0, 12);
8556
+ }
8557
+ function buildStatusSnapshot(options) {
8558
+ const cfg = loadConfig();
8559
+ const wsState = getWorkspaceState(cfg);
8560
+ const memSnap = getHostMemorySnapshot();
8561
+ const recentActivity = getRecentActivity(cfg, 20);
8562
+ const sessions = buildSessionEntries(
8563
+ options.allStates,
8564
+ options.cdpManagers
8565
+ );
8566
+ for (const session of sessions) {
8567
+ const lastSeenAt = getSessionSeenAt(cfg, session.id);
8568
+ const seenCompletionMarker = getSessionSeenMarker(cfg, session.id);
8569
+ const lastUsedAt = getSessionLastUsedAt(session);
8570
+ const completionMarker = getSessionCompletionMarker(session);
8571
+ const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
8572
+ getSessionMessageUpdatedAt(session) > 0,
8573
+ session.status,
8574
+ lastUsedAt,
8575
+ lastSeenAt,
8576
+ getLastMessageRole(session),
8577
+ completionMarker,
8578
+ seenCompletionMarker
8579
+ );
8580
+ session.lastSeenAt = lastSeenAt;
8581
+ session.unread = unread;
8582
+ session.inboxBucket = inboxBucket;
8583
+ if (READ_DEBUG_ENABLED && (session.unread || session.inboxBucket !== "idle" || session.providerType.includes("codex"))) {
8584
+ LOG.info(
8585
+ "RecentRead",
8586
+ `snapshot session id=${session.id} provider=${session.providerType} status=${String(session.status || "")} bucket=${inboxBucket} unread=${String(unread)} lastSeenAt=${lastSeenAt} completionMarker=${completionMarker || "-"} seenMarker=${seenCompletionMarker || "-"} lastUpdated=${String(session.lastUpdated || 0)} lastUsedAt=${lastUsedAt} lastRole=${getLastMessageRole(session)} msgUpdatedAt=${getSessionMessageUpdatedAt(session)}`
8587
+ );
8588
+ }
8589
+ }
8590
+ const terminalBackend = getTerminalBackendRuntimeStatus();
8591
+ return {
8592
+ instanceId: options.instanceId,
8593
+ version: options.version,
8594
+ daemonMode: options.daemonMode,
8595
+ machine: {
8596
+ hostname: os10.hostname(),
8597
+ platform: os10.platform(),
8598
+ arch: os10.arch(),
8599
+ cpus: os10.cpus().length,
8600
+ totalMem: memSnap.totalMem,
8601
+ freeMem: memSnap.freeMem,
8602
+ availableMem: memSnap.availableMem,
8603
+ loadavg: os10.loadavg(),
8604
+ uptime: os10.uptime(),
8605
+ release: os10.release()
8606
+ },
8607
+ machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
8608
+ timestamp: options.timestamp ?? Date.now(),
8609
+ detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
8610
+ ...options.p2p ? { p2p: options.p2p } : {},
8611
+ sessions,
8612
+ workspaces: wsState.workspaces,
8613
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
8614
+ defaultWorkspacePath: wsState.defaultWorkspacePath,
8615
+ recentLaunches: buildRecentLaunches(recentActivity),
8616
+ terminalBackend,
8617
+ availableProviders: buildAvailableProviders(options.providerLoader)
8618
+ };
8619
+ }
8620
+
8621
+ // src/commands/router.ts
8467
8622
  var fs7 = __toESM(require("fs"));
8468
8623
  var CHAT_COMMANDS = [
8469
8624
  "send_chat",
@@ -8472,6 +8627,7 @@ var CHAT_COMMANDS = [
8472
8627
  "set_mode",
8473
8628
  "change_model"
8474
8629
  ];
8630
+ var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
8475
8631
  var DaemonCommandRouter = class {
8476
8632
  deps;
8477
8633
  constructor(deps) {
@@ -8642,28 +8798,35 @@ var DaemonCommandRouter = class {
8642
8798
  updateConfig({ userName: name });
8643
8799
  return { success: true, userName: name };
8644
8800
  }
8645
- case "mark_recent_seen": {
8646
- const kind = args?.kind;
8647
- const providerType = args?.providerType;
8648
- if (!kind || !providerType) {
8649
- return { success: false, error: "kind and providerType are required" };
8801
+ case "mark_session_seen": {
8802
+ const sessionId = args?.sessionId;
8803
+ if (!sessionId || typeof sessionId !== "string") {
8804
+ return { success: false, error: "sessionId is required" };
8650
8805
  }
8651
- const recentKey = args?.recentKey || buildRecentActivityKey({
8652
- kind,
8653
- providerType,
8654
- workspace: args?.workspace || null
8655
- });
8656
- const next = markRecentSessionSeen(
8657
- loadConfig(),
8658
- recentKey,
8659
- typeof args?.seenAt === "number" ? args.seenAt : Date.now()
8806
+ const currentConfig = loadConfig();
8807
+ const prevSeenAt = currentConfig.sessionReads?.[sessionId] || 0;
8808
+ const sessionEntries = buildSessionEntries(
8809
+ this.deps.instanceManager.collectAllStates(),
8810
+ this.deps.cdpManagers
8811
+ );
8812
+ const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
8813
+ const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : "";
8814
+ const next = markSessionSeen(
8815
+ currentConfig,
8816
+ sessionId,
8817
+ typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
8818
+ completionMarker
8660
8819
  );
8820
+ if (READ_DEBUG_ENABLED2) {
8821
+ LOG.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
8822
+ }
8661
8823
  saveConfig(next);
8662
8824
  this.deps.onStatusChange?.();
8663
8825
  return {
8664
8826
  success: true,
8665
- recentKey,
8666
- seenAt: next.recentSessionReads?.[recentKey] || Date.now()
8827
+ sessionId,
8828
+ seenAt: next.sessionReads?.[sessionId] || Date.now(),
8829
+ completionMarker
8667
8830
  };
8668
8831
  }
8669
8832
  // ─── Daemon Self-Upgrade ───
@@ -8780,194 +8943,6 @@ var DaemonCommandRouter = class {
8780
8943
 
8781
8944
  // src/status/reporter.ts
8782
8945
  init_logger();
8783
-
8784
- // src/status/snapshot.ts
8785
- var os10 = __toESM(require("os"));
8786
- init_config();
8787
- init_terminal_screen();
8788
- function buildDetectedIdeInfos(detectedIdes, cdpManagers) {
8789
- return detectedIdes.filter((ide) => ide.installed !== false).map((ide) => ({
8790
- id: ide.id,
8791
- type: ide.id,
8792
- name: ide.displayName || ide.name || ide.id,
8793
- running: isCdpConnected(cdpManagers, ide.id),
8794
- ...ide.path ? { path: ide.path } : {}
8795
- }));
8796
- }
8797
- function buildAvailableProviders(providerLoader) {
8798
- return providerLoader.getAll().map((provider) => ({
8799
- type: provider.type,
8800
- name: provider.displayName || provider.type,
8801
- displayName: provider.displayName || provider.type,
8802
- icon: provider.icon || "\u{1F4BB}",
8803
- category: provider.category
8804
- }));
8805
- }
8806
- function parseMessageTime(value) {
8807
- if (typeof value === "number" && Number.isFinite(value)) return value;
8808
- if (typeof value === "string") {
8809
- const parsed = Date.parse(value);
8810
- if (Number.isFinite(parsed)) return parsed;
8811
- }
8812
- return 0;
8813
- }
8814
- function getSessionMessageUpdatedAt(session) {
8815
- const lastMessage = session.activeChat?.messages?.at?.(-1);
8816
- if (!lastMessage) return 0;
8817
- return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
8818
- }
8819
- function getSessionLastUsedAt(session) {
8820
- return getSessionMessageUpdatedAt(session) || session.lastUpdated || Date.now();
8821
- }
8822
- function getSessionKind(session) {
8823
- return session.transport === "cdp-page" || session.transport === "cdp-webview" ? "ide" : session.transport === "acp" ? "acp" : "cli";
8824
- }
8825
- function getLastMessageRole(session) {
8826
- const role = session.activeChat?.messages?.at?.(-1)?.role;
8827
- return typeof role === "string" ? role : "";
8828
- }
8829
- function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole) {
8830
- if (status === "waiting_approval") {
8831
- return { unread: false, inboxBucket: "needs_attention" };
8832
- }
8833
- if (status === "generating" || status === "starting") {
8834
- return { unread: false, inboxBucket: "working" };
8835
- }
8836
- const unread = hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
8837
- return { unread, inboxBucket: unread ? "task_complete" : "idle" };
8838
- }
8839
- function buildRecentSessions(sessions, recentActivity, readState) {
8840
- const visibleKeys = /* @__PURE__ */ new Set();
8841
- const hiddenKeys = /* @__PURE__ */ new Set();
8842
- const live = sessions.filter((session) => !session.surfaceHidden && session.status !== "stopped").map((session) => {
8843
- const kind = getSessionKind(session);
8844
- const recentKey = buildRecentActivityKey({
8845
- kind,
8846
- providerType: session.providerType,
8847
- workspace: session.workspace
8848
- });
8849
- const lastSeenAt = readState[recentKey] || 0;
8850
- const lastUsedAt = getSessionLastUsedAt(session);
8851
- const { unread, inboxBucket } = getUnreadState(
8852
- getSessionMessageUpdatedAt(session) > 0,
8853
- session.status,
8854
- lastUsedAt,
8855
- lastSeenAt,
8856
- getLastMessageRole(session)
8857
- );
8858
- return {
8859
- id: session.id,
8860
- recentKey,
8861
- sessionId: session.id,
8862
- providerType: session.providerType,
8863
- providerName: session.providerName,
8864
- kind,
8865
- title: session.activeChat?.title || session.title || session.providerName,
8866
- workspace: session.workspace,
8867
- currentModel: session.currentModel,
8868
- status: session.status,
8869
- lastUsedAt,
8870
- unread,
8871
- lastSeenAt,
8872
- inboxBucket,
8873
- surfaceHidden: false
8874
- };
8875
- });
8876
- for (const item of live) {
8877
- visibleKeys.add(`${item.kind}:${item.providerType}:${item.workspace || ""}`);
8878
- }
8879
- for (const session of sessions) {
8880
- if (!session.surfaceHidden) continue;
8881
- hiddenKeys.add(`${getSessionKind(session)}:${session.providerType}:${session.workspace || ""}`);
8882
- }
8883
- const persisted = recentActivity.filter((item) => {
8884
- const key = `${item.kind}:${item.providerType}:${item.workspace || ""}`;
8885
- return !visibleKeys.has(key) && !hiddenKeys.has(key);
8886
- }).map((item) => {
8887
- const lastSeenAt = readState[item.id] || 0;
8888
- const unread = item.lastUsedAt > lastSeenAt;
8889
- return {
8890
- id: item.id,
8891
- recentKey: item.id,
8892
- sessionId: item.sessionId || null,
8893
- providerType: item.providerType,
8894
- providerName: item.providerName,
8895
- kind: item.kind,
8896
- title: item.title || item.providerName,
8897
- workspace: item.workspace,
8898
- currentModel: item.currentModel,
8899
- lastUsedAt: item.lastUsedAt,
8900
- unread,
8901
- lastSeenAt,
8902
- inboxBucket: unread ? "task_complete" : "idle",
8903
- surfaceHidden: false
8904
- };
8905
- });
8906
- return [...live, ...persisted].sort((a, b) => b.lastUsedAt - a.lastUsedAt).slice(0, 12);
8907
- }
8908
- function buildStatusSnapshot(options) {
8909
- const cfg = loadConfig();
8910
- const wsState = getWorkspaceState(cfg);
8911
- const memSnap = getHostMemorySnapshot();
8912
- const recentActivity = getRecentActivity(cfg, 20);
8913
- const sessions = buildSessionEntries(
8914
- options.allStates,
8915
- options.cdpManagers
8916
- );
8917
- const readState = cfg.recentSessionReads || {};
8918
- for (const session of sessions) {
8919
- const kind = getSessionKind(session);
8920
- const recentKey = buildRecentActivityKey({
8921
- kind,
8922
- providerType: session.providerType,
8923
- workspace: session.workspace
8924
- });
8925
- const lastSeenAt = getRecentSessionSeenAt(cfg, recentKey);
8926
- const lastUsedAt = getSessionLastUsedAt(session);
8927
- const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
8928
- getSessionMessageUpdatedAt(session) > 0,
8929
- session.status,
8930
- lastUsedAt,
8931
- lastSeenAt,
8932
- getLastMessageRole(session)
8933
- );
8934
- session.recentKey = recentKey;
8935
- session.lastSeenAt = lastSeenAt;
8936
- session.unread = unread;
8937
- session.inboxBucket = inboxBucket;
8938
- }
8939
- const terminalBackend = getTerminalBackendRuntimeStatus();
8940
- return {
8941
- instanceId: options.instanceId,
8942
- version: options.version,
8943
- daemonMode: options.daemonMode,
8944
- machine: {
8945
- hostname: os10.hostname(),
8946
- platform: os10.platform(),
8947
- arch: os10.arch(),
8948
- cpus: os10.cpus().length,
8949
- totalMem: memSnap.totalMem,
8950
- freeMem: memSnap.freeMem,
8951
- availableMem: memSnap.availableMem,
8952
- loadavg: os10.loadavg(),
8953
- uptime: os10.uptime(),
8954
- release: os10.release()
8955
- },
8956
- machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
8957
- timestamp: options.timestamp ?? Date.now(),
8958
- detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
8959
- ...options.p2p ? { p2p: options.p2p } : {},
8960
- sessions,
8961
- workspaces: wsState.workspaces,
8962
- defaultWorkspaceId: wsState.defaultWorkspaceId,
8963
- defaultWorkspacePath: wsState.defaultWorkspacePath,
8964
- recentSessions: buildRecentSessions(sessions, recentActivity, readState),
8965
- terminalBackend,
8966
- availableProviders: buildAvailableProviders(options.providerLoader)
8967
- };
8968
- }
8969
-
8970
- // src/status/reporter.ts
8971
8946
  var DaemonStatusReporter = class {
8972
8947
  deps;
8973
8948
  log;
@@ -9115,7 +9090,7 @@ var DaemonStatusReporter = class {
9115
9090
  currentModel: session.currentModel,
9116
9091
  currentPlan: session.currentPlan,
9117
9092
  currentAutoApprove: session.currentAutoApprove,
9118
- recentKey: session.recentKey,
9093
+ lastUpdated: session.lastUpdated,
9119
9094
  unread: session.unread,
9120
9095
  lastSeenAt: session.lastSeenAt,
9121
9096
  inboxBucket: session.inboxBucket,
@@ -9172,12 +9147,14 @@ var crypto3 = __toESM(require("crypto"));
9172
9147
  init_provider_cli_adapter();
9173
9148
  init_logger();
9174
9149
  var CliProviderInstance = class {
9175
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
9150
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
9176
9151
  this.provider = provider;
9177
9152
  this.workingDir = workingDir;
9178
9153
  this.cliArgs = cliArgs;
9179
9154
  this.type = provider.type;
9180
9155
  this.instanceId = instanceId || crypto3.randomUUID();
9156
+ this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
9157
+ this.resolvedOutputFormat = this.resolveOutputFormat();
9181
9158
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
9182
9159
  this.monitor = new StatusMonitor();
9183
9160
  this.historyWriter = new ChatHistoryWriter();
@@ -9196,6 +9173,26 @@ var CliProviderInstance = class {
9196
9173
  lastApprovalEventAt = 0;
9197
9174
  historyWriter;
9198
9175
  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
+ }
9199
9196
  // ─── Lifecycle ─────────────────────────────────
9200
9197
  async init(context) {
9201
9198
  this.context = context;
@@ -9235,7 +9232,8 @@ var CliProviderInstance = class {
9235
9232
  name: this.provider.name,
9236
9233
  category: "cli",
9237
9234
  status: adapterStatus.status,
9238
- mode: "terminal",
9235
+ mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
9236
+ launchMode: this.launchMode?.id,
9239
9237
  activeChat: {
9240
9238
  id: `${this.type}_${this.workingDir}`,
9241
9239
  title: `${this.provider.name} \xB7 ${dirName}`,
@@ -10377,12 +10375,12 @@ var DaemonCliManager = class {
10377
10375
  }
10378
10376
  }, 3e3);
10379
10377
  }
10380
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
10378
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
10381
10379
  const instanceManager = this.deps.getInstanceManager();
10382
10380
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
10383
10381
  if (!instanceManager) throw new Error("InstanceManager not available");
10384
10382
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
10385
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
10383
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
10386
10384
  try {
10387
10385
  await instanceManager.addInstance(key, cliInstance, {
10388
10386
  serverConn: this.deps.getServerConn(),
@@ -10408,7 +10406,7 @@ var DaemonCliManager = class {
10408
10406
  this.startCliExitMonitor(key, cliType);
10409
10407
  }
10410
10408
  // ─── Session start/management ──────────────────────────────
10411
- async startSession(cliType, workingDir, cliArgs, initialModel) {
10409
+ async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
10412
10410
  const trimmed = (workingDir || "").trim();
10413
10411
  if (!trimmed) throw new Error("working directory required");
10414
10412
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -10500,6 +10498,29 @@ ${installInfo}`
10500
10498
  if (provider) {
10501
10499
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
10502
10500
  }
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
+ }
10503
10524
  const instanceManager = this.deps.getInstanceManager();
10504
10525
  if (provider && instanceManager) {
10505
10526
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -10508,14 +10529,15 @@ ${installInfo}`
10508
10529
  normalizedType,
10509
10530
  cliType,
10510
10531
  resolvedDir,
10511
- cliArgs,
10532
+ resolvedCliArgs,
10512
10533
  resolvedProvider,
10513
10534
  {},
10514
- false
10535
+ false,
10536
+ resolvedLaunchMode
10515
10537
  );
10516
10538
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
10517
10539
  } else {
10518
- const adapter = this.createAdapter(cliType, resolvedDir, cliArgs, key, false);
10540
+ const adapter = this.createAdapter(cliType, resolvedDir, resolvedCliArgs, key, false);
10519
10541
  try {
10520
10542
  await adapter.spawn();
10521
10543
  } catch (spawnErr) {
@@ -10623,7 +10645,8 @@ ${installInfo}`
10623
10645
  record.cliArgs,
10624
10646
  resolvedProvider,
10625
10647
  {},
10626
- true
10648
+ true,
10649
+ record.launchMode
10627
10650
  );
10628
10651
  restored += 1;
10629
10652
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record.runtimeKey || record.runtimeId} (${record.displayName || record.workspace})`);
@@ -10693,7 +10716,7 @@ ${installInfo}`
10693
10716
  const dir = resolved.path;
10694
10717
  const launchSource = resolved.source;
10695
10718
  if (!cliType) throw new Error("cliType required");
10696
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
10719
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
10697
10720
  let newKey = null;
10698
10721
  for (const [k, adapter] of this.adapters) {
10699
10722
  if (adapter.cliType === cliType && adapter.workingDir === dir) {