@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.mjs CHANGED
@@ -170,7 +170,8 @@ var init_config = __esm({
170
170
  workspaces: [],
171
171
  defaultWorkspaceId: null,
172
172
  recentActivity: [],
173
- recentSessionReads: {},
173
+ sessionReads: {},
174
+ sessionReadMarkers: {},
174
175
  machineNickname: null,
175
176
  machineId: void 0,
176
177
  machineSecret: null,
@@ -2044,18 +2045,27 @@ function appendRecentActivity(config, entry) {
2044
2045
  function getRecentActivity(config, limit = 20) {
2045
2046
  return [...config.recentActivity || []].sort((a, b) => b.lastUsedAt - a.lastUsedAt).slice(0, limit);
2046
2047
  }
2047
- function getRecentSessionSeenAt(config, recentKey) {
2048
- return config.recentSessionReads?.[recentKey] || 0;
2048
+ function getSessionSeenAt(config, sessionId) {
2049
+ return config.sessionReads?.[sessionId] || 0;
2049
2050
  }
2050
- function markRecentSessionSeen(config, recentKey, seenAt = Date.now()) {
2051
- const prev = config.recentSessionReads || {};
2052
- const nextSeenAt = Math.max(prev[recentKey] || 0, seenAt);
2051
+ function getSessionSeenMarker(config, sessionId) {
2052
+ return config.sessionReadMarkers?.[sessionId] || "";
2053
+ }
2054
+ function markSessionSeen(config, sessionId, seenAt = Date.now(), completionMarker) {
2055
+ const prev = config.sessionReads || {};
2056
+ const nextSeenAt = Math.max(prev[sessionId] || 0, seenAt);
2057
+ const prevMarkers = config.sessionReadMarkers || {};
2058
+ const nextMarker = typeof completionMarker === "string" ? completionMarker : "";
2053
2059
  return {
2054
2060
  ...config,
2055
- recentSessionReads: {
2061
+ sessionReads: {
2056
2062
  ...prev,
2057
- [recentKey]: nextSeenAt
2058
- }
2063
+ [sessionId]: nextSeenAt
2064
+ },
2065
+ sessionReadMarkers: nextMarker ? {
2066
+ ...prevMarkers,
2067
+ [sessionId]: nextMarker
2068
+ } : prevMarkers
2059
2069
  };
2060
2070
  }
2061
2071
 
@@ -4979,6 +4989,8 @@ function buildCliSession(state) {
4979
4989
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
4980
4990
  runtimeWriteOwner: state.runtime?.writeOwner || null,
4981
4991
  runtimeAttachedClients: state.runtime?.attachedClients || [],
4992
+ launchMode: state.launchMode,
4993
+ mode: state.mode,
4982
4994
  resume: state.resume,
4983
4995
  activeChat,
4984
4996
  capabilities: PTY_SESSION_CAPABILITIES,
@@ -8385,6 +8397,149 @@ cleanOldFiles();
8385
8397
 
8386
8398
  // src/commands/router.ts
8387
8399
  init_logger();
8400
+
8401
+ // src/status/snapshot.ts
8402
+ init_config();
8403
+ import * as os10 from "os";
8404
+ init_terminal_screen();
8405
+ init_logger();
8406
+ var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
8407
+ function buildDetectedIdeInfos(detectedIdes, cdpManagers) {
8408
+ return detectedIdes.filter((ide) => ide.installed !== false).map((ide) => ({
8409
+ id: ide.id,
8410
+ type: ide.id,
8411
+ name: ide.displayName || ide.name || ide.id,
8412
+ running: isCdpConnected(cdpManagers, ide.id),
8413
+ ...ide.path ? { path: ide.path } : {}
8414
+ }));
8415
+ }
8416
+ function buildAvailableProviders(providerLoader) {
8417
+ return providerLoader.getAll().map((provider) => ({
8418
+ type: provider.type,
8419
+ name: provider.displayName || provider.type,
8420
+ displayName: provider.displayName || provider.type,
8421
+ icon: provider.icon || "\u{1F4BB}",
8422
+ category: provider.category
8423
+ }));
8424
+ }
8425
+ function parseMessageTime(value) {
8426
+ if (typeof value === "number" && Number.isFinite(value)) return value;
8427
+ if (typeof value === "string") {
8428
+ const parsed = Date.parse(value);
8429
+ if (Number.isFinite(parsed)) return parsed;
8430
+ }
8431
+ return 0;
8432
+ }
8433
+ function getSessionMessageUpdatedAt(session) {
8434
+ const lastMessage = session.activeChat?.messages?.at?.(-1);
8435
+ if (!lastMessage) return 0;
8436
+ return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
8437
+ }
8438
+ function getSessionCompletionMarker(session) {
8439
+ const lastMessage = session.activeChat?.messages?.at?.(-1);
8440
+ if (!lastMessage) return "";
8441
+ const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
8442
+ if (role === "user" || role === "human") return "";
8443
+ if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
8444
+ if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
8445
+ if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
8446
+ const timestamp = parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt);
8447
+ return timestamp > 0 ? `ts:${timestamp}` : "";
8448
+ }
8449
+ function getSessionLastUsedAt(session) {
8450
+ return getSessionMessageUpdatedAt(session) || session.lastUpdated || Date.now();
8451
+ }
8452
+ function getLastMessageRole(session) {
8453
+ const role = session.activeChat?.messages?.at?.(-1)?.role;
8454
+ return typeof role === "string" ? role : "";
8455
+ }
8456
+ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole, completionMarker, seenCompletionMarker) {
8457
+ if (status === "waiting_approval") {
8458
+ return { unread: false, inboxBucket: "needs_attention" };
8459
+ }
8460
+ if (status === "generating" || status === "starting") {
8461
+ return { unread: false, inboxBucket: "working" };
8462
+ }
8463
+ const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
8464
+ return { unread, inboxBucket: unread ? "task_complete" : "idle" };
8465
+ }
8466
+ function buildRecentLaunches(recentActivity) {
8467
+ return recentActivity.map((item) => ({
8468
+ id: item.id,
8469
+ providerType: item.providerType,
8470
+ providerName: item.providerName,
8471
+ kind: item.kind,
8472
+ title: item.title || item.providerName,
8473
+ workspace: item.workspace,
8474
+ currentModel: item.currentModel,
8475
+ lastLaunchedAt: item.lastUsedAt
8476
+ })).sort((a, b) => b.lastLaunchedAt - a.lastLaunchedAt).slice(0, 12);
8477
+ }
8478
+ function buildStatusSnapshot(options) {
8479
+ const cfg = loadConfig();
8480
+ const wsState = getWorkspaceState(cfg);
8481
+ const memSnap = getHostMemorySnapshot();
8482
+ const recentActivity = getRecentActivity(cfg, 20);
8483
+ const sessions = buildSessionEntries(
8484
+ options.allStates,
8485
+ options.cdpManagers
8486
+ );
8487
+ for (const session of sessions) {
8488
+ const lastSeenAt = getSessionSeenAt(cfg, session.id);
8489
+ const seenCompletionMarker = getSessionSeenMarker(cfg, session.id);
8490
+ const lastUsedAt = getSessionLastUsedAt(session);
8491
+ const completionMarker = getSessionCompletionMarker(session);
8492
+ const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
8493
+ getSessionMessageUpdatedAt(session) > 0,
8494
+ session.status,
8495
+ lastUsedAt,
8496
+ lastSeenAt,
8497
+ getLastMessageRole(session),
8498
+ completionMarker,
8499
+ seenCompletionMarker
8500
+ );
8501
+ session.lastSeenAt = lastSeenAt;
8502
+ session.unread = unread;
8503
+ session.inboxBucket = inboxBucket;
8504
+ if (READ_DEBUG_ENABLED && (session.unread || session.inboxBucket !== "idle" || session.providerType.includes("codex"))) {
8505
+ LOG.info(
8506
+ "RecentRead",
8507
+ `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)}`
8508
+ );
8509
+ }
8510
+ }
8511
+ const terminalBackend = getTerminalBackendRuntimeStatus();
8512
+ return {
8513
+ instanceId: options.instanceId,
8514
+ version: options.version,
8515
+ daemonMode: options.daemonMode,
8516
+ machine: {
8517
+ hostname: os10.hostname(),
8518
+ platform: os10.platform(),
8519
+ arch: os10.arch(),
8520
+ cpus: os10.cpus().length,
8521
+ totalMem: memSnap.totalMem,
8522
+ freeMem: memSnap.freeMem,
8523
+ availableMem: memSnap.availableMem,
8524
+ loadavg: os10.loadavg(),
8525
+ uptime: os10.uptime(),
8526
+ release: os10.release()
8527
+ },
8528
+ machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
8529
+ timestamp: options.timestamp ?? Date.now(),
8530
+ detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
8531
+ ...options.p2p ? { p2p: options.p2p } : {},
8532
+ sessions,
8533
+ workspaces: wsState.workspaces,
8534
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
8535
+ defaultWorkspacePath: wsState.defaultWorkspacePath,
8536
+ recentLaunches: buildRecentLaunches(recentActivity),
8537
+ terminalBackend,
8538
+ availableProviders: buildAvailableProviders(options.providerLoader)
8539
+ };
8540
+ }
8541
+
8542
+ // src/commands/router.ts
8388
8543
  import * as fs7 from "fs";
8389
8544
  var CHAT_COMMANDS = [
8390
8545
  "send_chat",
@@ -8393,6 +8548,7 @@ var CHAT_COMMANDS = [
8393
8548
  "set_mode",
8394
8549
  "change_model"
8395
8550
  ];
8551
+ var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
8396
8552
  var DaemonCommandRouter = class {
8397
8553
  deps;
8398
8554
  constructor(deps) {
@@ -8563,28 +8719,35 @@ var DaemonCommandRouter = class {
8563
8719
  updateConfig({ userName: name });
8564
8720
  return { success: true, userName: name };
8565
8721
  }
8566
- case "mark_recent_seen": {
8567
- const kind = args?.kind;
8568
- const providerType = args?.providerType;
8569
- if (!kind || !providerType) {
8570
- return { success: false, error: "kind and providerType are required" };
8722
+ case "mark_session_seen": {
8723
+ const sessionId = args?.sessionId;
8724
+ if (!sessionId || typeof sessionId !== "string") {
8725
+ return { success: false, error: "sessionId is required" };
8571
8726
  }
8572
- const recentKey = args?.recentKey || buildRecentActivityKey({
8573
- kind,
8574
- providerType,
8575
- workspace: args?.workspace || null
8576
- });
8577
- const next = markRecentSessionSeen(
8578
- loadConfig(),
8579
- recentKey,
8580
- typeof args?.seenAt === "number" ? args.seenAt : Date.now()
8727
+ const currentConfig = loadConfig();
8728
+ const prevSeenAt = currentConfig.sessionReads?.[sessionId] || 0;
8729
+ const sessionEntries = buildSessionEntries(
8730
+ this.deps.instanceManager.collectAllStates(),
8731
+ this.deps.cdpManagers
8732
+ );
8733
+ const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
8734
+ const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : "";
8735
+ const next = markSessionSeen(
8736
+ currentConfig,
8737
+ sessionId,
8738
+ typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
8739
+ completionMarker
8581
8740
  );
8741
+ if (READ_DEBUG_ENABLED2) {
8742
+ LOG.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
8743
+ }
8582
8744
  saveConfig(next);
8583
8745
  this.deps.onStatusChange?.();
8584
8746
  return {
8585
8747
  success: true,
8586
- recentKey,
8587
- seenAt: next.recentSessionReads?.[recentKey] || Date.now()
8748
+ sessionId,
8749
+ seenAt: next.sessionReads?.[sessionId] || Date.now(),
8750
+ completionMarker
8588
8751
  };
8589
8752
  }
8590
8753
  // ─── Daemon Self-Upgrade ───
@@ -8701,194 +8864,6 @@ var DaemonCommandRouter = class {
8701
8864
 
8702
8865
  // src/status/reporter.ts
8703
8866
  init_logger();
8704
-
8705
- // src/status/snapshot.ts
8706
- init_config();
8707
- import * as os10 from "os";
8708
- init_terminal_screen();
8709
- function buildDetectedIdeInfos(detectedIdes, cdpManagers) {
8710
- return detectedIdes.filter((ide) => ide.installed !== false).map((ide) => ({
8711
- id: ide.id,
8712
- type: ide.id,
8713
- name: ide.displayName || ide.name || ide.id,
8714
- running: isCdpConnected(cdpManagers, ide.id),
8715
- ...ide.path ? { path: ide.path } : {}
8716
- }));
8717
- }
8718
- function buildAvailableProviders(providerLoader) {
8719
- return providerLoader.getAll().map((provider) => ({
8720
- type: provider.type,
8721
- name: provider.displayName || provider.type,
8722
- displayName: provider.displayName || provider.type,
8723
- icon: provider.icon || "\u{1F4BB}",
8724
- category: provider.category
8725
- }));
8726
- }
8727
- function parseMessageTime(value) {
8728
- if (typeof value === "number" && Number.isFinite(value)) return value;
8729
- if (typeof value === "string") {
8730
- const parsed = Date.parse(value);
8731
- if (Number.isFinite(parsed)) return parsed;
8732
- }
8733
- return 0;
8734
- }
8735
- function getSessionMessageUpdatedAt(session) {
8736
- const lastMessage = session.activeChat?.messages?.at?.(-1);
8737
- if (!lastMessage) return 0;
8738
- return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
8739
- }
8740
- function getSessionLastUsedAt(session) {
8741
- return getSessionMessageUpdatedAt(session) || session.lastUpdated || Date.now();
8742
- }
8743
- function getSessionKind(session) {
8744
- return session.transport === "cdp-page" || session.transport === "cdp-webview" ? "ide" : session.transport === "acp" ? "acp" : "cli";
8745
- }
8746
- function getLastMessageRole(session) {
8747
- const role = session.activeChat?.messages?.at?.(-1)?.role;
8748
- return typeof role === "string" ? role : "";
8749
- }
8750
- function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRole) {
8751
- if (status === "waiting_approval") {
8752
- return { unread: false, inboxBucket: "needs_attention" };
8753
- }
8754
- if (status === "generating" || status === "starting") {
8755
- return { unread: false, inboxBucket: "working" };
8756
- }
8757
- const unread = hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
8758
- return { unread, inboxBucket: unread ? "task_complete" : "idle" };
8759
- }
8760
- function buildRecentSessions(sessions, recentActivity, readState) {
8761
- const visibleKeys = /* @__PURE__ */ new Set();
8762
- const hiddenKeys = /* @__PURE__ */ new Set();
8763
- const live = sessions.filter((session) => !session.surfaceHidden && session.status !== "stopped").map((session) => {
8764
- const kind = getSessionKind(session);
8765
- const recentKey = buildRecentActivityKey({
8766
- kind,
8767
- providerType: session.providerType,
8768
- workspace: session.workspace
8769
- });
8770
- const lastSeenAt = readState[recentKey] || 0;
8771
- const lastUsedAt = getSessionLastUsedAt(session);
8772
- const { unread, inboxBucket } = getUnreadState(
8773
- getSessionMessageUpdatedAt(session) > 0,
8774
- session.status,
8775
- lastUsedAt,
8776
- lastSeenAt,
8777
- getLastMessageRole(session)
8778
- );
8779
- return {
8780
- id: session.id,
8781
- recentKey,
8782
- sessionId: session.id,
8783
- providerType: session.providerType,
8784
- providerName: session.providerName,
8785
- kind,
8786
- title: session.activeChat?.title || session.title || session.providerName,
8787
- workspace: session.workspace,
8788
- currentModel: session.currentModel,
8789
- status: session.status,
8790
- lastUsedAt,
8791
- unread,
8792
- lastSeenAt,
8793
- inboxBucket,
8794
- surfaceHidden: false
8795
- };
8796
- });
8797
- for (const item of live) {
8798
- visibleKeys.add(`${item.kind}:${item.providerType}:${item.workspace || ""}`);
8799
- }
8800
- for (const session of sessions) {
8801
- if (!session.surfaceHidden) continue;
8802
- hiddenKeys.add(`${getSessionKind(session)}:${session.providerType}:${session.workspace || ""}`);
8803
- }
8804
- const persisted = recentActivity.filter((item) => {
8805
- const key = `${item.kind}:${item.providerType}:${item.workspace || ""}`;
8806
- return !visibleKeys.has(key) && !hiddenKeys.has(key);
8807
- }).map((item) => {
8808
- const lastSeenAt = readState[item.id] || 0;
8809
- const unread = item.lastUsedAt > lastSeenAt;
8810
- return {
8811
- id: item.id,
8812
- recentKey: item.id,
8813
- sessionId: item.sessionId || null,
8814
- providerType: item.providerType,
8815
- providerName: item.providerName,
8816
- kind: item.kind,
8817
- title: item.title || item.providerName,
8818
- workspace: item.workspace,
8819
- currentModel: item.currentModel,
8820
- lastUsedAt: item.lastUsedAt,
8821
- unread,
8822
- lastSeenAt,
8823
- inboxBucket: unread ? "task_complete" : "idle",
8824
- surfaceHidden: false
8825
- };
8826
- });
8827
- return [...live, ...persisted].sort((a, b) => b.lastUsedAt - a.lastUsedAt).slice(0, 12);
8828
- }
8829
- function buildStatusSnapshot(options) {
8830
- const cfg = loadConfig();
8831
- const wsState = getWorkspaceState(cfg);
8832
- const memSnap = getHostMemorySnapshot();
8833
- const recentActivity = getRecentActivity(cfg, 20);
8834
- const sessions = buildSessionEntries(
8835
- options.allStates,
8836
- options.cdpManagers
8837
- );
8838
- const readState = cfg.recentSessionReads || {};
8839
- for (const session of sessions) {
8840
- const kind = getSessionKind(session);
8841
- const recentKey = buildRecentActivityKey({
8842
- kind,
8843
- providerType: session.providerType,
8844
- workspace: session.workspace
8845
- });
8846
- const lastSeenAt = getRecentSessionSeenAt(cfg, recentKey);
8847
- const lastUsedAt = getSessionLastUsedAt(session);
8848
- const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
8849
- getSessionMessageUpdatedAt(session) > 0,
8850
- session.status,
8851
- lastUsedAt,
8852
- lastSeenAt,
8853
- getLastMessageRole(session)
8854
- );
8855
- session.recentKey = recentKey;
8856
- session.lastSeenAt = lastSeenAt;
8857
- session.unread = unread;
8858
- session.inboxBucket = inboxBucket;
8859
- }
8860
- const terminalBackend = getTerminalBackendRuntimeStatus();
8861
- return {
8862
- instanceId: options.instanceId,
8863
- version: options.version,
8864
- daemonMode: options.daemonMode,
8865
- machine: {
8866
- hostname: os10.hostname(),
8867
- platform: os10.platform(),
8868
- arch: os10.arch(),
8869
- cpus: os10.cpus().length,
8870
- totalMem: memSnap.totalMem,
8871
- freeMem: memSnap.freeMem,
8872
- availableMem: memSnap.availableMem,
8873
- loadavg: os10.loadavg(),
8874
- uptime: os10.uptime(),
8875
- release: os10.release()
8876
- },
8877
- machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
8878
- timestamp: options.timestamp ?? Date.now(),
8879
- detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
8880
- ...options.p2p ? { p2p: options.p2p } : {},
8881
- sessions,
8882
- workspaces: wsState.workspaces,
8883
- defaultWorkspaceId: wsState.defaultWorkspaceId,
8884
- defaultWorkspacePath: wsState.defaultWorkspacePath,
8885
- recentSessions: buildRecentSessions(sessions, recentActivity, readState),
8886
- terminalBackend,
8887
- availableProviders: buildAvailableProviders(options.providerLoader)
8888
- };
8889
- }
8890
-
8891
- // src/status/reporter.ts
8892
8867
  var DaemonStatusReporter = class {
8893
8868
  deps;
8894
8869
  log;
@@ -9036,7 +9011,7 @@ var DaemonStatusReporter = class {
9036
9011
  currentModel: session.currentModel,
9037
9012
  currentPlan: session.currentPlan,
9038
9013
  currentAutoApprove: session.currentAutoApprove,
9039
- recentKey: session.recentKey,
9014
+ lastUpdated: session.lastUpdated,
9040
9015
  unread: session.unread,
9041
9016
  lastSeenAt: session.lastSeenAt,
9042
9017
  inboxBucket: session.inboxBucket,
@@ -9093,12 +9068,14 @@ init_provider_cli_adapter();
9093
9068
  import * as crypto3 from "crypto";
9094
9069
  init_logger();
9095
9070
  var CliProviderInstance = class {
9096
- constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory) {
9071
+ constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, launchModeId) {
9097
9072
  this.provider = provider;
9098
9073
  this.workingDir = workingDir;
9099
9074
  this.cliArgs = cliArgs;
9100
9075
  this.type = provider.type;
9101
9076
  this.instanceId = instanceId || crypto3.randomUUID();
9077
+ this.launchMode = launchModeId && provider.launchModes?.find((m) => m.id === launchModeId) || null;
9078
+ this.resolvedOutputFormat = this.resolveOutputFormat();
9102
9079
  this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
9103
9080
  this.monitor = new StatusMonitor();
9104
9081
  this.historyWriter = new ChatHistoryWriter();
@@ -9117,6 +9094,26 @@ var CliProviderInstance = class {
9117
9094
  lastApprovalEventAt = 0;
9118
9095
  historyWriter;
9119
9096
  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
+ }
9120
9117
  // ─── Lifecycle ─────────────────────────────────
9121
9118
  async init(context) {
9122
9119
  this.context = context;
@@ -9156,7 +9153,8 @@ var CliProviderInstance = class {
9156
9153
  name: this.provider.name,
9157
9154
  category: "cli",
9158
9155
  status: adapterStatus.status,
9159
- mode: "terminal",
9156
+ mode: this.resolvedOutputFormat === "stream-json" ? "chat" : "terminal",
9157
+ launchMode: this.launchMode?.id,
9160
9158
  activeChat: {
9161
9159
  id: `${this.type}_${this.workingDir}`,
9162
9160
  title: `${this.provider.name} \xB7 ${dirName}`,
@@ -10303,12 +10301,12 @@ var DaemonCliManager = class {
10303
10301
  }
10304
10302
  }, 3e3);
10305
10303
  }
10306
- async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false) {
10304
+ async registerCliInstance(key, normalizedType, cliType, resolvedDir, cliArgs, provider, settings, attachExisting = false, launchModeId) {
10307
10305
  const instanceManager = this.deps.getInstanceManager();
10308
10306
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
10309
10307
  if (!instanceManager) throw new Error("InstanceManager not available");
10310
10308
  const transportFactory = this.getTransportFactory(key, normalizedType, resolvedDir, cliArgs, attachExisting);
10311
- const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory);
10309
+ const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, launchModeId);
10312
10310
  try {
10313
10311
  await instanceManager.addInstance(key, cliInstance, {
10314
10312
  serverConn: this.deps.getServerConn(),
@@ -10334,7 +10332,7 @@ var DaemonCliManager = class {
10334
10332
  this.startCliExitMonitor(key, cliType);
10335
10333
  }
10336
10334
  // ─── Session start/management ──────────────────────────────
10337
- async startSession(cliType, workingDir, cliArgs, initialModel) {
10335
+ async startSession(cliType, workingDir, cliArgs, initialModel, launchMode, launchOptionValues) {
10338
10336
  const trimmed = (workingDir || "").trim();
10339
10337
  if (!trimmed) throw new Error("working directory required");
10340
10338
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path10.resolve(trimmed);
@@ -10426,6 +10424,29 @@ ${installInfo}`
10426
10424
  if (provider) {
10427
10425
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
10428
10426
  }
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
+ }
10429
10450
  const instanceManager = this.deps.getInstanceManager();
10430
10451
  if (provider && instanceManager) {
10431
10452
  const resolvedProvider = this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider;
@@ -10434,14 +10455,15 @@ ${installInfo}`
10434
10455
  normalizedType,
10435
10456
  cliType,
10436
10457
  resolvedDir,
10437
- cliArgs,
10458
+ resolvedCliArgs,
10438
10459
  resolvedProvider,
10439
10460
  {},
10440
- false
10461
+ false,
10462
+ resolvedLaunchMode
10441
10463
  );
10442
10464
  console.log(colorize("green", ` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
10443
10465
  } else {
10444
- const adapter = this.createAdapter(cliType, resolvedDir, cliArgs, key, false);
10466
+ const adapter = this.createAdapter(cliType, resolvedDir, resolvedCliArgs, key, false);
10445
10467
  try {
10446
10468
  await adapter.spawn();
10447
10469
  } catch (spawnErr) {
@@ -10549,7 +10571,8 @@ ${installInfo}`
10549
10571
  record.cliArgs,
10550
10572
  resolvedProvider,
10551
10573
  {},
10552
- true
10574
+ true,
10575
+ record.launchMode
10553
10576
  );
10554
10577
  restored += 1;
10555
10578
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record.runtimeKey || record.runtimeId} (${record.displayName || record.workspace})`);
@@ -10619,7 +10642,7 @@ ${installInfo}`
10619
10642
  const dir = resolved.path;
10620
10643
  const launchSource = resolved.source;
10621
10644
  if (!cliType) throw new Error("cliType required");
10622
- await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel);
10645
+ await this.startSession(cliType, dir, args?.cliArgs, args?.initialModel, args?.launchMode, args?.launchOptionValues);
10623
10646
  let newKey = null;
10624
10647
  for (const [k, adapter] of this.adapters) {
10625
10648
  if (adapter.cliType === cliType && adapter.workingDir === dir) {