@adhdev/daemon-standalone 0.8.24 → 0.8.27

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
@@ -28512,18 +28512,18 @@ var require_dist2 = __commonJS({
28512
28512
  };
28513
28513
  }
28514
28514
  });
28515
- var import_session_host_core2;
28515
+ var import_session_host_core3;
28516
28516
  var init_spawn_env = __esm2({
28517
28517
  "src/cli-adapters/spawn-env.ts"() {
28518
28518
  "use strict";
28519
- import_session_host_core2 = require_dist();
28519
+ import_session_host_core3 = require_dist();
28520
28520
  }
28521
28521
  });
28522
28522
  function loadNodePty() {
28523
28523
  if (cachedPty !== void 0) return cachedPty;
28524
28524
  try {
28525
28525
  cachedPty = require("node-pty");
28526
- (0, import_session_host_core2.ensureNodePtySpawnHelperPermissions)();
28526
+ (0, import_session_host_core3.ensureNodePtySpawnHelperPermissions)();
28527
28527
  } catch {
28528
28528
  cachedPty = null;
28529
28529
  }
@@ -28830,7 +28830,7 @@ var require_dist2 = __commonJS({
28830
28830
  init_terminal_screen();
28831
28831
  init_pty_transport();
28832
28832
  init_spawn_env();
28833
- buildCliSpawnEnv = import_session_host_core2.sanitizeSpawnEnv;
28833
+ buildCliSpawnEnv = import_session_host_core3.sanitizeSpawnEnv;
28834
28834
  ProviderCliAdapter = class _ProviderCliAdapter {
28835
28835
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
28836
28836
  this.extraArgs = extraArgs;
@@ -32969,6 +32969,7 @@ ${data.message || ""}`.trim();
32969
32969
  currentStatus = "idle";
32970
32970
  agentStreams = [];
32971
32971
  messages = [];
32972
+ prevMessageHashes = /* @__PURE__ */ new Map();
32972
32973
  activeModal = null;
32973
32974
  currentModel = "";
32974
32975
  currentMode = "";
@@ -33034,7 +33035,7 @@ ${data.message || ""}`.trim();
33034
33035
  onEvent(event, data) {
33035
33036
  if (event === "stream_update") {
33036
33037
  if (data?.streams) this.agentStreams = data.streams;
33037
- if (data?.messages) this.messages = data.messages;
33038
+ if (data?.messages) this.messages = this.assignReceivedAt(data.messages);
33038
33039
  if (data?.activeModal !== void 0) this.activeModal = data.activeModal;
33039
33040
  if (data?.model) this.currentModel = data.model;
33040
33041
  if (data?.mode) this.currentMode = data.mode;
@@ -33060,6 +33061,7 @@ ${data.message || ""}`.trim();
33060
33061
  dispose() {
33061
33062
  this.agentStreams = [];
33062
33063
  this.messages = [];
33064
+ this.prevMessageHashes.clear();
33063
33065
  this.monitor.reset();
33064
33066
  this.appliedEffectKeys.clear();
33065
33067
  this.runtimeMessages = [];
@@ -33215,6 +33217,23 @@ ${data.message || ""}`.trim();
33215
33217
  this.chatId || this.instanceId
33216
33218
  );
33217
33219
  }
33220
+ /**
33221
+ * Assign stable receivedAt to extension messages.
33222
+ * Same pattern as IdeProviderInstance.readChat() prevByHash —
33223
+ * preserves first-seen timestamp across polling cycles.
33224
+ */
33225
+ assignReceivedAt(messages) {
33226
+ const now = Date.now();
33227
+ const nextHashes = /* @__PURE__ */ new Map();
33228
+ for (const msg of messages) {
33229
+ const hash2 = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
33230
+ const prevTime = this.prevMessageHashes.get(hash2);
33231
+ msg.receivedAt = prevTime || now;
33232
+ nextHashes.set(hash2, msg.receivedAt);
33233
+ }
33234
+ this.prevMessageHashes = nextHashes;
33235
+ return messages;
33236
+ }
33218
33237
  mergeConversationMessages(messages) {
33219
33238
  if (this.runtimeMessages.length === 0) return messages;
33220
33239
  return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b2) => {
@@ -33271,6 +33290,7 @@ ${effect.notification.body || ""}`.trim();
33271
33290
  }
33272
33291
  this.agentStreams = [];
33273
33292
  this.messages = [];
33293
+ this.prevMessageHashes.clear();
33274
33294
  this.activeModal = null;
33275
33295
  this.currentModel = "";
33276
33296
  this.currentMode = "";
@@ -34246,16 +34266,28 @@ ${effect.notification.body || ""}`.trim();
34246
34266
  if (!message || typeof message !== "object") return message;
34247
34267
  return trimStructuredStrings(message, stringLimit);
34248
34268
  }
34269
+ function normalizeMessageTime(message) {
34270
+ if (!message || typeof message !== "object") return message;
34271
+ const msg = message;
34272
+ if (msg.receivedAt == null) {
34273
+ const fallback = msg.timestamp ?? msg.createdAt;
34274
+ if (fallback != null) {
34275
+ const ts22 = typeof fallback === "string" ? Date.parse(fallback) : Number(fallback);
34276
+ if (Number.isFinite(ts22) && ts22 > 0) msg.receivedAt = ts22;
34277
+ }
34278
+ }
34279
+ return msg;
34280
+ }
34249
34281
  function trimMessagesForStatus(messages) {
34250
34282
  if (!Array.isArray(messages) || messages.length === 0) return [];
34251
34283
  const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
34252
34284
  const kept = [];
34253
34285
  let totalBytes = 0;
34254
34286
  for (let i = recent.length - 1; i >= 0; i -= 1) {
34255
- let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
34287
+ let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
34256
34288
  let size = estimateBytes(normalized);
34257
34289
  if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
34258
- normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
34290
+ normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
34259
34291
  size = estimateBytes(normalized);
34260
34292
  }
34261
34293
  if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
@@ -34564,6 +34596,49 @@ ${effect.notification.body || ""}`.trim();
34564
34596
  }
34565
34597
  return sessions;
34566
34598
  }
34599
+ function upsertSessionTarget(sessionRegistry, target) {
34600
+ const existing = sessionRegistry.get(target.sessionId);
34601
+ if (existing && existing.parentSessionId === target.parentSessionId && existing.providerType === target.providerType && existing.transport === target.transport && existing.cdpManagerKey === target.cdpManagerKey && existing.instanceKey === target.instanceKey) {
34602
+ return;
34603
+ }
34604
+ sessionRegistry.register(target);
34605
+ }
34606
+ function reconcileIdeRuntimeSessions(instanceManager, sessionRegistry) {
34607
+ if (!instanceManager || !sessionRegistry) return;
34608
+ for (const instanceKey of instanceManager.listInstanceIds()) {
34609
+ if (!instanceKey.startsWith("ide:")) continue;
34610
+ const ideInstance = instanceManager.getInstance(instanceKey);
34611
+ if (!ideInstance || ideInstance.category !== "ide" || typeof ideInstance.getInstanceId !== "function") {
34612
+ continue;
34613
+ }
34614
+ const managerKey = instanceKey.slice(4);
34615
+ const ideType = typeof ideInstance.type === "string" && ideInstance.type.trim() ? ideInstance.type.trim() : managerKey.split("_")[0];
34616
+ const parentSessionId = ideInstance.getInstanceId();
34617
+ if (!parentSessionId) continue;
34618
+ upsertSessionTarget(sessionRegistry, {
34619
+ sessionId: parentSessionId,
34620
+ parentSessionId: null,
34621
+ providerType: ideType,
34622
+ transport: "cdp-page",
34623
+ cdpManagerKey: managerKey,
34624
+ instanceKey
34625
+ });
34626
+ const extensions = ideInstance.getExtensionInstances?.() || [];
34627
+ for (const ext of extensions) {
34628
+ const extType = typeof ext?.type === "string" ? ext.type.trim() : "";
34629
+ const extSessionId = ext?.getInstanceId?.();
34630
+ if (!extType || !extSessionId) continue;
34631
+ upsertSessionTarget(sessionRegistry, {
34632
+ sessionId: extSessionId,
34633
+ parentSessionId,
34634
+ providerType: extType,
34635
+ transport: "cdp-webview",
34636
+ cdpManagerKey: managerKey,
34637
+ instanceKey
34638
+ });
34639
+ }
34640
+ }
34641
+ }
34567
34642
  init_logger();
34568
34643
  init_logger();
34569
34644
  var RECENT_SEND_WINDOW_MS = 1200;
@@ -34827,7 +34902,7 @@ ${effect.notification.body || ""}`.trim();
34827
34902
  if (isExtensionTransport(transport)) {
34828
34903
  _log(`Extension: ${provider?.type || "unknown_extension"}`);
34829
34904
  try {
34830
- const evalResult = await h.evaluateProviderScript("sendMessage", { MESSAGE: text }, 3e4);
34905
+ const evalResult = await h.evaluateProviderScript("sendMessage", { message: text }, 3e4);
34831
34906
  if (evalResult?.result) {
34832
34907
  const parsed = parseMaybeJson(evalResult.result);
34833
34908
  if (didProviderConfirmSend(parsed)) {
@@ -34858,7 +34933,7 @@ ${effect.notification.body || ""}`.trim();
34858
34933
  return { success: false, error: `CDP for ${managerKey || "unknown"} not connected` };
34859
34934
  }
34860
34935
  _log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
34861
- const sendScript = h.getProviderScript("sendMessage", { MESSAGE: text });
34936
+ const sendScript = h.getProviderScript("sendMessage", { message: text });
34862
34937
  if (sendScript) {
34863
34938
  try {
34864
34939
  const result = await targetCdp.evaluate(sendScript, 3e4);
@@ -36252,9 +36327,26 @@ ${effect.notification.body || ""}`.trim();
36252
36327
  if (provider?.scripts) {
36253
36328
  const fn2 = provider.scripts[scriptName];
36254
36329
  if (typeof fn2 === "function") {
36255
- const firstVal = params ? Object.values(params)[0] : void 0;
36256
- const script = firstVal ? fn2(firstVal) : fn2();
36257
- if (script) return script;
36330
+ if (params && Object.keys(params).length > 0) {
36331
+ const firstVal = Object.values(params)[0];
36332
+ if (scriptName === "sendMessage" && typeof firstVal === "string") {
36333
+ const legacyScript = fn2(firstVal);
36334
+ if (legacyScript) return legacyScript;
36335
+ }
36336
+ const script = fn2(params);
36337
+ if (script) {
36338
+ const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
36339
+ if (!likelyLegacyObjectLeak) return script;
36340
+ }
36341
+ if (firstVal !== void 0) {
36342
+ const legacyScript = fn2(firstVal);
36343
+ if (legacyScript) return legacyScript;
36344
+ }
36345
+ if (script) return script;
36346
+ } else {
36347
+ const script = fn2();
36348
+ if (script) return script;
36349
+ }
36258
36350
  }
36259
36351
  }
36260
36352
  return null;
@@ -36310,17 +36402,27 @@ ${effect.notification.body || ""}`.trim();
36310
36402
  return key.split("_")[0];
36311
36403
  }
36312
36404
  resolveRoute(args) {
36313
- const session = this._ctx.sessionRegistry?.get(args?.targetSessionId);
36314
- const managerKey = this.extractIdeType(args);
36315
- const providerType = args?.agentType || args?.providerType || session?.providerType || this.inferProviderType(managerKey);
36316
- return { session, managerKey, providerType };
36405
+ const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
36406
+ let session = targetSessionId ? this._ctx.sessionRegistry?.get(targetSessionId) : void 0;
36407
+ if (targetSessionId && !session) {
36408
+ reconcileIdeRuntimeSessions(this._ctx.instanceManager, this._ctx.sessionRegistry);
36409
+ session = this._ctx.sessionRegistry?.get(targetSessionId);
36410
+ }
36411
+ const sessionLookupFailed = !!targetSessionId && !session;
36412
+ const managerKey = this.extractIdeType(args, sessionLookupFailed);
36413
+ let providerType;
36414
+ if (!sessionLookupFailed) {
36415
+ providerType = session?.providerType || args?.agentType || args?.providerType || this.inferProviderType(managerKey);
36416
+ }
36417
+ return { session, managerKey, providerType, sessionLookupFailed };
36317
36418
  }
36318
36419
  /** Extract CDP scope key from target session or explicit ideType */
36319
- extractIdeType(args) {
36420
+ extractIdeType(args, sessionLookupFailed = false) {
36320
36421
  if (args?.targetSessionId) {
36321
36422
  const target = this._ctx.sessionRegistry?.get(args.targetSessionId);
36322
36423
  if (target?.cdpManagerKey) return target.cdpManagerKey;
36323
36424
  if (this._ctx.cdpManagers.has(args.targetSessionId)) return args.targetSessionId;
36425
+ if (sessionLookupFailed) return void 0;
36324
36426
  }
36325
36427
  if (args?.ideType) {
36326
36428
  const target = this._ctx.sessionRegistry?.get(args.ideType);
@@ -36367,6 +36469,33 @@ ${effect.notification.body || ""}`.trim();
36367
36469
  this._currentRoute = this.resolveRoute(args);
36368
36470
  const startedAt = Date.now();
36369
36471
  this.logCommandStart(cmd, args);
36472
+ const sessionScopedCommands = /* @__PURE__ */ new Set([
36473
+ "read_chat",
36474
+ "send_chat",
36475
+ "list_chats",
36476
+ "new_chat",
36477
+ "switch_chat",
36478
+ "set_mode",
36479
+ "change_model",
36480
+ "set_thought_level",
36481
+ "resolve_action",
36482
+ "focus_session",
36483
+ "pty_input",
36484
+ "pty_resize",
36485
+ "invoke_provider_script",
36486
+ "list_extension_models",
36487
+ "set_extension_model",
36488
+ "list_extension_modes",
36489
+ "set_extension_mode"
36490
+ ]);
36491
+ if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
36492
+ const result2 = {
36493
+ success: false,
36494
+ error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
36495
+ };
36496
+ this.logCommandEnd(cmd, result2, startedAt);
36497
+ return result2;
36498
+ }
36370
36499
  let result;
36371
36500
  if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
36372
36501
  const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
@@ -36674,6 +36803,7 @@ ${effect.notification.body || ""}`.trim();
36674
36803
  this.detectStatusTransition();
36675
36804
  });
36676
36805
  await this.adapter.spawn();
36806
+ this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
36677
36807
  if (this.providerSessionId) {
36678
36808
  const restoredHistory = readChatHistory(this.type, 0, 200, this.providerSessionId);
36679
36809
  if (restoredHistory.messages.length > 0) {
@@ -36768,6 +36898,7 @@ ${effect.notification.body || ""}`.trim();
36768
36898
  this.promoteProviderSessionId(parsedProviderSessionId);
36769
36899
  }
36770
36900
  const runtime = this.adapter.getRuntimeMetadata();
36901
+ this.maybeAppendRuntimeRecoveryMessage(runtime);
36771
36902
  const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
36772
36903
  const controlValues = extractProviderControlValues(this.provider.controls, parsedStatus);
36773
36904
  if (controlValues) {
@@ -37094,6 +37225,28 @@ ${effect.notification.body || ""}`.trim();
37094
37225
  const pad = (value) => String(value).padStart(2, "0");
37095
37226
  return `${date5.getFullYear()}-${pad(date5.getMonth() + 1)}-${pad(date5.getDate())} ${pad(date5.getHours())}:${pad(date5.getMinutes())}:${pad(date5.getSeconds())}`;
37096
37227
  }
37228
+ maybeAppendRuntimeRecoveryMessage(runtime) {
37229
+ if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
37230
+ const recoveryState = String(runtime.recoveryState || "").trim();
37231
+ if (!recoveryState) return;
37232
+ let content = "";
37233
+ if (recoveryState === "auto_resumed") {
37234
+ content = "Session host restored this CLI after restart and reattached it from a saved snapshot.";
37235
+ } else if (recoveryState === "resume_failed") {
37236
+ const errorSuffix = runtime.recoveryError ? ` Resume failed: ${runtime.recoveryError}` : "";
37237
+ content = `Session host found this CLI after restart, but automatic resume failed.${errorSuffix}`;
37238
+ } else if (recoveryState === "host_restart_interrupted") {
37239
+ content = "Session host found this CLI in interrupted state after restart and is attempting to resume it.";
37240
+ } else if (recoveryState === "orphan_snapshot") {
37241
+ content = "Session host restored the last snapshot for this CLI, but the original runtime was not resumed automatically.";
37242
+ } else {
37243
+ content = `Session host restored this CLI after restart (${recoveryState}).`;
37244
+ }
37245
+ this.appendRuntimeSystemMessage(
37246
+ content,
37247
+ `runtime_recovery:${runtime.runtimeId}:${recoveryState}`
37248
+ );
37249
+ }
37097
37250
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
37098
37251
  const normalizedContent = String(content || "").trim();
37099
37252
  if (!normalizedContent) return;
@@ -40360,17 +40513,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
40360
40513
  function getSessionMessageUpdatedAt(session) {
40361
40514
  const lastMessage = session.activeChat?.messages?.at?.(-1);
40362
40515
  if (!lastMessage) return 0;
40363
- return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
40516
+ return parseMessageTime(lastMessage.receivedAt) || 0;
40364
40517
  }
40365
40518
  function getSessionCompletionMarker(session) {
40366
40519
  const lastMessage = session.activeChat?.messages?.at?.(-1);
40367
40520
  if (!lastMessage) return "";
40368
40521
  const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
40369
- if (role === "user" || role === "human") return "";
40522
+ if (role === "user" || role === "human" || role === "system") return "";
40370
40523
  if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
40371
40524
  if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
40372
40525
  if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
40373
- const timestamp = parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt);
40526
+ const timestamp = parseMessageTime(lastMessage.receivedAt);
40374
40527
  return timestamp > 0 ? `ts:${timestamp}` : "";
40375
40528
  }
40376
40529
  function getSessionLastUsedAt(session) {
@@ -40387,7 +40540,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
40387
40540
  if (status === "generating" || status === "starting") {
40388
40541
  return { unread: false, inboxBucket: "working" };
40389
40542
  }
40390
- const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
40543
+ const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human" && lastRole !== "system";
40391
40544
  return { unread, inboxBucket: unread ? "task_complete" : "idle" };
40392
40545
  }
40393
40546
  function buildRecentLaunches(recentActivity) {
@@ -40668,6 +40821,25 @@ Run 'adhdev doctor' for detailed diagnostics.`
40668
40821
  "change_model"
40669
40822
  ];
40670
40823
  var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
40824
+ function toHostedCliRuntimeDescriptor(record2) {
40825
+ if (!record2 || typeof record2 !== "object") return null;
40826
+ const runtimeId = typeof record2.sessionId === "string" ? record2.sessionId : "";
40827
+ const cliType = typeof record2.providerType === "string" ? record2.providerType : "";
40828
+ const workspace = typeof record2.workspace === "string" ? record2.workspace : "";
40829
+ if (!runtimeId || !cliType || !workspace) return null;
40830
+ return {
40831
+ runtimeId,
40832
+ runtimeKey: typeof record2.runtimeKey === "string" ? record2.runtimeKey : void 0,
40833
+ displayName: typeof record2.displayName === "string" ? record2.displayName : void 0,
40834
+ workspaceLabel: typeof record2.workspaceLabel === "string" ? record2.workspaceLabel : void 0,
40835
+ lifecycle: typeof record2.lifecycle === "string" ? record2.lifecycle : void 0,
40836
+ recoveryState: typeof record2.meta?.runtimeRecoveryState === "string" ? String(record2.meta.runtimeRecoveryState) : null,
40837
+ cliType,
40838
+ workspace,
40839
+ cliArgs: Array.isArray(record2.meta?.cliArgs) ? record2.meta.cliArgs : [],
40840
+ providerSessionId: typeof record2.meta?.providerSessionId === "string" ? String(record2.meta.providerSessionId) : void 0
40841
+ };
40842
+ }
40671
40843
  var DaemonCommandRouter = class {
40672
40844
  deps;
40673
40845
  constructor(deps) {
@@ -40741,6 +40913,90 @@ Run 'adhdev doctor' for detailed diagnostics.`
40741
40913
  return { success: false, error: e.message };
40742
40914
  }
40743
40915
  }
40916
+ case "session_host_get_diagnostics": {
40917
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40918
+ const diagnostics = await this.deps.sessionHostControl.getDiagnostics({
40919
+ includeSessions: args?.includeSessions !== false,
40920
+ limit: Number(args?.limit) || void 0
40921
+ });
40922
+ return { success: true, diagnostics };
40923
+ }
40924
+ case "session_host_list_sessions": {
40925
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40926
+ const sessions = await this.deps.sessionHostControl.listSessions();
40927
+ return { success: true, sessions };
40928
+ }
40929
+ case "session_host_stop_session": {
40930
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40931
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
40932
+ if (!sessionId) return { success: false, error: "sessionId required" };
40933
+ const record2 = await this.deps.sessionHostControl.stopSession(sessionId);
40934
+ return { success: true, record: record2 };
40935
+ }
40936
+ case "session_host_resume_session": {
40937
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40938
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
40939
+ if (!sessionId) return { success: false, error: "sessionId required" };
40940
+ const record2 = await this.deps.sessionHostControl.resumeSession(sessionId);
40941
+ const hosted = toHostedCliRuntimeDescriptor(record2);
40942
+ if (hosted) {
40943
+ await this.deps.cliManager.restoreHostedSessions([hosted]);
40944
+ }
40945
+ return { success: true, record: record2 };
40946
+ }
40947
+ case "session_host_restart_session": {
40948
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40949
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
40950
+ if (!sessionId) return { success: false, error: "sessionId required" };
40951
+ const record2 = await this.deps.sessionHostControl.restartSession(sessionId);
40952
+ const hosted = toHostedCliRuntimeDescriptor(record2);
40953
+ if (hosted) {
40954
+ await this.deps.cliManager.restoreHostedSessions([hosted]);
40955
+ }
40956
+ return { success: true, record: record2 };
40957
+ }
40958
+ case "session_host_send_signal": {
40959
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40960
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
40961
+ const signal = typeof args?.signal === "string" ? args.signal : "";
40962
+ if (!sessionId) return { success: false, error: "sessionId required" };
40963
+ if (!signal) return { success: false, error: "signal required" };
40964
+ const record2 = await this.deps.sessionHostControl.sendSignal(sessionId, signal);
40965
+ return { success: true, record: record2 };
40966
+ }
40967
+ case "session_host_force_detach_client": {
40968
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40969
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
40970
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
40971
+ if (!sessionId) return { success: false, error: "sessionId required" };
40972
+ if (!clientId) return { success: false, error: "clientId required" };
40973
+ const record2 = await this.deps.sessionHostControl.forceDetachClient(sessionId, clientId);
40974
+ return { success: true, record: record2 };
40975
+ }
40976
+ case "session_host_acquire_write": {
40977
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40978
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
40979
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
40980
+ const ownerType = args?.ownerType === "agent" ? "agent" : "user";
40981
+ if (!sessionId) return { success: false, error: "sessionId required" };
40982
+ if (!clientId) return { success: false, error: "clientId required" };
40983
+ const record2 = await this.deps.sessionHostControl.acquireWrite({
40984
+ sessionId,
40985
+ clientId,
40986
+ ownerType,
40987
+ force: args?.force !== false
40988
+ });
40989
+ return { success: true, record: record2 };
40990
+ }
40991
+ case "session_host_release_write": {
40992
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
40993
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
40994
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
40995
+ if (!sessionId) return { success: false, error: "sessionId required" };
40996
+ if (!clientId) return { success: false, error: "clientId required" };
40997
+ const record2 = await this.deps.sessionHostControl.releaseWrite({ sessionId, clientId });
40998
+ return { success: true, record: record2 };
40999
+ }
40744
41000
  case "list_saved_sessions": {
40745
41001
  const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : typeof args?.agentType === "string" ? args.agentType.trim() : "";
40746
41002
  const kind = args?.kind === "acp" ? "acp" : "cli";
@@ -41261,6 +41517,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
41261
41517
  hasScript(name) {
41262
41518
  return typeof this.provider.scripts?.[name] === "function";
41263
41519
  }
41520
+ parseMaybeJson(raw) {
41521
+ if (typeof raw !== "string") return raw;
41522
+ try {
41523
+ return JSON.parse(raw);
41524
+ } catch {
41525
+ return raw;
41526
+ }
41527
+ }
41264
41528
  summarizeRaw(raw) {
41265
41529
  try {
41266
41530
  if (typeof raw === "string") return raw.replace(/\s+/g, " ").trim().slice(0, 240);
@@ -41321,12 +41585,30 @@ Run 'adhdev doctor' for detailed diagnostics.`
41321
41585
  }
41322
41586
  }
41323
41587
  async sendMessage(evaluate, text) {
41324
- const script = this.callScript("sendMessage", text);
41588
+ const params = { message: text };
41589
+ const script = this.callScript("sendMessage", params) || this.callScript("sendMessage", text);
41325
41590
  if (!script) throw new Error(`[${this.agentName}] sendMessage script not available`);
41326
41591
  const result = await evaluate(script);
41327
41592
  if (result && typeof result === "string" && result.startsWith("error:")) {
41328
41593
  throw new Error(`[${this.agentName}] sendMessage failed: ${result}`);
41329
41594
  }
41595
+ const parsed = this.parseMaybeJson(result);
41596
+ if (parsed === true) return;
41597
+ if (typeof parsed === "string") {
41598
+ const normalized = parsed.trim().toLowerCase();
41599
+ if (normalized === "ok" || normalized === "sent" || normalized === "success" || normalized === "true") {
41600
+ return;
41601
+ }
41602
+ }
41603
+ if (parsed && typeof parsed === "object") {
41604
+ if (parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true) {
41605
+ return;
41606
+ }
41607
+ if (typeof parsed.error === "string" && parsed.error.trim()) {
41608
+ throw new Error(`[${this.agentName}] sendMessage failed: ${parsed.error}`);
41609
+ }
41610
+ }
41611
+ throw new Error(`[${this.agentName}] sendMessage was not confirmed`);
41330
41612
  }
41331
41613
  async resolveAction(evaluate, action, button) {
41332
41614
  const script = this.callScript("resolveAction", { action, button });
@@ -41707,6 +41989,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
41707
41989
  sessionRegistry
41708
41990
  } = this.deps;
41709
41991
  if (!agentStreamManager || cdpManagers.size === 0) return;
41992
+ reconcileIdeRuntimeSessions(instanceManager, sessionRegistry);
41710
41993
  for (const [ideType, cdp] of cdpManagers) {
41711
41994
  registerExtensionProviders(providerLoader, cdp, ideType);
41712
41995
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
@@ -47548,6 +47831,7 @@ data: ${JSON.stringify(msg.data)}
47548
47831
  }
47549
47832
  }
47550
47833
  handleEvent(event) {
47834
+ if (!("sessionId" in event)) return;
47551
47835
  if (event.sessionId !== this.options.runtimeId) return;
47552
47836
  if ((event.type === "session_started" || event.type === "session_resumed") && typeof event.pid === "number") {
47553
47837
  this.currentPid = event.pid;
@@ -47623,7 +47907,10 @@ data: ${JSON.stringify(msg.data)}
47623
47907
  clientId: client.clientId,
47624
47908
  type: client.type,
47625
47909
  readOnly: client.readOnly
47626
- }))
47910
+ })),
47911
+ restoredFromStorage: record2.meta?.restoredFromStorage === true,
47912
+ recoveryState: typeof record2.meta?.runtimeRecoveryState === "string" ? String(record2.meta.runtimeRecoveryState) : null,
47913
+ recoveryError: typeof record2.meta?.runtimeRecoveryError === "string" ? String(record2.meta.runtimeRecoveryError) : null
47627
47914
  };
47628
47915
  }
47629
47916
  enqueue(action) {
@@ -47659,11 +47946,11 @@ data: ${JSON.stringify(msg.data)}
47659
47946
  });
47660
47947
  }
47661
47948
  };
47662
- var import_session_host_core3 = require_dist();
47949
+ var import_session_host_core32 = require_dist();
47663
47950
  var STARTUP_TIMEOUT_MS = 8e3;
47664
47951
  var STARTUP_POLL_MS = 200;
47665
47952
  async function canConnect(endpoint) {
47666
- const client = new import_session_host_core3.SessionHostClient({ endpoint });
47953
+ const client = new import_session_host_core32.SessionHostClient({ endpoint });
47667
47954
  try {
47668
47955
  await client.connect();
47669
47956
  await client.close();
@@ -47681,14 +47968,14 @@ data: ${JSON.stringify(msg.data)}
47681
47968
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
47682
47969
  }
47683
47970
  async function ensureSessionHostReady2(options) {
47684
- const endpoint = (0, import_session_host_core3.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
47971
+ const endpoint = (0, import_session_host_core32.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
47685
47972
  if (await canConnect(endpoint)) return endpoint;
47686
47973
  options.spawnHost();
47687
47974
  await waitForReady(endpoint, options.timeoutMs);
47688
47975
  return endpoint;
47689
47976
  }
47690
47977
  async function listHostedCliRuntimes2(endpoint) {
47691
- const client = new import_session_host_core3.SessionHostClient({ endpoint });
47978
+ const client = new import_session_host_core32.SessionHostClient({ endpoint });
47692
47979
  try {
47693
47980
  const response = await client.request({
47694
47981
  type: "list_sessions",
@@ -48059,6 +48346,7 @@ data: ${JSON.stringify(msg.data)}
48059
48346
  onIdeConnected: () => poller?.start(),
48060
48347
  onStatusChange: config2.onStatusChange,
48061
48348
  onPostChatCommand: config2.onPostChatCommand,
48349
+ sessionHostControl: config2.sessionHostControl,
48062
48350
  getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG2.forComponent(`CDP:${ideType}`).asLogFn())
48063
48351
  });
48064
48352
  poller = new AgentStreamPoller({
@@ -48433,6 +48721,58 @@ var SessionHostClient = class {
48433
48721
  }
48434
48722
  };
48435
48723
 
48724
+ // src/session-host-control.ts
48725
+ var StandaloneSessionHostControlPlane = class {
48726
+ constructor(getEndpoint) {
48727
+ this.getEndpoint = getEndpoint;
48728
+ }
48729
+ async getDiagnostics(payload = {}) {
48730
+ return this.request("get_host_diagnostics", payload);
48731
+ }
48732
+ async listSessions() {
48733
+ return this.request("list_sessions", {});
48734
+ }
48735
+ async stopSession(sessionId) {
48736
+ return this.request("stop_session", { sessionId });
48737
+ }
48738
+ async resumeSession(sessionId) {
48739
+ return this.request("resume_session", { sessionId });
48740
+ }
48741
+ async restartSession(sessionId) {
48742
+ return this.request("restart_session", { sessionId });
48743
+ }
48744
+ async sendSignal(sessionId, signal) {
48745
+ return this.request("send_signal", { sessionId, signal });
48746
+ }
48747
+ async forceDetachClient(sessionId, clientId) {
48748
+ return this.request("force_detach_client", { sessionId, clientId });
48749
+ }
48750
+ async acquireWrite(payload) {
48751
+ return this.request("acquire_write", payload);
48752
+ }
48753
+ async releaseWrite(payload) {
48754
+ return this.request("release_write", payload);
48755
+ }
48756
+ async request(type, payload) {
48757
+ const endpoint = await this.getEndpoint();
48758
+ const client = new SessionHostClient({ endpoint });
48759
+ try {
48760
+ await client.connect();
48761
+ const response = await client.request({
48762
+ type,
48763
+ payload
48764
+ });
48765
+ if (!response.success) {
48766
+ throw new Error(response.error || `Session host request failed: ${type}`);
48767
+ }
48768
+ return response.result ?? null;
48769
+ } finally {
48770
+ await client.close().catch(() => {
48771
+ });
48772
+ }
48773
+ }
48774
+ };
48775
+
48436
48776
  // ../terminal-mux-control/dist/chunk-7RNMRPVZ.mjs
48437
48777
  var import_os = __toESM(require("os"), 1);
48438
48778
  var import_path = __toESM(require("path"), 1);
@@ -48692,6 +49032,9 @@ var StandaloneServer = class {
48692
49032
  const host = options.host || "127.0.0.1";
48693
49033
  const sessionHostEndpoint = await ensureSessionHostReady();
48694
49034
  this.sessionHostEndpoint = sessionHostEndpoint;
49035
+ const sessionHostControl = new StandaloneSessionHostControlPlane(
49036
+ async () => this.ensureActiveSessionHostEndpoint()
49037
+ );
48695
49038
  this.authToken = options.token || process.env.ADHDEV_TOKEN || null;
48696
49039
  this.components = await (0, import_daemon_core2.initDaemonComponents)({
48697
49040
  cliManagerDeps: {
@@ -48730,6 +49073,7 @@ var StandaloneServer = class {
48730
49073
  listHostedCliRuntimes: async () => listHostedCliRuntimes(sessionHostEndpoint)
48731
49074
  },
48732
49075
  onStatusChange: () => this.scheduleBroadcastStatus(),
49076
+ sessionHostControl,
48733
49077
  onStreamsUpdated: (ideType, streams) => {
48734
49078
  if (!this.components) return;
48735
49079
  (0, import_daemon_core2.forwardAgentStreamsToIdeInstance)(this.components.instanceManager, ideType, streams);
@@ -49068,6 +49412,7 @@ var StandaloneServer = class {
49068
49412
  `);
49069
49413
  }
49070
49414
  const writeEvent = (event) => {
49415
+ if (!("sessionId" in event)) return;
49071
49416
  if (event.sessionId !== sessionId) return;
49072
49417
  if (!this.isCliSession(sessionId)) return;
49073
49418
  res.write(`event: ${event.type}
@@ -49220,7 +49565,7 @@ var StandaloneServer = class {
49220
49565
  return { success: false, error: "command type required" };
49221
49566
  }
49222
49567
  const result = await this.components.router.execute(type, args, "standalone");
49223
- if (type.startsWith("workspace_")) this.scheduleBroadcastStatus();
49568
+ if (type.startsWith("workspace_") || type.startsWith("session_host_")) this.scheduleBroadcastStatus();
49224
49569
  return result;
49225
49570
  }
49226
49571
  scheduleBroadcastStatus() {