@adhdev/daemon-standalone 0.8.34 → 0.8.36

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
@@ -27843,6 +27843,7 @@ var require_dist2 = __commonJS({
27843
27843
  const parsed = isPlainObject2(raw) ? raw : {};
27844
27844
  return {
27845
27845
  serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
27846
+ allowServerApiProxy: asBoolean(parsed.allowServerApiProxy, DEFAULT_CONFIG.allowServerApiProxy ?? false),
27846
27847
  selectedIde: asNullableString(parsed.selectedIde),
27847
27848
  configuredIdes: asStringArray(parsed.configuredIdes),
27848
27849
  installedExtensions: asStringArray(parsed.installedExtensions),
@@ -27996,6 +27997,7 @@ var require_dist2 = __commonJS({
27996
27997
  import_crypto2 = require("crypto");
27997
27998
  DEFAULT_CONFIG = {
27998
27999
  serverUrl: "https://api.adhf.dev",
28000
+ allowServerApiProxy: false,
27999
28001
  selectedIde: null,
28000
28002
  configuredIdes: [],
28001
28003
  installedExtensions: [],
@@ -30284,8 +30286,6 @@ ${data.message || ""}`.trim();
30284
30286
  if (blockingModal || this.currentStatus === "waiting_approval") {
30285
30287
  throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
30286
30288
  }
30287
- this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
30288
- this.syncMessageViews();
30289
30289
  this.isWaitingForResponse = true;
30290
30290
  this.responseBuffer = "";
30291
30291
  this.finishRetryCount = 0;
@@ -30317,6 +30317,13 @@ ${data.message || ""}`.trim();
30317
30317
  const submitDelayMs = this.sendDelayMs + Math.min(2e3, Math.max(0, estimatedLines - 1) * 350);
30318
30318
  const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5e3, estimatedLines * 500));
30319
30319
  const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
30320
+ let didCommitUserTurn = false;
30321
+ const commitUserTurn = () => {
30322
+ if (didCommitUserTurn) return;
30323
+ didCommitUserTurn = true;
30324
+ this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
30325
+ this.syncMessageViews();
30326
+ };
30320
30327
  if (this.settleTimer) {
30321
30328
  clearTimeout(this.settleTimer);
30322
30329
  this.settleTimer = null;
@@ -30329,109 +30336,128 @@ ${data.message || ""}`.trim();
30329
30336
  if (this.isWaitingForResponse) this.finishResponse();
30330
30337
  }, this.timeouts.maxResponse);
30331
30338
  };
30332
- const submit = () => {
30333
- if (!this.ptyProcess) return;
30334
- this.submitPendingUntil = 0;
30335
- this.recordTrace("submit_write", {
30336
- mode: "submit_key",
30337
- sendKey: this.sendKey,
30338
- screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
30339
- });
30340
- this.ptyProcess.write(this.sendKey);
30341
- const retrySubmitIfStuck = (attempt) => {
30342
- this.submitRetryTimer = null;
30343
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
30344
- if (this.currentStatus === "waiting_approval") return;
30345
- if ((this.responseBuffer || "").trim()) return;
30339
+ await new Promise((resolve12) => {
30340
+ let resolved = false;
30341
+ const resolveOnce = () => {
30342
+ if (resolved) return;
30343
+ resolved = true;
30344
+ resolve12();
30345
+ };
30346
+ const submit = () => {
30347
+ if (!this.ptyProcess) {
30348
+ resolveOnce();
30349
+ return;
30350
+ }
30351
+ commitUserTurn();
30352
+ this.submitPendingUntil = 0;
30346
30353
  const screenText = this.terminalScreen.getText();
30347
- if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
30348
- if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
30349
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
30350
- LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
30351
30354
  this.recordTrace("submit_write", {
30352
- mode: "submit_retry",
30353
- attempt,
30355
+ mode: "submit_key",
30354
30356
  sendKey: this.sendKey,
30355
30357
  screenText: summarizeCliTraceText(screenText, 500)
30356
30358
  });
30357
30359
  this.ptyProcess.write(this.sendKey);
30358
- if (attempt >= 3) {
30359
- this.submitRetryUsed = true;
30360
- return;
30361
- }
30362
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
30360
+ const retrySubmitIfStuck = (attempt) => {
30361
+ this.submitRetryTimer = null;
30362
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
30363
+ if (this.currentStatus === "waiting_approval") return;
30364
+ if ((this.responseBuffer || "").trim()) return;
30365
+ const screenText2 = this.terminalScreen.getText();
30366
+ if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
30367
+ if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText2)) return;
30368
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
30369
+ LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
30370
+ this.recordTrace("submit_write", {
30371
+ mode: "submit_retry",
30372
+ attempt,
30373
+ sendKey: this.sendKey,
30374
+ screenText: summarizeCliTraceText(screenText2, 500)
30375
+ });
30376
+ this.ptyProcess.write(this.sendKey);
30377
+ if (attempt >= 3) {
30378
+ this.submitRetryUsed = true;
30379
+ return;
30380
+ }
30381
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
30382
+ };
30383
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
30384
+ startResponseTimeout();
30385
+ resolveOnce();
30363
30386
  };
30364
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
30365
- startResponseTimeout();
30366
- };
30367
- if (this.submitStrategy === "immediate") {
30368
- this.submitPendingUntil = 0;
30387
+ if (this.submitStrategy === "immediate") {
30388
+ commitUserTurn();
30389
+ this.submitPendingUntil = 0;
30390
+ this.recordTrace("submit_write", {
30391
+ mode: "immediate",
30392
+ text: summarizeCliTraceText(text, 500),
30393
+ sendKey: this.sendKey,
30394
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
30395
+ });
30396
+ this.ptyProcess.write(text + this.sendKey);
30397
+ this.submitRetryTimer = setTimeout(() => {
30398
+ this.submitRetryTimer = null;
30399
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
30400
+ if (this.currentStatus === "waiting_approval") return;
30401
+ if ((this.responseBuffer || "").trim()) return;
30402
+ const screenText = this.terminalScreen.getText();
30403
+ if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
30404
+ LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
30405
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
30406
+ this.recordTrace("submit_write", {
30407
+ mode: "immediate_retry",
30408
+ attempt: 1,
30409
+ sendKey: this.sendKey,
30410
+ screenText: summarizeCliTraceText(screenText, 500)
30411
+ });
30412
+ this.ptyProcess.write(this.sendKey);
30413
+ this.submitRetryUsed = true;
30414
+ }, retryDelayMs);
30415
+ startResponseTimeout();
30416
+ resolveOnce();
30417
+ return;
30418
+ }
30419
+ if (submitDelayMs > 0) {
30420
+ this.submitPendingUntil = Date.now() + submitDelayMs;
30421
+ }
30422
+ this.ptyProcess.write(text);
30369
30423
  this.recordTrace("submit_write", {
30370
- mode: "immediate",
30424
+ mode: "type_then_submit",
30371
30425
  text: summarizeCliTraceText(text, 500),
30372
30426
  sendKey: this.sendKey,
30373
30427
  screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
30374
30428
  });
30375
- this.ptyProcess.write(text + this.sendKey);
30376
- this.submitRetryTimer = setTimeout(() => {
30377
- this.submitRetryTimer = null;
30378
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
30379
- if (this.currentStatus === "waiting_approval") return;
30380
- if ((this.responseBuffer || "").trim()) return;
30429
+ const submitStartedAt = Date.now();
30430
+ let lastNormalizedScreen = "";
30431
+ let lastScreenChangeAt = submitStartedAt;
30432
+ const waitForEchoAndSubmit = () => {
30433
+ if (!this.ptyProcess) {
30434
+ resolveOnce();
30435
+ return;
30436
+ }
30437
+ const now = Date.now();
30438
+ const elapsed = now - submitStartedAt;
30381
30439
  const screenText = this.terminalScreen.getText();
30382
- if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
30383
- LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
30384
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
30385
- this.recordTrace("submit_write", {
30386
- mode: "immediate_retry",
30387
- attempt: 1,
30388
- sendKey: this.sendKey,
30389
- screenText: summarizeCliTraceText(screenText, 500)
30390
- });
30391
- this.ptyProcess.write(this.sendKey);
30392
- this.submitRetryUsed = true;
30393
- }, retryDelayMs);
30394
- startResponseTimeout();
30395
- return;
30396
- }
30397
- if (submitDelayMs > 0) {
30398
- this.submitPendingUntil = Date.now() + submitDelayMs;
30399
- }
30400
- this.ptyProcess.write(text);
30401
- this.recordTrace("submit_write", {
30402
- mode: "type_then_submit",
30403
- text: summarizeCliTraceText(text, 500),
30404
- sendKey: this.sendKey,
30405
- screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
30406
- });
30407
- const submitStartedAt = Date.now();
30408
- let lastNormalizedScreen = "";
30409
- let lastScreenChangeAt = submitStartedAt;
30410
- const waitForEchoAndSubmit = () => {
30411
- if (!this.ptyProcess) return;
30412
- const now = Date.now();
30413
- const elapsed = now - submitStartedAt;
30414
- const screenText = this.terminalScreen.getText();
30415
- const normalizedScreen = normalizePromptText(screenText);
30416
- if (normalizedScreen !== lastNormalizedScreen) {
30417
- lastNormalizedScreen = normalizedScreen;
30418
- lastScreenChangeAt = now;
30419
- }
30420
- const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
30421
- if (echoVisible) {
30422
- const screenSettled = now - lastScreenChangeAt >= 500;
30423
- if (elapsed >= submitDelayMs && screenSettled) {
30440
+ const normalizedScreen = normalizePromptText(screenText);
30441
+ if (normalizedScreen !== lastNormalizedScreen) {
30442
+ lastNormalizedScreen = normalizedScreen;
30443
+ lastScreenChangeAt = now;
30444
+ }
30445
+ const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
30446
+ if (echoVisible) {
30447
+ const screenSettled = now - lastScreenChangeAt >= 500;
30448
+ if (elapsed >= submitDelayMs && screenSettled) {
30449
+ submit();
30450
+ return;
30451
+ }
30452
+ }
30453
+ if (elapsed >= maxEchoWaitMs) {
30424
30454
  submit();
30425
30455
  return;
30426
30456
  }
30427
- }
30428
- if (elapsed >= maxEchoWaitMs) {
30429
- submit();
30430
- return;
30431
- }
30432
- setTimeout(waitForEchoAndSubmit, 50);
30433
- };
30434
- waitForEchoAndSubmit();
30457
+ setTimeout(waitForEchoAndSubmit, 50);
30458
+ };
30459
+ waitForEchoAndSubmit();
30460
+ });
30435
30461
  }
30436
30462
  getPartialResponse() {
30437
30463
  if (!this.isWaitingForResponse) return "";
@@ -30795,6 +30821,7 @@ ${data.message || ""}`.trim();
30795
30821
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory2,
30796
30822
  VersionArchive: () => VersionArchive,
30797
30823
  appendRecentActivity: () => appendRecentActivity,
30824
+ buildMachineInfo: () => buildMachineInfo2,
30798
30825
  buildSessionEntries: () => buildSessionEntries,
30799
30826
  buildStatusSnapshot: () => buildStatusSnapshot2,
30800
30827
  connectCdpManager: () => connectCdpManager,
@@ -34712,11 +34739,24 @@ ${effect.notification.body || ""}`.trim();
34712
34739
  "thinking",
34713
34740
  "active"
34714
34741
  ]);
34715
- var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
34716
- var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
34717
- var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
34718
- var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
34719
- var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
34742
+ var FULL_STATUS_ACTIVE_CHAT_OPTIONS = {
34743
+ includeMessages: true,
34744
+ includeInputContent: true,
34745
+ includeActiveModal: true,
34746
+ messageLimit: 60,
34747
+ totalBytesLimit: 96 * 1024,
34748
+ stringLimit: 4 * 1024,
34749
+ fallbackStringLimit: 1024
34750
+ };
34751
+ var LIVE_STATUS_ACTIVE_CHAT_OPTIONS = {
34752
+ includeMessages: false,
34753
+ includeInputContent: false,
34754
+ includeActiveModal: false,
34755
+ messageLimit: 0,
34756
+ totalBytesLimit: 0,
34757
+ stringLimit: 512,
34758
+ fallbackStringLimit: 256
34759
+ };
34720
34760
  var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
34721
34761
  var STATUS_MODAL_BUTTON_LIMIT = 120;
34722
34762
  function truncateString(value, maxChars) {
@@ -34755,19 +34795,20 @@ ${effect.notification.body || ""}`.trim();
34755
34795
  }
34756
34796
  return msg;
34757
34797
  }
34758
- function trimMessagesForStatus(messages) {
34798
+ function trimMessagesForStatus(messages, options) {
34799
+ if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];
34759
34800
  if (!Array.isArray(messages) || messages.length === 0) return [];
34760
- const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
34801
+ const recent = messages.slice(-options.messageLimit);
34761
34802
  const kept = [];
34762
34803
  let totalBytes = 0;
34763
34804
  for (let i = recent.length - 1; i >= 0; i -= 1) {
34764
- let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
34805
+ let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));
34765
34806
  let size = estimateBytes(normalized);
34766
- if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
34767
- normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
34807
+ if (size > options.totalBytesLimit) {
34808
+ normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));
34768
34809
  size = estimateBytes(normalized);
34769
34810
  }
34770
- if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
34811
+ if (kept.length > 0 && totalBytes + size > options.totalBytesLimit) {
34771
34812
  continue;
34772
34813
  }
34773
34814
  kept.push(normalized);
@@ -34797,21 +34838,38 @@ ${effect.notification.body || ""}`.trim();
34797
34838
  function isManagedStatusWaiting(status, opts) {
34798
34839
  return normalizeManagedStatus(status, opts) === "waiting_approval";
34799
34840
  }
34800
- function normalizeActiveChatData(activeChat) {
34841
+ function normalizeActiveChatData(activeChat, options = FULL_STATUS_ACTIVE_CHAT_OPTIONS) {
34801
34842
  if (!activeChat) return activeChat;
34843
+ const resolvedOptions = {
34844
+ ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,
34845
+ ...options
34846
+ };
34802
34847
  return {
34803
34848
  ...activeChat,
34804
34849
  status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
34805
- messages: trimMessagesForStatus(activeChat.messages),
34806
- activeModal: activeChat.activeModal ? {
34850
+ messages: trimMessagesForStatus(activeChat.messages, resolvedOptions),
34851
+ activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {
34807
34852
  message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
34808
34853
  buttons: (activeChat.activeModal.buttons || []).map(
34809
34854
  (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
34810
34855
  )
34811
- } : activeChat.activeModal,
34812
- inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
34856
+ } : null,
34857
+ inputContent: resolvedOptions.includeInputContent && activeChat.inputContent ? truncateString(activeChat.inputContent, 2 * 1024) : void 0
34813
34858
  };
34814
34859
  }
34860
+ function getActiveChatOptions(profile) {
34861
+ if (profile === "full") return {};
34862
+ return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
34863
+ }
34864
+ function shouldIncludeSessionControls(profile) {
34865
+ return profile !== "live";
34866
+ }
34867
+ function shouldIncludeSessionMetadata(profile) {
34868
+ return profile !== "live";
34869
+ }
34870
+ function shouldIncludeRuntimeMetadata(profile) {
34871
+ return profile !== "live";
34872
+ }
34815
34873
  function findCdpManager(cdpManagers, key) {
34816
34874
  const exact = cdpManagers.get(key);
34817
34875
  if (exact) return exact;
@@ -34919,74 +34977,88 @@ ${effect.notification.body || ""}`.trim();
34919
34977
  "set_mode",
34920
34978
  "set_thought_level"
34921
34979
  ];
34922
- function buildIdeWorkspaceSession(state, cdpManagers) {
34923
- const activeChat = normalizeActiveChatData(state.activeChat);
34980
+ function buildIdeWorkspaceSession(state, cdpManagers, options) {
34981
+ const profile = options.profile || "full";
34982
+ const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
34983
+ const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
34984
+ const includeSessionControls = shouldIncludeSessionControls(profile);
34924
34985
  const title = activeChat?.title || state.name;
34925
34986
  return {
34926
34987
  id: state.instanceId || state.type,
34927
34988
  parentId: null,
34928
34989
  providerType: state.type,
34929
- providerName: state.name,
34990
+ ...includeSessionMetadata && { providerName: state.name },
34930
34991
  kind: "workspace",
34931
34992
  transport: "cdp-page",
34932
34993
  status: normalizeManagedStatus(activeChat?.status || state.status, {
34933
34994
  activeModal: activeChat?.activeModal || null
34934
34995
  }),
34935
34996
  title,
34936
- workspace: state.workspace || null,
34997
+ ...includeSessionMetadata && { workspace: state.workspace || null },
34937
34998
  activeChat,
34938
- capabilities: IDE_SESSION_CAPABILITIES,
34999
+ ...includeSessionMetadata && { capabilities: IDE_SESSION_CAPABILITIES },
34939
35000
  cdpConnected: state.cdpConnected ?? isCdpConnected(cdpManagers, state.type),
34940
35001
  currentModel: state.currentModel,
34941
35002
  currentPlan: state.currentPlan,
34942
35003
  currentAutoApprove: state.currentAutoApprove,
34943
- controlValues: state.controlValues,
34944
- providerControls: buildFallbackControls(
34945
- state.providerControls,
34946
- state.currentModel,
34947
- state.currentPlan
34948
- ),
35004
+ ...includeSessionControls && {
35005
+ controlValues: state.controlValues,
35006
+ providerControls: buildFallbackControls(
35007
+ state.providerControls,
35008
+ state.currentModel,
35009
+ state.currentPlan
35010
+ )
35011
+ },
34949
35012
  errorMessage: state.errorMessage,
34950
35013
  errorReason: state.errorReason,
34951
35014
  lastUpdated: state.lastUpdated
34952
35015
  };
34953
35016
  }
34954
- function buildExtensionAgentSession(parent, ext) {
34955
- const activeChat = normalizeActiveChatData(ext.activeChat);
35017
+ function buildExtensionAgentSession(parent, ext, options) {
35018
+ const profile = options.profile || "full";
35019
+ const activeChat = normalizeActiveChatData(ext.activeChat, getActiveChatOptions(profile));
35020
+ const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
35021
+ const includeSessionControls = shouldIncludeSessionControls(profile);
34956
35022
  return {
34957
35023
  id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
34958
35024
  parentId: parent.instanceId || parent.type,
34959
35025
  providerType: ext.type,
34960
- providerName: ext.name,
35026
+ ...includeSessionMetadata && { providerName: ext.name },
34961
35027
  kind: "agent",
34962
35028
  transport: "cdp-webview",
34963
35029
  status: normalizeManagedStatus(activeChat?.status || ext.status, {
34964
35030
  activeModal: activeChat?.activeModal || null
34965
35031
  }),
34966
35032
  title: activeChat?.title || ext.name,
34967
- workspace: parent.workspace || null,
35033
+ ...includeSessionMetadata && { workspace: parent.workspace || null },
34968
35034
  activeChat,
34969
- capabilities: EXTENSION_SESSION_CAPABILITIES,
35035
+ ...includeSessionMetadata && { capabilities: EXTENSION_SESSION_CAPABILITIES },
34970
35036
  currentModel: ext.currentModel,
34971
35037
  currentPlan: ext.currentPlan,
34972
- controlValues: ext.controlValues,
34973
- providerControls: buildFallbackControls(
34974
- ext.providerControls,
34975
- ext.currentModel,
34976
- ext.currentPlan
34977
- ),
35038
+ ...includeSessionControls && {
35039
+ controlValues: ext.controlValues,
35040
+ providerControls: buildFallbackControls(
35041
+ ext.providerControls,
35042
+ ext.currentModel,
35043
+ ext.currentPlan
35044
+ )
35045
+ },
34978
35046
  errorMessage: ext.errorMessage,
34979
35047
  errorReason: ext.errorReason,
34980
35048
  lastUpdated: ext.lastUpdated
34981
35049
  };
34982
35050
  }
34983
- function buildCliSession(state) {
34984
- const activeChat = normalizeActiveChatData(state.activeChat);
35051
+ function buildCliSession(state, options) {
35052
+ const profile = options.profile || "full";
35053
+ const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
35054
+ const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
35055
+ const includeRuntimeMetadata = shouldIncludeRuntimeMetadata(profile);
35056
+ const includeSessionControls = shouldIncludeSessionControls(profile);
34985
35057
  return {
34986
35058
  id: state.instanceId,
34987
35059
  parentId: null,
34988
35060
  providerType: state.type,
34989
- providerName: state.name,
35061
+ ...includeSessionMetadata && { providerName: state.name },
34990
35062
  providerSessionId: state.providerSessionId,
34991
35063
  kind: "agent",
34992
35064
  transport: "pty",
@@ -34994,74 +35066,85 @@ ${effect.notification.body || ""}`.trim();
34994
35066
  activeModal: activeChat?.activeModal || null
34995
35067
  }),
34996
35068
  title: activeChat?.title || state.name,
34997
- workspace: state.workspace || null,
34998
- runtimeKey: state.runtime?.runtimeKey,
34999
- runtimeDisplayName: state.runtime?.displayName,
35000
- runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
35001
- runtimeWriteOwner: state.runtime?.writeOwner || null,
35002
- runtimeAttachedClients: state.runtime?.attachedClients || [],
35069
+ ...includeSessionMetadata && { workspace: state.workspace || null },
35070
+ ...includeRuntimeMetadata && {
35071
+ runtimeKey: state.runtime?.runtimeKey,
35072
+ runtimeDisplayName: state.runtime?.displayName,
35073
+ runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
35074
+ runtimeWriteOwner: state.runtime?.writeOwner || null,
35075
+ runtimeAttachedClients: state.runtime?.attachedClients || []
35076
+ },
35003
35077
  mode: state.mode,
35004
35078
  resume: state.resume,
35005
35079
  activeChat,
35006
- capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
35007
- controlValues: state.controlValues,
35008
- providerControls: buildFallbackControls(
35009
- state.providerControls
35010
- ),
35080
+ ...includeSessionMetadata && {
35081
+ capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES
35082
+ },
35083
+ ...includeSessionControls && {
35084
+ controlValues: state.controlValues,
35085
+ providerControls: buildFallbackControls(
35086
+ state.providerControls
35087
+ )
35088
+ },
35011
35089
  errorMessage: state.errorMessage,
35012
35090
  errorReason: state.errorReason,
35013
35091
  lastUpdated: state.lastUpdated
35014
35092
  };
35015
35093
  }
35016
- function buildAcpSession(state) {
35017
- const activeChat = normalizeActiveChatData(state.activeChat);
35094
+ function buildAcpSession(state, options) {
35095
+ const profile = options.profile || "full";
35096
+ const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
35097
+ const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
35098
+ const includeSessionControls = shouldIncludeSessionControls(profile);
35018
35099
  return {
35019
35100
  id: state.instanceId,
35020
35101
  parentId: null,
35021
35102
  providerType: state.type,
35022
- providerName: state.name,
35103
+ ...includeSessionMetadata && { providerName: state.name },
35023
35104
  kind: "agent",
35024
35105
  transport: "acp",
35025
35106
  status: normalizeManagedStatus(activeChat?.status || state.status, {
35026
35107
  activeModal: activeChat?.activeModal || null
35027
35108
  }),
35028
35109
  title: activeChat?.title || state.name,
35029
- workspace: state.workspace || null,
35110
+ ...includeSessionMetadata && { workspace: state.workspace || null },
35030
35111
  activeChat,
35031
- capabilities: ACP_SESSION_CAPABILITIES,
35112
+ ...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
35032
35113
  currentModel: state.currentModel,
35033
35114
  currentPlan: state.currentPlan,
35034
- acpConfigOptions: state.acpConfigOptions,
35035
- acpModes: state.acpModes,
35036
- controlValues: state.controlValues,
35037
- providerControls: buildFallbackControls(
35038
- state.providerControls,
35039
- state.currentModel,
35040
- state.currentPlan,
35041
- state.acpConfigOptions,
35042
- state.acpModes
35043
- ),
35115
+ ...includeSessionControls && {
35116
+ acpConfigOptions: state.acpConfigOptions,
35117
+ acpModes: state.acpModes,
35118
+ controlValues: state.controlValues,
35119
+ providerControls: buildFallbackControls(
35120
+ state.providerControls,
35121
+ state.currentModel,
35122
+ state.currentPlan,
35123
+ state.acpConfigOptions,
35124
+ state.acpModes
35125
+ )
35126
+ },
35044
35127
  errorMessage: state.errorMessage,
35045
35128
  errorReason: state.errorReason,
35046
35129
  lastUpdated: state.lastUpdated
35047
35130
  };
35048
35131
  }
35049
- function buildSessionEntries(allStates, cdpManagers) {
35132
+ function buildSessionEntries(allStates, cdpManagers, options = {}) {
35050
35133
  const sessions = [];
35051
35134
  const ideStates = allStates.filter((s15) => s15.category === "ide");
35052
35135
  const cliStates = allStates.filter((s15) => s15.category === "cli");
35053
35136
  const acpStates = allStates.filter((s15) => s15.category === "acp");
35054
35137
  for (const state of ideStates) {
35055
- sessions.push(buildIdeWorkspaceSession(state, cdpManagers));
35138
+ sessions.push(buildIdeWorkspaceSession(state, cdpManagers, options));
35056
35139
  for (const ext of state.extensions) {
35057
- sessions.push(buildExtensionAgentSession(state, ext));
35140
+ sessions.push(buildExtensionAgentSession(state, ext, options));
35058
35141
  }
35059
35142
  }
35060
35143
  for (const state of cliStates) {
35061
- sessions.push(buildCliSession(state));
35144
+ sessions.push(buildCliSession(state, options));
35062
35145
  }
35063
35146
  for (const state of acpStates) {
35064
- sessions.push(buildAcpSession(state));
35147
+ sessions.push(buildAcpSession(state, options));
35065
35148
  }
35066
35149
  const extensionParentIds = new Set(
35067
35150
  sessions.filter((session) => session.transport === "cdp-webview" && !!session.parentId).map((session) => session.parentId)
@@ -35117,9 +35200,26 @@ ${effect.notification.body || ""}`.trim();
35117
35200
  }
35118
35201
  }
35119
35202
  init_logger();
35203
+ function flattenContent(content) {
35204
+ if (typeof content === "string") return content;
35205
+ return content.filter((b2) => b2.type === "text").map((b2) => b2.text).join("\n");
35206
+ }
35120
35207
  init_logger();
35121
35208
  var RECENT_SEND_WINDOW_MS = 1200;
35122
35209
  var recentSendByTarget = /* @__PURE__ */ new Map();
35210
+ function hashSignatureParts2(parts) {
35211
+ let hash2 = 2166136261;
35212
+ for (const part of parts) {
35213
+ const text = String(part || "");
35214
+ for (let i = 0; i < text.length; i += 1) {
35215
+ hash2 ^= text.charCodeAt(i);
35216
+ hash2 = Math.imul(hash2, 16777619) >>> 0;
35217
+ }
35218
+ hash2 ^= 255;
35219
+ hash2 = Math.imul(hash2, 16777619) >>> 0;
35220
+ }
35221
+ return hash2.toString(16).padStart(8, "0");
35222
+ }
35123
35223
  function getCurrentProviderType(h, fallback = "") {
35124
35224
  return h.currentSession?.providerType || h.currentProviderType || fallback;
35125
35225
  }
@@ -35193,6 +35293,134 @@ ${effect.notification.body || ""}`.trim();
35193
35293
  return value;
35194
35294
  }
35195
35295
  }
35296
+ function getChatMessageSignature(message) {
35297
+ if (!message) return "";
35298
+ let content = "";
35299
+ try {
35300
+ content = JSON.stringify(message.content ?? "");
35301
+ } catch {
35302
+ content = String(message.content ?? "");
35303
+ }
35304
+ return hashSignatureParts2([
35305
+ String(message.id || ""),
35306
+ String(message.index ?? ""),
35307
+ String(message.role || ""),
35308
+ String(message.receivedAt ?? message.timestamp ?? ""),
35309
+ content
35310
+ ]);
35311
+ }
35312
+ function normalizeReadChatCursor(args) {
35313
+ const knownMessageCount = Math.max(0, Number(args?.knownMessageCount || 0));
35314
+ const lastMessageSignature = typeof args?.lastMessageSignature === "string" ? args.lastMessageSignature : "";
35315
+ const tailLimit = Math.max(0, Number(args?.tailLimit || 0));
35316
+ return { knownMessageCount, lastMessageSignature, tailLimit };
35317
+ }
35318
+ function normalizeReadChatMessages(payload) {
35319
+ const messages = Array.isArray(payload.messages) ? payload.messages : [];
35320
+ return messages;
35321
+ }
35322
+ function deriveHistoryDedupKey(message) {
35323
+ const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
35324
+ if (unitKey) return `read_chat:${unitKey}`;
35325
+ const turnKey = typeof message._turnKey === "string" ? message._turnKey.trim() : "";
35326
+ if (!turnKey) return void 0;
35327
+ let content = "";
35328
+ try {
35329
+ content = JSON.stringify(message.content ?? "");
35330
+ } catch {
35331
+ content = String(message.content ?? "");
35332
+ }
35333
+ return `read_chat:${turnKey}:${String(message.role || "").toLowerCase()}:${content}`;
35334
+ }
35335
+ function toHistoryPersistedMessages(messages) {
35336
+ return messages.map((message) => ({
35337
+ role: message.role,
35338
+ content: flattenContent(message.content),
35339
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : void 0,
35340
+ kind: typeof message.kind === "string" ? message.kind : void 0,
35341
+ senderName: typeof message.senderName === "string" ? message.senderName : void 0,
35342
+ historyDedupKey: deriveHistoryDedupKey(message)
35343
+ }));
35344
+ }
35345
+ function computeReadChatSync(messages, cursor) {
35346
+ const totalMessages = messages.length;
35347
+ const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
35348
+ const { knownMessageCount, lastMessageSignature: knownSignature } = cursor;
35349
+ if (!knownMessageCount || !knownSignature) {
35350
+ return {
35351
+ syncMode: "full",
35352
+ replaceFrom: 0,
35353
+ messages,
35354
+ totalMessages,
35355
+ lastMessageSignature
35356
+ };
35357
+ }
35358
+ if (knownMessageCount > totalMessages) {
35359
+ return {
35360
+ syncMode: "full",
35361
+ replaceFrom: 0,
35362
+ messages,
35363
+ totalMessages,
35364
+ lastMessageSignature
35365
+ };
35366
+ }
35367
+ if (knownMessageCount === totalMessages && knownSignature === lastMessageSignature) {
35368
+ return {
35369
+ syncMode: "noop",
35370
+ replaceFrom: totalMessages,
35371
+ messages: [],
35372
+ totalMessages,
35373
+ lastMessageSignature
35374
+ };
35375
+ }
35376
+ if (knownMessageCount < totalMessages) {
35377
+ const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
35378
+ if (anchorSignature === knownSignature) {
35379
+ return {
35380
+ syncMode: "append",
35381
+ replaceFrom: knownMessageCount,
35382
+ messages: messages.slice(knownMessageCount),
35383
+ totalMessages,
35384
+ lastMessageSignature
35385
+ };
35386
+ }
35387
+ }
35388
+ const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
35389
+ return {
35390
+ syncMode: replaceFrom === 0 ? "full" : "replace_tail",
35391
+ replaceFrom,
35392
+ messages: replaceFrom === 0 ? messages : messages.slice(replaceFrom),
35393
+ totalMessages,
35394
+ lastMessageSignature
35395
+ };
35396
+ }
35397
+ function buildReadChatCommandResult(payload, args) {
35398
+ const messages = normalizeReadChatMessages(payload);
35399
+ const cursor = normalizeReadChatCursor(args);
35400
+ if (!cursor.knownMessageCount && !cursor.lastMessageSignature && cursor.tailLimit > 0 && messages.length > cursor.tailLimit) {
35401
+ const tailMessages = messages.slice(-cursor.tailLimit);
35402
+ const lastMessageSignature = getChatMessageSignature(tailMessages[tailMessages.length - 1]);
35403
+ return {
35404
+ success: true,
35405
+ ...payload,
35406
+ messages: tailMessages,
35407
+ syncMode: "full",
35408
+ replaceFrom: 0,
35409
+ totalMessages: messages.length,
35410
+ lastMessageSignature
35411
+ };
35412
+ }
35413
+ const sync = computeReadChatSync(messages, cursor);
35414
+ return {
35415
+ success: true,
35416
+ ...payload,
35417
+ messages: sync.messages,
35418
+ syncMode: sync.syncMode,
35419
+ replaceFrom: sync.replaceFrom,
35420
+ totalMessages: sync.totalMessages,
35421
+ lastMessageSignature: sync.lastMessageSignature
35422
+ };
35423
+ }
35196
35424
  function didProviderConfirmSend(result) {
35197
35425
  const parsed = parseMaybeJson(result);
35198
35426
  if (parsed === true) return true;
@@ -35266,12 +35494,11 @@ ${effect.notification.body || ""}`.trim();
35266
35494
  _log(`${transport} adapter: ${adapter.cliType}`);
35267
35495
  const status = adapter.getStatus();
35268
35496
  if (status) {
35269
- return {
35270
- success: true,
35497
+ return buildReadChatCommandResult({
35271
35498
  messages: status.messages || [],
35272
35499
  status: status.status,
35273
35500
  activeModal: status.activeModal
35274
- };
35501
+ }, args);
35275
35502
  }
35276
35503
  }
35277
35504
  return { success: false, error: `${transport} adapter not found` };
@@ -35291,12 +35518,12 @@ ${effect.notification.body || ""}`.trim();
35291
35518
  _log(`Extension OK: ${parsed.messages?.length || 0} msgs`);
35292
35519
  h.historyWriter.appendNewMessages(
35293
35520
  provider?.type || "unknown_extension",
35294
- parsed.messages || [],
35521
+ toHistoryPersistedMessages(normalizeReadChatMessages(parsed)),
35295
35522
  parsed.title,
35296
35523
  args?.targetSessionId,
35297
35524
  historySessionId
35298
35525
  );
35299
- return { success: true, ...parsed };
35526
+ return buildReadChatCommandResult(parsed, args);
35300
35527
  }
35301
35528
  }
35302
35529
  } catch (e) {
@@ -35308,21 +35535,25 @@ ${effect.notification.body || ""}`.trim();
35308
35535
  if (cdp2 && parentSessionId) {
35309
35536
  const stream = await h.agentStream.collectActiveSession(cdp2, parentSessionId);
35310
35537
  if (stream?.agentType !== provider?.type) {
35311
- return { success: true, messages: [], status: "idle" };
35538
+ return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
35312
35539
  }
35313
35540
  if (stream) {
35314
35541
  h.historyWriter.appendNewMessages(
35315
35542
  stream.agentType,
35316
- stream.messages || [],
35543
+ toHistoryPersistedMessages(stream.messages || []),
35317
35544
  void 0,
35318
35545
  args?.targetSessionId,
35319
35546
  historySessionId
35320
35547
  );
35321
- return { success: true, messages: stream.messages || [], status: stream.status, agentType: stream.agentType };
35548
+ return buildReadChatCommandResult({
35549
+ messages: stream.messages || [],
35550
+ status: stream.status,
35551
+ agentType: stream.agentType
35552
+ }, args);
35322
35553
  }
35323
35554
  }
35324
35555
  }
35325
- return { success: true, messages: [], status: "idle" };
35556
+ return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
35326
35557
  }
35327
35558
  const cdp = h.getCdp();
35328
35559
  if (!cdp?.isConnected) return { success: false, error: "CDP not connected" };
@@ -35344,18 +35575,18 @@ ${effect.notification.body || ""}`.trim();
35344
35575
  _log(`Webview OK: ${parsed.messages?.length || 0} msgs`);
35345
35576
  h.historyWriter.appendNewMessages(
35346
35577
  provider?.type || getCurrentProviderType(h, "unknown_webview"),
35347
- parsed.messages || [],
35578
+ toHistoryPersistedMessages(normalizeReadChatMessages(parsed)),
35348
35579
  parsed.title,
35349
35580
  args?.targetSessionId,
35350
35581
  historySessionId
35351
35582
  );
35352
- return { success: true, ...parsed };
35583
+ return buildReadChatCommandResult(parsed, args);
35353
35584
  }
35354
35585
  }
35355
35586
  } catch (e) {
35356
35587
  _log(`Webview readChat error: ${e.message}`);
35357
35588
  }
35358
- return { success: true, messages: [], status: "idle" };
35589
+ return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
35359
35590
  }
35360
35591
  const script = h.getProviderScript("readChat") || h.getProviderScript("read_chat");
35361
35592
  if (script) {
@@ -35372,18 +35603,18 @@ ${effect.notification.body || ""}`.trim();
35372
35603
  _log(`OK: ${parsed.messages?.length} msgs`);
35373
35604
  h.historyWriter.appendNewMessages(
35374
35605
  provider?.type || getCurrentProviderType(h, "unknown_ide"),
35375
- parsed.messages || [],
35606
+ toHistoryPersistedMessages(normalizeReadChatMessages(parsed)),
35376
35607
  parsed.title,
35377
35608
  args?.targetSessionId,
35378
35609
  historySessionId
35379
35610
  );
35380
- return { success: true, ...parsed };
35611
+ return buildReadChatCommandResult(parsed, args);
35381
35612
  }
35382
35613
  } catch (e) {
35383
35614
  LOG2.info("Command", `[read_chat] Script error: ${e.message}`);
35384
35615
  }
35385
35616
  }
35386
- return { success: true, messages: [], status: "idle" };
35617
+ return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
35387
35618
  }
35388
35619
  async function handleSendChat(h, args) {
35389
35620
  const text = args?.text || args?.message;
@@ -36500,21 +36731,21 @@ ${effect.notification.body || ""}`.trim();
36500
36731
  });
36501
36732
  }
36502
36733
  async function executeProviderScript(h, args, scriptName) {
36503
- const { agentType, ideType } = args || {};
36504
- if (!agentType) return { success: false, error: "agentType is required" };
36734
+ const resolvedProviderType = h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
36735
+ if (!resolvedProviderType) return { success: false, error: "targetSessionId or providerType is required" };
36505
36736
  const loader = h.ctx.providerLoader;
36506
36737
  if (!loader) return { success: false, error: "ProviderLoader not initialized" };
36507
- const provider = loader.resolve(agentType);
36508
- if (!provider) return { success: false, error: `Provider not found: ${agentType}` };
36738
+ const provider = loader.resolve(resolvedProviderType);
36739
+ if (!provider) return { success: false, error: `Provider not found: ${resolvedProviderType}` };
36509
36740
  const webviewScriptName = `webview${scriptName.charAt(0).toUpperCase() + scriptName.slice(1)}`;
36510
36741
  const hasWebviewScript = provider.category === "ide" && !!provider.scripts?.[webviewScriptName];
36511
36742
  const actualScriptName = hasWebviewScript ? webviewScriptName : scriptName;
36512
36743
  if (!provider.scripts?.[actualScriptName]) {
36513
- return { success: false, error: `Script '${actualScriptName}' not available for ${agentType}` };
36744
+ return { success: false, error: `Script '${actualScriptName}' not available for ${resolvedProviderType}` };
36514
36745
  }
36515
36746
  const normalizedArgs = normalizeProviderScriptArgs(args);
36516
36747
  if (provider.category === "cli") {
36517
- const adapter = h.getCliAdapter(args?.targetSessionId || agentType);
36748
+ const adapter = h.getCliAdapter(args?.targetSessionId || resolvedProviderType);
36518
36749
  if (!adapter?.invokeScript) {
36519
36750
  return { success: false, error: `CLI adapter does not support script '${actualScriptName}'` };
36520
36751
  }
@@ -36539,7 +36770,7 @@ ${effect.notification.body || ""}`.trim();
36539
36770
  const scriptFn = provider.scripts[actualScriptName];
36540
36771
  const scriptCode = scriptFn(normalizedArgs);
36541
36772
  if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
36542
- const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || agentType : h.currentSession?.cdpManagerKey || h.currentManagerKey || ideType;
36773
+ const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : h.currentSession?.cdpManagerKey || h.currentManagerKey;
36543
36774
  LOG2.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
36544
36775
  const cdp = h.getCdp(cdpKey);
36545
36776
  if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
@@ -36547,7 +36778,7 @@ ${effect.notification.body || ""}`.trim();
36547
36778
  let result;
36548
36779
  if (provider.category === "extension") {
36549
36780
  const runtimeSessionId = h.currentSession?.sessionId || args?.targetSessionId;
36550
- if (!runtimeSessionId) return { success: false, error: `No target session found for ${agentType}` };
36781
+ if (!runtimeSessionId) return { success: false, error: `No target session found for ${resolvedProviderType}` };
36551
36782
  const parentSessionId = h.currentSession?.parentSessionId;
36552
36783
  if (parentSessionId) {
36553
36784
  await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
@@ -36576,7 +36807,7 @@ ${effect.notification.body || ""}`.trim();
36576
36807
  }
36577
36808
  } else {
36578
36809
  if (!targetSessionId) {
36579
- return { success: false, error: `No active session found for ${agentType}` };
36810
+ return { success: false, error: `No active session found for ${resolvedProviderType}` };
36580
36811
  }
36581
36812
  result = await cdp.evaluateInSessionFrame(targetSessionId, scriptCode);
36582
36813
  }
@@ -37949,10 +38180,6 @@ ${effect.notification.body || ""}`.trim();
37949
38180
  var import_stream = require("stream");
37950
38181
  var import_child_process5 = require("child_process");
37951
38182
  var import_sdk = (init_acp(), __toCommonJS(acp_exports));
37952
- function flattenContent(content) {
37953
- if (typeof content === "string") return content;
37954
- return content.filter((b2) => b2.type === "text").map((b2) => b2.text).join("\n");
37955
- }
37956
38183
  init_logger();
37957
38184
  var AcpProviderInstance = class {
37958
38185
  constructor(provider, workingDir, cliArgs = []) {
@@ -41302,6 +41529,37 @@ Run 'adhdev doctor' for detailed diagnostics.`
41302
41529
  ...provider.detectedPath !== void 0 ? { detectedPath: provider.detectedPath } : {}
41303
41530
  }));
41304
41531
  }
41532
+ function buildMachineInfo2(profile = "full") {
41533
+ const base = {
41534
+ hostname: os16.hostname(),
41535
+ platform: os16.platform()
41536
+ };
41537
+ if (profile === "live") {
41538
+ return base;
41539
+ }
41540
+ if (profile === "metadata") {
41541
+ const memSnap2 = getHostMemorySnapshot();
41542
+ return {
41543
+ ...base,
41544
+ arch: os16.arch(),
41545
+ cpus: os16.cpus().length,
41546
+ totalMem: memSnap2.totalMem,
41547
+ release: os16.release()
41548
+ };
41549
+ }
41550
+ const memSnap = getHostMemorySnapshot();
41551
+ return {
41552
+ ...base,
41553
+ arch: os16.arch(),
41554
+ cpus: os16.cpus().length,
41555
+ totalMem: memSnap.totalMem,
41556
+ freeMem: memSnap.freeMem,
41557
+ availableMem: memSnap.availableMem,
41558
+ loadavg: os16.loadavg(),
41559
+ uptime: os16.uptime(),
41560
+ release: os16.release()
41561
+ };
41562
+ }
41305
41563
  function parseMessageTime(value) {
41306
41564
  if (typeof value === "number" && Number.isFinite(value)) return value;
41307
41565
  if (typeof value === "string") {
@@ -41357,26 +41615,35 @@ Run 'adhdev doctor' for detailed diagnostics.`
41357
41615
  })).sort((a, b2) => b2.lastLaunchedAt - a.lastLaunchedAt).slice(0, 12);
41358
41616
  }
41359
41617
  function buildStatusSnapshot2(options) {
41618
+ const profile = options.profile || "full";
41360
41619
  const cfg = loadConfig2();
41361
41620
  const state = loadState();
41362
41621
  const wsState = getWorkspaceState2(cfg);
41363
- const memSnap = getHostMemorySnapshot();
41364
41622
  const recentActivity = getRecentActivity(state, 20);
41365
- const sessions = buildSessionEntries(
41623
+ const unreadSourceSessions = buildSessionEntries(
41366
41624
  options.allStates,
41367
- options.cdpManagers
41625
+ options.cdpManagers,
41626
+ { profile: "full" }
41368
41627
  );
41369
- for (const session of sessions) {
41370
- const lastSeenAt = getSessionSeenAt(state, session.id);
41371
- const seenCompletionMarker = getSessionSeenMarker(state, session.id);
41372
- const lastUsedAt = getSessionLastUsedAt(session);
41373
- const completionMarker = getSessionCompletionMarker(session);
41374
- const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
41375
- getSessionMessageUpdatedAt(session) > 0,
41376
- session.status,
41628
+ const sessions = profile === "full" ? unreadSourceSessions : buildSessionEntries(
41629
+ options.allStates,
41630
+ options.cdpManagers,
41631
+ { profile }
41632
+ );
41633
+ const sessionsById = new Map(sessions.map((session) => [session.id, session]));
41634
+ for (const sourceSession of unreadSourceSessions) {
41635
+ const session = sessionsById.get(sourceSession.id);
41636
+ if (!session) continue;
41637
+ const lastSeenAt = getSessionSeenAt(state, sourceSession.id);
41638
+ const seenCompletionMarker = getSessionSeenMarker(state, sourceSession.id);
41639
+ const lastUsedAt = getSessionLastUsedAt(sourceSession);
41640
+ const completionMarker = getSessionCompletionMarker(sourceSession);
41641
+ const { unread, inboxBucket } = sourceSession.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
41642
+ getSessionMessageUpdatedAt(sourceSession) > 0,
41643
+ sourceSession.status,
41377
41644
  lastUsedAt,
41378
41645
  lastSeenAt,
41379
- getLastMessageRole(session),
41646
+ getLastMessageRole(sourceSession),
41380
41647
  completionMarker,
41381
41648
  seenCompletionMarker
41382
41649
  );
@@ -41386,39 +41653,30 @@ Run 'adhdev doctor' for detailed diagnostics.`
41386
41653
  if (READ_DEBUG_ENABLED && (session.unread || session.inboxBucket !== "idle" || session.providerType.includes("codex"))) {
41387
41654
  LOG2.info(
41388
41655
  "RecentRead",
41389
- `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)}`
41656
+ `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(sourceSession)} msgUpdatedAt=${getSessionMessageUpdatedAt(sourceSession)}`
41390
41657
  );
41391
41658
  }
41392
41659
  }
41393
- const terminalBackend = getTerminalBackendRuntimeStatus();
41660
+ const includeMachineMetadata = profile !== "live";
41661
+ const terminalBackend = includeMachineMetadata ? getTerminalBackendRuntimeStatus() : void 0;
41394
41662
  return {
41395
41663
  instanceId: options.instanceId,
41396
- version: options.version,
41397
- daemonMode: options.daemonMode,
41398
- machine: {
41399
- hostname: os16.hostname(),
41400
- platform: os16.platform(),
41401
- arch: os16.arch(),
41402
- cpus: os16.cpus().length,
41403
- totalMem: memSnap.totalMem,
41404
- freeMem: memSnap.freeMem,
41405
- availableMem: memSnap.availableMem,
41406
- loadavg: os16.loadavg(),
41407
- uptime: os16.uptime(),
41408
- release: os16.release()
41409
- },
41410
- machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
41664
+ ...includeMachineMetadata ? { version: options.version } : {},
41665
+ machine: buildMachineInfo2(profile),
41666
+ ...includeMachineMetadata ? { machineNickname: options.machineNickname ?? cfg.machineNickname ?? null } : {},
41411
41667
  timestamp: options.timestamp ?? Date.now(),
41412
- detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
41413
41668
  ...options.p2p ? { p2p: options.p2p } : {},
41414
41669
  sessions,
41415
- workspaces: wsState.workspaces,
41416
- defaultWorkspaceId: wsState.defaultWorkspaceId,
41417
- defaultWorkspacePath: wsState.defaultWorkspacePath,
41418
- terminalSizingMode: cfg.terminalSizingMode || "measured",
41419
- recentLaunches: buildRecentLaunches(recentActivity),
41420
- terminalBackend,
41421
- availableProviders: buildAvailableProviders(options.providerLoader)
41670
+ ...terminalBackend ? { terminalBackend } : {},
41671
+ ...includeMachineMetadata && {
41672
+ detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
41673
+ workspaces: wsState.workspaces,
41674
+ defaultWorkspaceId: wsState.defaultWorkspaceId,
41675
+ defaultWorkspacePath: wsState.defaultWorkspacePath,
41676
+ terminalSizingMode: cfg.terminalSizingMode || "measured",
41677
+ recentLaunches: buildRecentLaunches(recentActivity),
41678
+ availableProviders: buildAvailableProviders(options.providerLoader)
41679
+ }
41422
41680
  };
41423
41681
  }
41424
41682
  var import_child_process7 = require("child_process");
@@ -41970,6 +42228,25 @@ Run 'adhdev doctor' for detailed diagnostics.`
41970
42228
  updateConfig({ userName: name });
41971
42229
  return { success: true, userName: name };
41972
42230
  }
42231
+ case "get_status_metadata": {
42232
+ const snapshot = buildStatusSnapshot2({
42233
+ allStates: this.deps.instanceManager.collectAllStates(),
42234
+ cdpManagers: this.deps.cdpManagers,
42235
+ providerLoader: this.deps.providerLoader,
42236
+ detectedIdes: this.deps.detectedIdes.value,
42237
+ instanceId: this.deps.statusInstanceId || loadConfig2().machineId || "daemon",
42238
+ version: this.deps.statusVersion || "unknown",
42239
+ profile: "metadata"
42240
+ });
42241
+ return { success: true, status: snapshot };
42242
+ }
42243
+ case "get_machine_runtime_stats": {
42244
+ return {
42245
+ success: true,
42246
+ machine: buildMachineInfo2("full"),
42247
+ timestamp: Date.now()
42248
+ };
42249
+ }
41973
42250
  case "mark_session_seen": {
41974
42251
  const sessionId = args?.sessionId;
41975
42252
  if (!sessionId || typeof sessionId !== "string") {
@@ -42121,6 +42398,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
42121
42398
  lastStatusSentAt = 0;
42122
42399
  statusPendingThrottle = false;
42123
42400
  lastP2PStatusHash = "";
42401
+ lastServerStatusHash = "";
42124
42402
  lastStatusSummary = "";
42125
42403
  statusTimer = null;
42126
42404
  p2pTimer = null;
@@ -42131,11 +42409,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
42131
42409
  // ─── Lifecycle ───────────────────────────────────
42132
42410
  startReporting() {
42133
42411
  setTimeout(() => {
42134
- this.sendUnifiedStatusReport().catch((e) => LOG2.warn("Status", `Initial report failed: ${e?.message}`));
42412
+ this.sendUnifiedStatusReport({ forceServer: true, reason: "initial" }).catch((e) => LOG2.warn("Status", `Initial report failed: ${e?.message}`));
42135
42413
  }, 2e3);
42136
42414
  const scheduleServerReport = () => {
42137
42415
  this.statusTimer = setTimeout(() => {
42138
- this.sendUnifiedStatusReport().catch((e) => LOG2.warn("Status", `Periodic report failed: ${e?.message}`));
42416
+ this.sendUnifiedStatusReport({ forceServer: true, reason: "periodic" }).catch((e) => LOG2.warn("Status", `Periodic report failed: ${e?.message}`));
42139
42417
  scheduleServerReport();
42140
42418
  }, 3e4);
42141
42419
  };
@@ -42172,9 +42450,58 @@ Run 'adhdev doctor' for detailed diagnostics.`
42172
42450
  }, 5e3 - elapsed);
42173
42451
  }
42174
42452
  }
42453
+ toDaemonStatusEventName(value) {
42454
+ switch (value) {
42455
+ case "agent:generating_started":
42456
+ case "agent:waiting_approval":
42457
+ case "agent:generating_completed":
42458
+ case "agent:stopped":
42459
+ case "monitor:long_generating":
42460
+ return value;
42461
+ default:
42462
+ return null;
42463
+ }
42464
+ }
42465
+ buildServerStatusEvent(event) {
42466
+ const eventName = this.toDaemonStatusEventName(event.event);
42467
+ if (!eventName) return null;
42468
+ if (eventName.startsWith("provider:")) {
42469
+ return null;
42470
+ }
42471
+ const payload = {
42472
+ event: eventName,
42473
+ timestamp: typeof event.timestamp === "number" && Number.isFinite(event.timestamp) ? event.timestamp : Date.now()
42474
+ };
42475
+ if (typeof event.targetSessionId === "string" && event.targetSessionId.trim()) {
42476
+ payload.targetSessionId = event.targetSessionId.trim();
42477
+ }
42478
+ const providerType = typeof event.providerType === "string" && event.providerType.trim() ? event.providerType.trim() : typeof event.ideType === "string" && event.ideType.trim() ? event.ideType.trim() : "";
42479
+ if (providerType) {
42480
+ payload.providerType = providerType;
42481
+ }
42482
+ if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
42483
+ payload.duration = event.duration;
42484
+ }
42485
+ if (typeof event.elapsedSec === "number" && Number.isFinite(event.elapsedSec)) {
42486
+ payload.elapsedSec = event.elapsedSec;
42487
+ }
42488
+ if (typeof event.modalMessage === "string" && event.modalMessage.trim()) {
42489
+ payload.modalMessage = event.modalMessage;
42490
+ }
42491
+ if (Array.isArray(event.modalButtons)) {
42492
+ const modalButtons = event.modalButtons.filter((button) => typeof button === "string" && button.trim().length > 0);
42493
+ if (modalButtons.length > 0) {
42494
+ payload.modalButtons = modalButtons;
42495
+ }
42496
+ }
42497
+ return payload;
42498
+ }
42175
42499
  emitStatusEvent(event) {
42176
42500
  LOG2.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
42177
- this.deps.serverConn?.sendMessage("status_event", event);
42501
+ const serverEvent = this.buildServerStatusEvent(event);
42502
+ if (!serverEvent) return;
42503
+ this.deps.p2p?.sendStatusEvent(serverEvent);
42504
+ this.deps.serverConn?.sendMessage("status_event", serverEvent);
42178
42505
  }
42179
42506
  removeAgentTracking(_key) {
42180
42507
  }
@@ -42243,17 +42570,16 @@ Run 'adhdev doctor' for detailed diagnostics.`
42243
42570
  detectedIdes: this.deps.detectedIdes || [],
42244
42571
  instanceId: this.deps.instanceId,
42245
42572
  version: this.deps.daemonVersion || "unknown",
42246
- daemonMode: true,
42247
42573
  timestamp: now,
42248
42574
  p2p: {
42249
42575
  available: p2p?.isAvailable || false,
42250
42576
  state: p2p?.connectionState || "unavailable",
42251
42577
  peers: p2p?.connectedPeerCount || 0,
42252
42578
  screenshotActive: p2p?.screenshotActive || false
42253
- }
42579
+ },
42580
+ profile: "live"
42254
42581
  }),
42255
- screenshotUsage: this.deps.getScreenshotUsage?.() || null,
42256
- connectedExtensions: []
42582
+ screenshotUsage: this.deps.getScreenshotUsage?.() || null
42257
42583
  };
42258
42584
  const payloadBytes = JSON.stringify(payload).length;
42259
42585
  const p2pSent = this.sendP2PPayload(payload);
@@ -42268,46 +42594,48 @@ Run 'adhdev doctor' for detailed diagnostics.`
42268
42594
  }
42269
42595
  if (opts?.p2pOnly) return;
42270
42596
  const wsPayload = {
42271
- daemonMode: true,
42272
42597
  sessions: sessions.map((session) => ({
42273
42598
  id: session.id,
42274
42599
  parentId: session.parentId,
42275
42600
  providerType: session.providerType,
42276
- providerName: session.providerName,
42601
+ providerName: session.providerName || session.providerType,
42277
42602
  kind: session.kind,
42278
42603
  transport: session.transport,
42279
42604
  status: session.status,
42280
- workspace: session.workspace,
42605
+ workspace: session.workspace ?? null,
42281
42606
  title: session.title,
42282
42607
  cdpConnected: session.cdpConnected,
42283
42608
  currentModel: session.currentModel,
42284
42609
  currentPlan: session.currentPlan,
42285
- currentAutoApprove: session.currentAutoApprove,
42286
- lastUpdated: session.lastUpdated,
42287
- unread: session.unread,
42288
- lastSeenAt: session.lastSeenAt,
42289
- inboxBucket: session.inboxBucket,
42290
- surfaceHidden: session.surfaceHidden,
42291
- controlValues: session.controlValues,
42292
- providerControls: session.providerControls,
42293
- acpConfigOptions: session.acpConfigOptions,
42294
- acpModes: session.acpModes
42610
+ currentAutoApprove: session.currentAutoApprove
42295
42611
  })),
42296
42612
  p2p: payload.p2p,
42297
- timestamp: now,
42298
- detectedIdes: payload.detectedIdes,
42299
- availableProviders: payload.availableProviders
42613
+ timestamp: now
42300
42614
  };
42615
+ const wsHash = this.simpleHash(JSON.stringify({
42616
+ ...wsPayload,
42617
+ timestamp: void 0
42618
+ }));
42619
+ if (!opts?.forceServer && wsHash === this.lastServerStatusHash) {
42620
+ LOG2.debug("Server", `skip duplicate status_report${opts?.reason ? ` (${opts.reason})` : ""}`);
42621
+ return;
42622
+ }
42623
+ this.lastServerStatusHash = wsHash;
42301
42624
  serverConn.sendMessage("status_report", wsPayload);
42302
- LOG2.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
42625
+ LOG2.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)${opts?.reason ? ` [${opts.reason}]` : ""}`);
42303
42626
  }
42304
42627
  // ─── P2P ─────────────────────────────────────────
42305
42628
  sendP2PPayload(payload) {
42306
42629
  const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
42630
+ const sessions = Array.isArray(hashTarget.sessions) ? hashTarget.sessions.map((session) => {
42631
+ if (!session || typeof session !== "object") return session;
42632
+ const { lastUpdated: _lu, ...stableSession } = session;
42633
+ return stableSession;
42634
+ }) : hashTarget.sessions;
42307
42635
  const hashPayload = hashTarget.machine ? (() => {
42308
42636
  const { freeMem: _f, availableMem: _a2, loadavg: _l2, uptime: _u, ...stableMachine } = hashTarget.machine;
42309
- return { ...hashTarget, machine: stableMachine };
42310
- })() : hashTarget;
42637
+ return { ...hashTarget, sessions, machine: stableMachine };
42638
+ })() : { ...hashTarget, sessions };
42311
42639
  const h = this.simpleHash(JSON.stringify(hashPayload));
42312
42640
  if (h !== this.lastP2PStatusHash) {
42313
42641
  this.lastP2PStatusHash = h;
@@ -49363,6 +49691,8 @@ data: ${JSON.stringify(msg.data)}
49363
49691
  onStatusChange: config2.onStatusChange,
49364
49692
  onPostChatCommand: config2.onPostChatCommand,
49365
49693
  sessionHostControl: config2.sessionHostControl,
49694
+ statusInstanceId: config2.statusInstanceId,
49695
+ statusVersion: config2.statusVersion,
49366
49696
  getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG2.forComponent(`CDP:${ideType}`).asLogFn())
49367
49697
  });
49368
49698
  poller = new AgentStreamPoller({
@@ -49990,18 +50320,75 @@ var SESSION_TARGET_COMMANDS = /* @__PURE__ */ new Set([
49990
50320
  "restart_session",
49991
50321
  "agent_command"
49992
50322
  ]);
50323
+ var ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
50324
+ "generating",
50325
+ "waiting_approval",
50326
+ "starting"
50327
+ ]);
50328
+ function hashSignatureParts(parts) {
50329
+ let hash2 = 2166136261;
50330
+ for (const part of parts) {
50331
+ const text = String(part || "");
50332
+ for (let i = 0; i < text.length; i += 1) {
50333
+ hash2 ^= text.charCodeAt(i);
50334
+ hash2 = Math.imul(hash2, 16777619) >>> 0;
50335
+ }
50336
+ hash2 ^= 255;
50337
+ hash2 = Math.imul(hash2, 16777619) >>> 0;
50338
+ }
50339
+ return hash2.toString(16).padStart(8, "0");
50340
+ }
50341
+ function buildChatTailDeliverySignature(payload) {
50342
+ let messages = "";
50343
+ try {
50344
+ messages = JSON.stringify(payload.messages);
50345
+ } catch {
50346
+ messages = String(payload.messages.length);
50347
+ }
50348
+ return hashSignatureParts([
50349
+ payload.sessionId,
50350
+ payload.historySessionId || "",
50351
+ payload.status,
50352
+ payload.title || "",
50353
+ payload.syncMode,
50354
+ String(payload.replaceFrom),
50355
+ String(payload.totalMessages),
50356
+ payload.lastMessageSignature,
50357
+ payload.activeModal ? `${payload.activeModal.message}|${payload.activeModal.buttons.join("")}` : "",
50358
+ messages
50359
+ ]);
50360
+ }
50361
+ function buildSessionModalDeliverySignature(payload) {
50362
+ return hashSignatureParts([
50363
+ payload.sessionId,
50364
+ payload.status,
50365
+ payload.title || "",
50366
+ payload.modalMessage || "",
50367
+ Array.isArray(payload.modalButtons) ? payload.modalButtons.join("") : ""
50368
+ ]);
50369
+ }
49993
50370
  var StandaloneServer = class {
49994
50371
  httpServer = null;
49995
50372
  wss = null;
49996
50373
  clients = /* @__PURE__ */ new Set();
50374
+ wsSubscriptions = /* @__PURE__ */ new Map();
50375
+ wsMachineRuntimeSubscriptions = /* @__PURE__ */ new Map();
50376
+ wsSessionHostDiagnosticsSubscriptions = /* @__PURE__ */ new Map();
50377
+ wsSessionModalSubscriptions = /* @__PURE__ */ new Map();
50378
+ wsDaemonMetadataSubscriptions = /* @__PURE__ */ new Map();
49997
50379
  authToken = null;
49998
50380
  statusTimer = null;
49999
50381
  lastStatusBroadcastAt = 0;
50000
50382
  statusBroadcastPending = false;
50383
+ lastWsStatusSignature = null;
50384
+ wsChatFlushInFlight = false;
50385
+ pendingWsChatFlush = null;
50386
+ hotWsChatSessionIds = /* @__PURE__ */ new Set();
50001
50387
  running = false;
50002
50388
  components = null;
50003
50389
  devServer = null;
50004
50390
  sessionHostEndpoint = null;
50391
+ sessionHostControl = null;
50005
50392
  isRecoverableSessionHostError(error48) {
50006
50393
  const message = error48 instanceof Error ? error48.message : String(error48);
50007
50394
  return message.includes("ECONNREFUSED") || message.includes("ENOENT") || message.includes("Session host socket unavailable");
@@ -50049,12 +50436,15 @@ var StandaloneServer = class {
50049
50436
  async start(options = {}) {
50050
50437
  const port = options.port || DEFAULT_PORT;
50051
50438
  const host = options.host || "127.0.0.1";
50439
+ const cfg = (0, import_daemon_core2.loadConfig)();
50052
50440
  const sessionHostEndpoint = await ensureSessionHostReady();
50053
50441
  this.sessionHostEndpoint = sessionHostEndpoint;
50054
50442
  const sessionHostControl = new StandaloneSessionHostControlPlane(
50055
50443
  async () => this.ensureActiveSessionHostEndpoint()
50056
50444
  );
50445
+ this.sessionHostControl = sessionHostControl;
50057
50446
  this.authToken = options.token || process.env.ADHDEV_TOKEN || null;
50447
+ const statusInstanceId = `standalone_${cfg.machineId || "mach_unknown"}`;
50058
50448
  this.components = await (0, import_daemon_core2.initDaemonComponents)({
50059
50449
  cliManagerDeps: {
50060
50450
  getServerConn: () => null,
@@ -50091,6 +50481,9 @@ var StandaloneServer = class {
50091
50481
  }),
50092
50482
  listHostedCliRuntimes: async () => listHostedCliRuntimes(sessionHostEndpoint)
50093
50483
  },
50484
+ statusInstanceId,
50485
+ statusVersion: pkgVersion,
50486
+ statusDaemonMode: false,
50094
50487
  onStatusChange: () => this.scheduleBroadcastStatus(),
50095
50488
  sessionHostControl,
50096
50489
  onStreamsUpdated: (ideType, streams) => {
@@ -50132,6 +50525,10 @@ var StandaloneServer = class {
50132
50525
  });
50133
50526
  this.statusTimer = setInterval(() => {
50134
50527
  this.scheduleBroadcastStatus();
50528
+ void this.flushWsChatSubscriptions(void 0, { onlyActive: true });
50529
+ void this.flushWsMachineRuntimeSubscriptions();
50530
+ void this.flushWsSessionHostDiagnosticsSubscriptions();
50531
+ void this.flushWsSessionModalSubscriptions();
50135
50532
  }, STATUS_INTERVAL);
50136
50533
  this.running = true;
50137
50534
  await new Promise((resolve4) => {
@@ -50467,13 +50864,27 @@ var StandaloneServer = class {
50467
50864
  }
50468
50865
  }
50469
50866
  this.clients.add(ws2);
50867
+ this.wsSubscriptions.set(ws2, /* @__PURE__ */ new Map());
50868
+ this.wsMachineRuntimeSubscriptions.set(ws2, /* @__PURE__ */ new Map());
50869
+ this.wsSessionHostDiagnosticsSubscriptions.set(ws2, /* @__PURE__ */ new Map());
50870
+ this.wsSessionModalSubscriptions.set(ws2, /* @__PURE__ */ new Map());
50871
+ this.wsDaemonMetadataSubscriptions.set(ws2, /* @__PURE__ */ new Map());
50470
50872
  console.log(`[WS] Client connected (total: ${this.clients.size})`);
50471
- const status = this.getStatus();
50873
+ const status = this.getWsStatus(this.buildSharedSnapshot("live"));
50874
+ this.lastWsStatusSignature = this.buildWsStatusSignature(status);
50472
50875
  ws2.send(JSON.stringify({ type: "status", data: status }));
50473
50876
  void this.pushWsRuntimeSnapshots(ws2);
50474
50877
  ws2.on("message", async (raw) => {
50475
50878
  try {
50476
50879
  const msg = JSON.parse(raw.toString());
50880
+ if (msg.type === "subscribe") {
50881
+ await this.handleWsSubscribe(ws2, msg);
50882
+ return;
50883
+ }
50884
+ if (msg.type === "unsubscribe") {
50885
+ this.handleWsUnsubscribe(ws2, msg);
50886
+ return;
50887
+ }
50477
50888
  if (msg.type === "command") {
50478
50889
  const envelope = msg.data && typeof msg.data === "object" ? {
50479
50890
  ...msg.data,
@@ -50497,14 +50908,394 @@ var StandaloneServer = class {
50497
50908
  });
50498
50909
  ws2.on("close", () => {
50499
50910
  this.clients.delete(ws2);
50911
+ this.wsSubscriptions.delete(ws2);
50912
+ this.wsMachineRuntimeSubscriptions.delete(ws2);
50913
+ this.wsSessionHostDiagnosticsSubscriptions.delete(ws2);
50914
+ this.wsSessionModalSubscriptions.delete(ws2);
50915
+ this.wsDaemonMetadataSubscriptions.delete(ws2);
50500
50916
  console.log(`[WS] Client disconnected (total: ${this.clients.size})`);
50501
50917
  });
50502
50918
  ws2.on("error", () => {
50503
50919
  this.clients.delete(ws2);
50920
+ this.wsSubscriptions.delete(ws2);
50921
+ this.wsMachineRuntimeSubscriptions.delete(ws2);
50922
+ this.wsSessionHostDiagnosticsSubscriptions.delete(ws2);
50923
+ this.wsSessionModalSubscriptions.delete(ws2);
50924
+ this.wsDaemonMetadataSubscriptions.delete(ws2);
50925
+ });
50926
+ }
50927
+ async handleWsSubscribe(ws2, msg) {
50928
+ if (msg.topic === "session.chat_tail") {
50929
+ const params = msg.params;
50930
+ if (!params?.targetSessionId) return;
50931
+ const subs = this.wsSubscriptions.get(ws2) || /* @__PURE__ */ new Map();
50932
+ this.wsSubscriptions.set(ws2, subs);
50933
+ subs.set(msg.key, {
50934
+ request: {
50935
+ ...msg,
50936
+ topic: "session.chat_tail",
50937
+ params
50938
+ },
50939
+ seq: 0,
50940
+ cursor: {
50941
+ knownMessageCount: Math.max(0, Number(params.knownMessageCount || 0)),
50942
+ lastMessageSignature: typeof params.lastMessageSignature === "string" ? params.lastMessageSignature : "",
50943
+ tailLimit: Math.max(0, Number(params.tailLimit || 0))
50944
+ },
50945
+ lastDeliveredSignature: ""
50946
+ });
50947
+ await this.flushWsChatSubscriptions(ws2);
50948
+ return;
50949
+ }
50950
+ if (msg.topic === "machine.runtime") {
50951
+ const params = msg.params;
50952
+ const subs = this.wsMachineRuntimeSubscriptions.get(ws2) || /* @__PURE__ */ new Map();
50953
+ this.wsMachineRuntimeSubscriptions.set(ws2, subs);
50954
+ subs.set(msg.key, {
50955
+ request: {
50956
+ ...msg,
50957
+ topic: "machine.runtime",
50958
+ params
50959
+ },
50960
+ seq: 0,
50961
+ lastSentAt: 0
50962
+ });
50963
+ await this.flushWsMachineRuntimeSubscriptions(ws2);
50964
+ return;
50965
+ }
50966
+ if (msg.topic === "session_host.diagnostics") {
50967
+ const params = msg.params;
50968
+ const subs = this.wsSessionHostDiagnosticsSubscriptions.get(ws2) || /* @__PURE__ */ new Map();
50969
+ this.wsSessionHostDiagnosticsSubscriptions.set(ws2, subs);
50970
+ subs.set(msg.key, {
50971
+ request: {
50972
+ ...msg,
50973
+ topic: "session_host.diagnostics",
50974
+ params
50975
+ },
50976
+ seq: 0,
50977
+ lastSentAt: 0
50978
+ });
50979
+ await this.flushWsSessionHostDiagnosticsSubscriptions(ws2);
50980
+ return;
50981
+ }
50982
+ if (msg.topic === "session.modal") {
50983
+ const params = msg.params;
50984
+ if (!params?.targetSessionId) return;
50985
+ const subs = this.wsSessionModalSubscriptions.get(ws2) || /* @__PURE__ */ new Map();
50986
+ this.wsSessionModalSubscriptions.set(ws2, subs);
50987
+ subs.set(msg.key, {
50988
+ request: {
50989
+ ...msg,
50990
+ topic: "session.modal",
50991
+ params
50992
+ },
50993
+ seq: 0,
50994
+ lastSentAt: 0,
50995
+ lastDeliveredSignature: ""
50996
+ });
50997
+ await this.flushWsSessionModalSubscriptions(ws2);
50998
+ return;
50999
+ }
51000
+ if (msg.topic === "daemon.metadata") {
51001
+ const params = msg.params;
51002
+ const subs = this.wsDaemonMetadataSubscriptions.get(ws2) || /* @__PURE__ */ new Map();
51003
+ this.wsDaemonMetadataSubscriptions.set(ws2, subs);
51004
+ subs.set(msg.key, {
51005
+ request: {
51006
+ ...msg,
51007
+ topic: "daemon.metadata",
51008
+ params
51009
+ },
51010
+ seq: 0,
51011
+ lastSentAt: 0
51012
+ });
51013
+ await this.flushWsDaemonMetadataSubscriptions(ws2);
51014
+ }
51015
+ }
51016
+ handleWsUnsubscribe(ws2, msg) {
51017
+ if (msg.topic === "session.chat_tail") {
51018
+ this.wsSubscriptions.get(ws2)?.delete(msg.key);
51019
+ return;
51020
+ }
51021
+ if (msg.topic === "machine.runtime") {
51022
+ this.wsMachineRuntimeSubscriptions.get(ws2)?.delete(msg.key);
51023
+ return;
51024
+ }
51025
+ if (msg.topic === "session_host.diagnostics") {
51026
+ this.wsSessionHostDiagnosticsSubscriptions.get(ws2)?.delete(msg.key);
51027
+ return;
51028
+ }
51029
+ if (msg.topic === "session.modal") {
51030
+ this.wsSessionModalSubscriptions.get(ws2)?.delete(msg.key);
51031
+ return;
51032
+ }
51033
+ if (msg.topic === "daemon.metadata") {
51034
+ this.wsDaemonMetadataSubscriptions.get(ws2)?.delete(msg.key);
51035
+ }
51036
+ }
51037
+ async buildChatTailUpdate(request, state, key) {
51038
+ const result = await this.executeCommand("read_chat", {
51039
+ targetSessionId: request.targetSessionId,
51040
+ ...request.historySessionId ? { historySessionId: request.historySessionId } : {},
51041
+ knownMessageCount: state.cursor.knownMessageCount,
51042
+ lastMessageSignature: state.cursor.lastMessageSignature,
51043
+ ...state.cursor.tailLimit > 0 ? { tailLimit: state.cursor.tailLimit } : {}
50504
51044
  });
51045
+ if (!result?.success || result.syncMode === "noop") {
51046
+ if (result?.success) {
51047
+ state.cursor = {
51048
+ knownMessageCount: Math.max(0, Number(result.totalMessages || state.cursor.knownMessageCount)),
51049
+ lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : state.cursor.lastMessageSignature,
51050
+ tailLimit: state.cursor.tailLimit
51051
+ };
51052
+ }
51053
+ return null;
51054
+ }
51055
+ state.seq += 1;
51056
+ const syncMode = result.syncMode === "append" || result.syncMode === "replace_tail" || result.syncMode === "noop" || result.syncMode === "full" ? result.syncMode : "full";
51057
+ state.cursor = {
51058
+ knownMessageCount: Math.max(0, Number(result.totalMessages || 0)),
51059
+ lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : "",
51060
+ tailLimit: state.cursor.tailLimit
51061
+ };
51062
+ const activeModal = result.activeModal && typeof result.activeModal === "object" && typeof result.activeModal.message === "string" && Array.isArray(result.activeModal.buttons) ? {
51063
+ message: result.activeModal.message,
51064
+ buttons: result.activeModal.buttons.filter((button) => typeof button === "string")
51065
+ } : null;
51066
+ const deliverySignature = buildChatTailDeliverySignature({
51067
+ sessionId: request.targetSessionId,
51068
+ ...request.historySessionId ? { historySessionId: request.historySessionId } : {},
51069
+ messages: Array.isArray(result.messages) ? result.messages : [],
51070
+ status: typeof result.status === "string" ? result.status : "idle",
51071
+ ...typeof result.title === "string" ? { title: result.title } : {},
51072
+ ...activeModal ? { activeModal } : {},
51073
+ syncMode,
51074
+ replaceFrom: Number(result.replaceFrom || 0),
51075
+ totalMessages: Number(result.totalMessages || 0),
51076
+ lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
51077
+ });
51078
+ if (deliverySignature === state.lastDeliveredSignature) {
51079
+ return null;
51080
+ }
51081
+ state.lastDeliveredSignature = deliverySignature;
51082
+ return {
51083
+ topic: "session.chat_tail",
51084
+ key,
51085
+ sessionId: request.targetSessionId,
51086
+ ...request.historySessionId ? { historySessionId: request.historySessionId } : {},
51087
+ seq: state.seq,
51088
+ timestamp: Date.now(),
51089
+ messages: Array.isArray(result.messages) ? result.messages : [],
51090
+ status: typeof result.status === "string" ? result.status : "idle",
51091
+ ...typeof result.title === "string" ? { title: result.title } : {},
51092
+ ...activeModal ? { activeModal } : {},
51093
+ syncMode,
51094
+ replaceFrom: Number(result.replaceFrom || 0),
51095
+ totalMessages: Number(result.totalMessages || 0),
51096
+ lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
51097
+ };
51098
+ }
51099
+ getHotChatSessionIdsForWsFlush() {
51100
+ const snapshot = this.buildSharedSnapshot("live");
51101
+ const active = new Set(
51102
+ snapshot.sessions.filter((session) => ACTIVE_CHAT_POLL_STATUSES.has(String(session.status || "").toLowerCase())).map((session) => session.id)
51103
+ );
51104
+ const finalizing = new Set(
51105
+ Array.from(this.hotWsChatSessionIds).filter((sessionId) => !active.has(sessionId))
51106
+ );
51107
+ this.hotWsChatSessionIds = active;
51108
+ return { active, finalizing };
51109
+ }
51110
+ async flushWsChatSubscriptions(targetWs, options = {}) {
51111
+ if (this.wsChatFlushInFlight) {
51112
+ const nextOnlyActive = options.onlyActive === true;
51113
+ const pending = this.pendingWsChatFlush;
51114
+ this.pendingWsChatFlush = {
51115
+ targetWs: pending?.targetWs === void 0 || targetWs === void 0 ? void 0 : targetWs,
51116
+ onlyActive: pending ? pending.onlyActive && nextOnlyActive : nextOnlyActive
51117
+ };
51118
+ return;
51119
+ }
51120
+ this.wsChatFlushInFlight = true;
51121
+ try {
51122
+ const targets = targetWs ? [targetWs] : Array.from(this.clients);
51123
+ const hotSessionIds = options.onlyActive ? this.getHotChatSessionIdsForWsFlush() : null;
51124
+ for (const ws2 of targets) {
51125
+ if (ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51126
+ const subs = this.wsSubscriptions.get(ws2);
51127
+ if (!subs || subs.size === 0) continue;
51128
+ for (const [key, sub] of subs.entries()) {
51129
+ const targetSessionId = sub.request.params.targetSessionId;
51130
+ if (hotSessionIds && !hotSessionIds.active.has(targetSessionId) && !hotSessionIds.finalizing.has(targetSessionId)) {
51131
+ continue;
51132
+ }
51133
+ const update = await this.buildChatTailUpdate(sub.request.params, sub, key);
51134
+ if (!update || ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51135
+ ws2.send(JSON.stringify({ type: "topic_update", update }));
51136
+ }
51137
+ }
51138
+ } finally {
51139
+ this.wsChatFlushInFlight = false;
51140
+ if (this.pendingWsChatFlush) {
51141
+ const pending = this.pendingWsChatFlush;
51142
+ this.pendingWsChatFlush = null;
51143
+ void this.flushWsChatSubscriptions(pending.targetWs, { onlyActive: pending.onlyActive });
51144
+ }
51145
+ }
51146
+ }
51147
+ buildMachineRuntimeUpdate(state, key) {
51148
+ const intervalMs = Math.max(5e3, Number(state.request.params.intervalMs || 15e3));
51149
+ const now = Date.now();
51150
+ if (state.lastSentAt > 0 && now - state.lastSentAt < intervalMs) {
51151
+ return null;
51152
+ }
51153
+ state.seq += 1;
51154
+ state.lastSentAt = now;
51155
+ return {
51156
+ topic: "machine.runtime",
51157
+ key,
51158
+ machine: (0, import_daemon_core2.buildMachineInfo)("full"),
51159
+ seq: state.seq,
51160
+ timestamp: now
51161
+ };
51162
+ }
51163
+ async flushWsMachineRuntimeSubscriptions(targetWs) {
51164
+ const targets = targetWs ? [targetWs] : Array.from(this.clients);
51165
+ for (const ws2 of targets) {
51166
+ if (ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51167
+ const subs = this.wsMachineRuntimeSubscriptions.get(ws2);
51168
+ if (!subs || subs.size === 0) continue;
51169
+ for (const [key, sub] of subs.entries()) {
51170
+ const update = this.buildMachineRuntimeUpdate(sub, key);
51171
+ if (!update || ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51172
+ ws2.send(JSON.stringify({ type: "topic_update", update }));
51173
+ }
51174
+ }
51175
+ }
51176
+ async buildSessionHostDiagnosticsUpdate(state, key) {
51177
+ if (!this.sessionHostControl) return null;
51178
+ const intervalMs = Math.max(5e3, Number(state.request.params.intervalMs || 1e4));
51179
+ const now = Date.now();
51180
+ if (state.lastSentAt > 0 && now - state.lastSentAt < intervalMs) {
51181
+ return null;
51182
+ }
51183
+ const diagnostics = await this.sessionHostControl.getDiagnostics({
51184
+ includeSessions: state.request.params.includeSessions !== false,
51185
+ limit: Number(state.request.params.limit) || void 0
51186
+ });
51187
+ state.seq += 1;
51188
+ state.lastSentAt = now;
51189
+ return {
51190
+ topic: "session_host.diagnostics",
51191
+ key,
51192
+ diagnostics,
51193
+ seq: state.seq,
51194
+ timestamp: now
51195
+ };
51196
+ }
51197
+ async flushWsSessionHostDiagnosticsSubscriptions(targetWs) {
51198
+ const targets = targetWs ? [targetWs] : Array.from(this.clients);
51199
+ for (const ws2 of targets) {
51200
+ if (ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51201
+ const subs = this.wsSessionHostDiagnosticsSubscriptions.get(ws2);
51202
+ if (!subs || subs.size === 0) continue;
51203
+ for (const [key, sub] of subs.entries()) {
51204
+ const update = await this.buildSessionHostDiagnosticsUpdate(sub, key);
51205
+ if (!update || ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51206
+ ws2.send(JSON.stringify({ type: "topic_update", update }));
51207
+ }
51208
+ }
51209
+ }
51210
+ findProviderStateBySessionId(sessionId) {
51211
+ if (!this.components || !sessionId) return null;
51212
+ const states = this.components.instanceManager.collectAllStates();
51213
+ for (const state of states) {
51214
+ if (state.instanceId === sessionId) return state;
51215
+ if (state.category === "ide") {
51216
+ const child = state.extensions.find((entry) => entry.instanceId === sessionId);
51217
+ if (child) return child;
51218
+ }
51219
+ }
51220
+ return null;
51221
+ }
51222
+ buildSessionModalUpdate(state, key) {
51223
+ const providerState = this.findProviderStateBySessionId(state.request.params.targetSessionId);
51224
+ if (!providerState) return null;
51225
+ const now = Date.now();
51226
+ state.seq += 1;
51227
+ state.lastSentAt = now;
51228
+ const activeModal = providerState.activeChat?.activeModal;
51229
+ const modalButtons = Array.isArray(activeModal?.buttons) ? activeModal.buttons.filter((button) => typeof button === "string") : [];
51230
+ const status = String(providerState.activeChat?.status || providerState.status || "idle");
51231
+ const title = typeof providerState.activeChat?.title === "string" ? providerState.activeChat.title : void 0;
51232
+ const modalMessage = typeof activeModal?.message === "string" ? activeModal.message : void 0;
51233
+ const deliverySignature = buildSessionModalDeliverySignature({
51234
+ sessionId: state.request.params.targetSessionId,
51235
+ status,
51236
+ ...title ? { title } : {},
51237
+ ...modalMessage ? { modalMessage } : {},
51238
+ ...modalButtons.length > 0 ? { modalButtons } : {}
51239
+ });
51240
+ if (deliverySignature === state.lastDeliveredSignature) {
51241
+ return null;
51242
+ }
51243
+ state.lastDeliveredSignature = deliverySignature;
51244
+ return {
51245
+ topic: "session.modal",
51246
+ key,
51247
+ sessionId: state.request.params.targetSessionId,
51248
+ status,
51249
+ ...title ? { title } : {},
51250
+ ...modalMessage ? { modalMessage } : {},
51251
+ ...modalButtons.length > 0 ? { modalButtons } : {},
51252
+ seq: state.seq,
51253
+ timestamp: now
51254
+ };
51255
+ }
51256
+ async flushWsSessionModalSubscriptions(targetWs) {
51257
+ const targets = targetWs ? [targetWs] : Array.from(this.clients);
51258
+ for (const ws2 of targets) {
51259
+ if (ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51260
+ const subs = this.wsSessionModalSubscriptions.get(ws2);
51261
+ if (!subs || subs.size === 0) continue;
51262
+ for (const [key, sub] of subs.entries()) {
51263
+ const update = this.buildSessionModalUpdate(sub, key);
51264
+ if (!update || ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51265
+ ws2.send(JSON.stringify({ type: "topic_update", update }));
51266
+ }
51267
+ }
51268
+ }
51269
+ buildDaemonMetadataUpdate(state, key) {
51270
+ const now = Date.now();
51271
+ state.seq += 1;
51272
+ state.lastSentAt = now;
51273
+ const cfgSnap = (0, import_daemon_core2.loadConfig)();
51274
+ return {
51275
+ topic: "daemon.metadata",
51276
+ key,
51277
+ daemonId: `standalone_${cfgSnap.machineId || "standalone"}`,
51278
+ status: this.buildSharedSnapshot("metadata"),
51279
+ userName: cfgSnap.userName || void 0,
51280
+ seq: state.seq,
51281
+ timestamp: now
51282
+ };
51283
+ }
51284
+ async flushWsDaemonMetadataSubscriptions(targetWs) {
51285
+ const targets = targetWs ? [targetWs] : Array.from(this.clients);
51286
+ for (const ws2 of targets) {
51287
+ if (ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51288
+ const subs = this.wsDaemonMetadataSubscriptions.get(ws2);
51289
+ if (!subs || subs.size === 0) continue;
51290
+ for (const [key, sub] of subs.entries()) {
51291
+ const update = this.buildDaemonMetadataUpdate(sub, key);
51292
+ if (ws2.readyState !== import_ws.WebSocket.OPEN) continue;
51293
+ ws2.send(JSON.stringify({ type: "topic_update", update }));
51294
+ }
51295
+ }
50505
51296
  }
50506
51297
  // ─── Core Logic ───
50507
- buildSharedSnapshot() {
51298
+ buildSharedSnapshot(profile = "full") {
50508
51299
  const cfgSnap = (0, import_daemon_core2.loadConfig)();
50509
51300
  const machineId = cfgSnap.machineId || "mach_unknown";
50510
51301
  const allStates = this.components.instanceManager.collectAllStates();
@@ -50518,7 +51309,7 @@ var StandaloneServer = class {
50518
51309
  })),
50519
51310
  instanceId: `standalone_${machineId}`,
50520
51311
  version: pkgVersion,
50521
- daemonMode: false
51312
+ profile
50522
51313
  });
50523
51314
  }
50524
51315
  async pushWsRuntimeSnapshots(ws2) {
@@ -50546,27 +51337,62 @@ var StandaloneServer = class {
50546
51337
  });
50547
51338
  }
50548
51339
  }
50549
- getStatus(snapshot = this.buildSharedSnapshot()) {
51340
+ getStatus(snapshot = this.buildSharedSnapshot("full")) {
50550
51341
  const cfgSnap = (0, import_daemon_core2.loadConfig)();
51342
+ const machineRuntime = (0, import_daemon_core2.buildMachineInfo)("full");
50551
51343
  return {
50552
51344
  ...snapshot,
50553
51345
  id: snapshot.instanceId,
50554
- daemonMode: false,
50555
51346
  type: "standalone",
50556
51347
  platform: snapshot.machine.platform,
50557
51348
  hostname: snapshot.machine.hostname,
50558
51349
  userName: cfgSnap.userName || void 0,
50559
51350
  system: {
50560
- cpus: snapshot.machine.cpus,
50561
- totalMem: snapshot.machine.totalMem,
50562
- freeMem: snapshot.machine.freeMem,
50563
- availableMem: snapshot.machine.availableMem,
50564
- loadavg: snapshot.machine.loadavg,
50565
- uptime: snapshot.machine.uptime,
50566
- arch: snapshot.machine.arch
51351
+ cpus: snapshot.machine.cpus ?? machineRuntime.cpus ?? 0,
51352
+ totalMem: snapshot.machine.totalMem ?? machineRuntime.totalMem ?? 0,
51353
+ freeMem: snapshot.machine.freeMem ?? machineRuntime.freeMem ?? 0,
51354
+ availableMem: snapshot.machine.availableMem ?? machineRuntime.availableMem ?? 0,
51355
+ loadavg: snapshot.machine.loadavg ?? machineRuntime.loadavg ?? [],
51356
+ uptime: snapshot.machine.uptime ?? machineRuntime.uptime ?? 0,
51357
+ arch: snapshot.machine.arch ?? machineRuntime.arch ?? os5.arch()
50567
51358
  }
50568
51359
  };
50569
51360
  }
51361
+ getWsStatus(snapshot = this.buildSharedSnapshot("live")) {
51362
+ return {
51363
+ instanceId: snapshot.instanceId,
51364
+ machine: snapshot.machine,
51365
+ timestamp: snapshot.timestamp,
51366
+ sessions: snapshot.sessions,
51367
+ terminalBackend: snapshot.terminalBackend
51368
+ };
51369
+ }
51370
+ buildWsStatusSignature(status) {
51371
+ return JSON.stringify({
51372
+ instanceId: status.instanceId,
51373
+ machine: {
51374
+ hostname: status.machine.hostname,
51375
+ platform: status.machine.platform
51376
+ },
51377
+ sessions: status.sessions.map((session) => ({
51378
+ id: session.id,
51379
+ parentId: session.parentId,
51380
+ providerType: session.providerType,
51381
+ kind: session.kind,
51382
+ transport: session.transport,
51383
+ status: session.status,
51384
+ title: session.title,
51385
+ cdpConnected: session.cdpConnected,
51386
+ currentModel: session.currentModel,
51387
+ currentPlan: session.currentPlan,
51388
+ currentAutoApprove: session.currentAutoApprove,
51389
+ lastSeenAt: session.lastSeenAt,
51390
+ unread: session.unread,
51391
+ inboxBucket: session.inboxBucket,
51392
+ surfaceHidden: session.surfaceHidden
51393
+ }))
51394
+ });
51395
+ }
50570
51396
  normalizeCommandEnvelope(input) {
50571
51397
  const body = input && typeof input === "object" ? input : {};
50572
51398
  const type = typeof body.type === "string" && body.type.trim() ? body.type.trim() : typeof body.commandType === "string" && body.commandType.trim() ? body.commandType.trim() : typeof body.command === "string" && body.command.trim() ? body.command.trim() : "";
@@ -50588,6 +51414,11 @@ var StandaloneServer = class {
50588
51414
  }
50589
51415
  const result = await this.components.router.execute(type, args, "standalone");
50590
51416
  if (type.startsWith("workspace_") || type.startsWith("session_host_")) this.scheduleBroadcastStatus();
51417
+ if (type === "get_status_metadata" || type === "set_user_name" || type === "set_machine_nickname" || type.startsWith("workspace_") || type.startsWith("session_host_")) {
51418
+ void this.flushWsDaemonMetadataSubscriptions();
51419
+ }
51420
+ if (type.startsWith("session_host_")) void this.flushWsSessionHostDiagnosticsSubscriptions();
51421
+ if (type === "resolve_action" || type === "send_chat" || type === "read_chat") void this.flushWsSessionModalSubscriptions();
50591
51422
  return result;
50592
51423
  }
50593
51424
  scheduleBroadcastStatus() {
@@ -50607,8 +51438,11 @@ var StandaloneServer = class {
50607
51438
  }
50608
51439
  broadcastStatus() {
50609
51440
  if (this.clients.size === 0) return;
51441
+ const status = this.getWsStatus(this.buildSharedSnapshot("live"));
51442
+ const signature = this.buildWsStatusSignature(status);
51443
+ if (signature === this.lastWsStatusSignature) return;
51444
+ this.lastWsStatusSignature = signature;
50610
51445
  this.lastStatusBroadcastAt = Date.now();
50611
- const status = this.getStatus();
50612
51446
  const msg = JSON.stringify({ type: "status", data: status });
50613
51447
  const cdpCount = [...this.components.cdpManagers.values()].filter((m) => m.isConnected).length;
50614
51448
  import_daemon_core2.LOG.debug("Broadcast", `status \u2192 ${this.clients.size} client(s), ${status.sessions?.length || 0} session(s), ${cdpCount} CDP`);
@@ -50648,6 +51482,12 @@ var StandaloneServer = class {
50648
51482
  }
50649
51483
  }
50650
51484
  this.clients.clear();
51485
+ this.wsSubscriptions.clear();
51486
+ this.wsMachineRuntimeSubscriptions.clear();
51487
+ this.wsSessionHostDiagnosticsSubscriptions.clear();
51488
+ this.wsSessionModalSubscriptions.clear();
51489
+ this.wsDaemonMetadataSubscriptions.clear();
51490
+ this.lastWsStatusSignature = null;
50651
51491
  if (this.wss) {
50652
51492
  this.wss.close();
50653
51493
  this.wss = null;
@@ -50655,6 +51495,7 @@ var StandaloneServer = class {
50655
51495
  if (this.components) {
50656
51496
  await (0, import_daemon_core2.shutdownDaemonComponents)(this.components);
50657
51497
  }
51498
+ this.sessionHostControl = null;
50658
51499
  if (this.httpServer) {
50659
51500
  this.httpServer.close();
50660
51501
  this.httpServer = null;