@adhdev/daemon-core 0.8.25 → 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.
@@ -16,6 +16,7 @@ export declare class ProviderStreamAdapter implements IAgentStreamAdapter {
16
16
  constructor(provider: ProviderModule);
17
17
  private callScript;
18
18
  private hasScript;
19
+ private parseMaybeJson;
19
20
  private summarizeRaw;
20
21
  private isTransportError;
21
22
  readChat(evaluate: AgentEvaluateFn): Promise<AgentStreamState>;
@@ -10,6 +10,7 @@ import { DaemonCdpManager } from '../cdp/manager.js';
10
10
  import { DaemonCdpInitializer } from '../cdp/initializer.js';
11
11
  import { DaemonCommandHandler } from '../commands/handler.js';
12
12
  import { DaemonCommandRouter } from '../commands/router.js';
13
+ import type { SessionHostControlPlane } from '../commands/router.js';
13
14
  import { DaemonCliManager, type CliTransportFactoryParams, type HostedCliRuntimeDescriptor } from '../commands/cli-manager.js';
14
15
  import { DaemonAgentStreamManager } from '../agent-stream/manager.js';
15
16
  import { AgentStreamPoller } from '../agent-stream/poller.js';
@@ -35,6 +36,7 @@ export interface DaemonInitConfig {
35
36
  /** Router transport-specific callbacks */
36
37
  onStatusChange?: () => void;
37
38
  onPostChatCommand?: () => void;
39
+ sessionHostControl?: SessionHostControlPlane | null;
38
40
  getCdpLogFn?: (ideType: string) => (msg: string) => void;
39
41
  /** Additional callback after CDP manager created (transport-specific extras) */
40
42
  onCdpManagerSetup?: (ideType: string, manager: DaemonCdpManager, managerKey: string) => void | Promise<void>;
@@ -20,6 +20,9 @@ export interface PtyRuntimeMetadata {
20
20
  workspaceLabel?: string;
21
21
  writeOwner?: PtyRuntimeWriteOwner | null;
22
22
  attachedClients?: PtyRuntimeClientInfo[];
23
+ restoredFromStorage?: boolean;
24
+ recoveryState?: string | null;
25
+ recoveryError?: string | null;
23
26
  }
24
27
  export interface PtyRuntimeTransport {
25
28
  readonly pid: number;
@@ -14,6 +14,28 @@ import { DaemonCliManager } from './cli-manager.js';
14
14
  import type { ProviderLoader } from '../providers/provider-loader.js';
15
15
  import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
16
16
  import { SessionRegistry } from '../sessions/registry.js';
17
+ export interface SessionHostControlPlane {
18
+ getDiagnostics(payload?: {
19
+ includeSessions?: boolean;
20
+ limit?: number;
21
+ }): Promise<any>;
22
+ listSessions(): Promise<any[]>;
23
+ stopSession(sessionId: string): Promise<any>;
24
+ resumeSession(sessionId: string): Promise<any>;
25
+ restartSession(sessionId: string): Promise<any>;
26
+ sendSignal(sessionId: string, signal: string): Promise<any>;
27
+ forceDetachClient(sessionId: string, clientId: string): Promise<any>;
28
+ acquireWrite(payload: {
29
+ sessionId: string;
30
+ clientId: string;
31
+ ownerType: 'agent' | 'user';
32
+ force?: boolean;
33
+ }): Promise<any>;
34
+ releaseWrite(payload: {
35
+ sessionId: string;
36
+ clientId: string;
37
+ }): Promise<any>;
38
+ }
17
39
  export interface CommandRouterDeps {
18
40
  commandHandler: DaemonCommandHandler;
19
41
  cliManager: DaemonCliManager;
@@ -37,6 +59,8 @@ export interface CommandRouterDeps {
37
59
  getCdpLogFn?: (ideType: string) => (msg: string) => void;
38
60
  /** Package name for upgrade detection ('adhdev' or '@adhdev/daemon-standalone') */
39
61
  packageName?: string;
62
+ /** Session host control plane */
63
+ sessionHostControl?: SessionHostControlPlane | null;
40
64
  }
41
65
  export interface CommandRouterResult {
42
66
  success: boolean;
package/dist/index.js CHANGED
@@ -5201,6 +5201,7 @@ var ExtensionProviderInstance = class {
5201
5201
  currentStatus = "idle";
5202
5202
  agentStreams = [];
5203
5203
  messages = [];
5204
+ prevMessageHashes = /* @__PURE__ */ new Map();
5204
5205
  activeModal = null;
5205
5206
  currentModel = "";
5206
5207
  currentMode = "";
@@ -5266,7 +5267,7 @@ var ExtensionProviderInstance = class {
5266
5267
  onEvent(event, data) {
5267
5268
  if (event === "stream_update") {
5268
5269
  if (data?.streams) this.agentStreams = data.streams;
5269
- if (data?.messages) this.messages = data.messages;
5270
+ if (data?.messages) this.messages = this.assignReceivedAt(data.messages);
5270
5271
  if (data?.activeModal !== void 0) this.activeModal = data.activeModal;
5271
5272
  if (data?.model) this.currentModel = data.model;
5272
5273
  if (data?.mode) this.currentMode = data.mode;
@@ -5292,6 +5293,7 @@ var ExtensionProviderInstance = class {
5292
5293
  dispose() {
5293
5294
  this.agentStreams = [];
5294
5295
  this.messages = [];
5296
+ this.prevMessageHashes.clear();
5295
5297
  this.monitor.reset();
5296
5298
  this.appliedEffectKeys.clear();
5297
5299
  this.runtimeMessages = [];
@@ -5447,6 +5449,23 @@ var ExtensionProviderInstance = class {
5447
5449
  this.chatId || this.instanceId
5448
5450
  );
5449
5451
  }
5452
+ /**
5453
+ * Assign stable receivedAt to extension messages.
5454
+ * Same pattern as IdeProviderInstance.readChat() prevByHash —
5455
+ * preserves first-seen timestamp across polling cycles.
5456
+ */
5457
+ assignReceivedAt(messages) {
5458
+ const now = Date.now();
5459
+ const nextHashes = /* @__PURE__ */ new Map();
5460
+ for (const msg of messages) {
5461
+ const hash = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
5462
+ const prevTime = this.prevMessageHashes.get(hash);
5463
+ msg.receivedAt = prevTime || now;
5464
+ nextHashes.set(hash, msg.receivedAt);
5465
+ }
5466
+ this.prevMessageHashes = nextHashes;
5467
+ return messages;
5468
+ }
5450
5469
  mergeConversationMessages(messages) {
5451
5470
  if (this.runtimeMessages.length === 0) return messages;
5452
5471
  return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
@@ -5503,6 +5522,7 @@ ${effect.notification.body || ""}`.trim();
5503
5522
  }
5504
5523
  this.agentStreams = [];
5505
5524
  this.messages = [];
5525
+ this.prevMessageHashes.clear();
5506
5526
  this.activeModal = null;
5507
5527
  this.currentModel = "";
5508
5528
  this.currentMode = "";
@@ -6488,16 +6508,28 @@ function trimMessageForStatus(message, stringLimit) {
6488
6508
  if (!message || typeof message !== "object") return message;
6489
6509
  return trimStructuredStrings(message, stringLimit);
6490
6510
  }
6511
+ function normalizeMessageTime(message) {
6512
+ if (!message || typeof message !== "object") return message;
6513
+ const msg = message;
6514
+ if (msg.receivedAt == null) {
6515
+ const fallback = msg.timestamp ?? msg.createdAt;
6516
+ if (fallback != null) {
6517
+ const ts2 = typeof fallback === "string" ? Date.parse(fallback) : Number(fallback);
6518
+ if (Number.isFinite(ts2) && ts2 > 0) msg.receivedAt = ts2;
6519
+ }
6520
+ }
6521
+ return msg;
6522
+ }
6491
6523
  function trimMessagesForStatus(messages) {
6492
6524
  if (!Array.isArray(messages) || messages.length === 0) return [];
6493
6525
  const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
6494
6526
  const kept = [];
6495
6527
  let totalBytes = 0;
6496
6528
  for (let i = recent.length - 1; i >= 0; i -= 1) {
6497
- let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
6529
+ let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
6498
6530
  let size = estimateBytes(normalized);
6499
6531
  if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
6500
- normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
6532
+ normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
6501
6533
  size = estimateBytes(normalized);
6502
6534
  }
6503
6535
  if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
@@ -7120,7 +7152,7 @@ async function handleSendChat(h, args) {
7120
7152
  if (isExtensionTransport(transport)) {
7121
7153
  _log(`Extension: ${provider?.type || "unknown_extension"}`);
7122
7154
  try {
7123
- const evalResult = await h.evaluateProviderScript("sendMessage", { MESSAGE: text }, 3e4);
7155
+ const evalResult = await h.evaluateProviderScript("sendMessage", { message: text }, 3e4);
7124
7156
  if (evalResult?.result) {
7125
7157
  const parsed = parseMaybeJson(evalResult.result);
7126
7158
  if (didProviderConfirmSend(parsed)) {
@@ -7151,7 +7183,7 @@ async function handleSendChat(h, args) {
7151
7183
  return { success: false, error: `CDP for ${managerKey || "unknown"} not connected` };
7152
7184
  }
7153
7185
  _log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
7154
- const sendScript = h.getProviderScript("sendMessage", { MESSAGE: text });
7186
+ const sendScript = h.getProviderScript("sendMessage", { message: text });
7155
7187
  if (sendScript) {
7156
7188
  try {
7157
7189
  const result = await targetCdp.evaluate(sendScript, 3e4);
@@ -8553,9 +8585,26 @@ var DaemonCommandHandler = class {
8553
8585
  if (provider?.scripts) {
8554
8586
  const fn = provider.scripts[scriptName];
8555
8587
  if (typeof fn === "function") {
8556
- const firstVal = params ? Object.values(params)[0] : void 0;
8557
- const script = firstVal ? fn(firstVal) : fn();
8558
- if (script) return script;
8588
+ if (params && Object.keys(params).length > 0) {
8589
+ const firstVal = Object.values(params)[0];
8590
+ if (scriptName === "sendMessage" && typeof firstVal === "string") {
8591
+ const legacyScript = fn(firstVal);
8592
+ if (legacyScript) return legacyScript;
8593
+ }
8594
+ const script = fn(params);
8595
+ if (script) {
8596
+ const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
8597
+ if (!likelyLegacyObjectLeak) return script;
8598
+ }
8599
+ if (firstVal !== void 0) {
8600
+ const legacyScript = fn(firstVal);
8601
+ if (legacyScript) return legacyScript;
8602
+ }
8603
+ if (script) return script;
8604
+ } else {
8605
+ const script = fn();
8606
+ if (script) return script;
8607
+ }
8559
8608
  }
8560
8609
  }
8561
8610
  return null;
@@ -9016,6 +9065,7 @@ var CliProviderInstance = class {
9016
9065
  this.detectStatusTransition();
9017
9066
  });
9018
9067
  await this.adapter.spawn();
9068
+ this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
9019
9069
  if (this.providerSessionId) {
9020
9070
  const restoredHistory = readChatHistory(this.type, 0, 200, this.providerSessionId);
9021
9071
  if (restoredHistory.messages.length > 0) {
@@ -9110,6 +9160,7 @@ var CliProviderInstance = class {
9110
9160
  this.promoteProviderSessionId(parsedProviderSessionId);
9111
9161
  }
9112
9162
  const runtime = this.adapter.getRuntimeMetadata();
9163
+ this.maybeAppendRuntimeRecoveryMessage(runtime);
9113
9164
  const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
9114
9165
  const controlValues = extractProviderControlValues(this.provider.controls, parsedStatus);
9115
9166
  if (controlValues) {
@@ -9436,6 +9487,28 @@ ${effect.notification.body || ""}`.trim();
9436
9487
  const pad = (value) => String(value).padStart(2, "0");
9437
9488
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
9438
9489
  }
9490
+ maybeAppendRuntimeRecoveryMessage(runtime) {
9491
+ if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
9492
+ const recoveryState = String(runtime.recoveryState || "").trim();
9493
+ if (!recoveryState) return;
9494
+ let content = "";
9495
+ if (recoveryState === "auto_resumed") {
9496
+ content = "Session host restored this CLI after restart and reattached it from a saved snapshot.";
9497
+ } else if (recoveryState === "resume_failed") {
9498
+ const errorSuffix = runtime.recoveryError ? ` Resume failed: ${runtime.recoveryError}` : "";
9499
+ content = `Session host found this CLI after restart, but automatic resume failed.${errorSuffix}`;
9500
+ } else if (recoveryState === "host_restart_interrupted") {
9501
+ content = "Session host found this CLI in interrupted state after restart and is attempting to resume it.";
9502
+ } else if (recoveryState === "orphan_snapshot") {
9503
+ content = "Session host restored the last snapshot for this CLI, but the original runtime was not resumed automatically.";
9504
+ } else {
9505
+ content = `Session host restored this CLI after restart (${recoveryState}).`;
9506
+ }
9507
+ this.appendRuntimeSystemMessage(
9508
+ content,
9509
+ `runtime_recovery:${runtime.runtimeId}:${recoveryState}`
9510
+ );
9511
+ }
9439
9512
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
9440
9513
  const normalizedContent = String(content || "").trim();
9441
9514
  if (!normalizedContent) return;
@@ -12724,17 +12797,17 @@ function parseMessageTime(value) {
12724
12797
  function getSessionMessageUpdatedAt(session) {
12725
12798
  const lastMessage = session.activeChat?.messages?.at?.(-1);
12726
12799
  if (!lastMessage) return 0;
12727
- return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
12800
+ return parseMessageTime(lastMessage.receivedAt) || 0;
12728
12801
  }
12729
12802
  function getSessionCompletionMarker(session) {
12730
12803
  const lastMessage = session.activeChat?.messages?.at?.(-1);
12731
12804
  if (!lastMessage) return "";
12732
12805
  const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
12733
- if (role === "user" || role === "human") return "";
12806
+ if (role === "user" || role === "human" || role === "system") return "";
12734
12807
  if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
12735
12808
  if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
12736
12809
  if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
12737
- const timestamp = parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt);
12810
+ const timestamp = parseMessageTime(lastMessage.receivedAt);
12738
12811
  return timestamp > 0 ? `ts:${timestamp}` : "";
12739
12812
  }
12740
12813
  function getSessionLastUsedAt(session) {
@@ -12751,7 +12824,7 @@ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRo
12751
12824
  if (status === "generating" || status === "starting") {
12752
12825
  return { unread: false, inboxBucket: "working" };
12753
12826
  }
12754
- const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
12827
+ const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human" && lastRole !== "system";
12755
12828
  return { unread, inboxBucket: unread ? "task_complete" : "idle" };
12756
12829
  }
12757
12830
  function buildRecentLaunches(recentActivity) {
@@ -13036,6 +13109,25 @@ var CHAT_COMMANDS = [
13036
13109
  "change_model"
13037
13110
  ];
13038
13111
  var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
13112
+ function toHostedCliRuntimeDescriptor(record) {
13113
+ if (!record || typeof record !== "object") return null;
13114
+ const runtimeId = typeof record.sessionId === "string" ? record.sessionId : "";
13115
+ const cliType = typeof record.providerType === "string" ? record.providerType : "";
13116
+ const workspace = typeof record.workspace === "string" ? record.workspace : "";
13117
+ if (!runtimeId || !cliType || !workspace) return null;
13118
+ return {
13119
+ runtimeId,
13120
+ runtimeKey: typeof record.runtimeKey === "string" ? record.runtimeKey : void 0,
13121
+ displayName: typeof record.displayName === "string" ? record.displayName : void 0,
13122
+ workspaceLabel: typeof record.workspaceLabel === "string" ? record.workspaceLabel : void 0,
13123
+ lifecycle: typeof record.lifecycle === "string" ? record.lifecycle : void 0,
13124
+ recoveryState: typeof record.meta?.runtimeRecoveryState === "string" ? String(record.meta.runtimeRecoveryState) : null,
13125
+ cliType,
13126
+ workspace,
13127
+ cliArgs: Array.isArray(record.meta?.cliArgs) ? record.meta.cliArgs : [],
13128
+ providerSessionId: typeof record.meta?.providerSessionId === "string" ? String(record.meta.providerSessionId) : void 0
13129
+ };
13130
+ }
13039
13131
  var DaemonCommandRouter = class {
13040
13132
  deps;
13041
13133
  constructor(deps) {
@@ -13109,6 +13201,90 @@ var DaemonCommandRouter = class {
13109
13201
  return { success: false, error: e.message };
13110
13202
  }
13111
13203
  }
13204
+ case "session_host_get_diagnostics": {
13205
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13206
+ const diagnostics = await this.deps.sessionHostControl.getDiagnostics({
13207
+ includeSessions: args?.includeSessions !== false,
13208
+ limit: Number(args?.limit) || void 0
13209
+ });
13210
+ return { success: true, diagnostics };
13211
+ }
13212
+ case "session_host_list_sessions": {
13213
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13214
+ const sessions = await this.deps.sessionHostControl.listSessions();
13215
+ return { success: true, sessions };
13216
+ }
13217
+ case "session_host_stop_session": {
13218
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13219
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
13220
+ if (!sessionId) return { success: false, error: "sessionId required" };
13221
+ const record = await this.deps.sessionHostControl.stopSession(sessionId);
13222
+ return { success: true, record };
13223
+ }
13224
+ case "session_host_resume_session": {
13225
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13226
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
13227
+ if (!sessionId) return { success: false, error: "sessionId required" };
13228
+ const record = await this.deps.sessionHostControl.resumeSession(sessionId);
13229
+ const hosted = toHostedCliRuntimeDescriptor(record);
13230
+ if (hosted) {
13231
+ await this.deps.cliManager.restoreHostedSessions([hosted]);
13232
+ }
13233
+ return { success: true, record };
13234
+ }
13235
+ case "session_host_restart_session": {
13236
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13237
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
13238
+ if (!sessionId) return { success: false, error: "sessionId required" };
13239
+ const record = await this.deps.sessionHostControl.restartSession(sessionId);
13240
+ const hosted = toHostedCliRuntimeDescriptor(record);
13241
+ if (hosted) {
13242
+ await this.deps.cliManager.restoreHostedSessions([hosted]);
13243
+ }
13244
+ return { success: true, record };
13245
+ }
13246
+ case "session_host_send_signal": {
13247
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13248
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
13249
+ const signal = typeof args?.signal === "string" ? args.signal : "";
13250
+ if (!sessionId) return { success: false, error: "sessionId required" };
13251
+ if (!signal) return { success: false, error: "signal required" };
13252
+ const record = await this.deps.sessionHostControl.sendSignal(sessionId, signal);
13253
+ return { success: true, record };
13254
+ }
13255
+ case "session_host_force_detach_client": {
13256
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13257
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
13258
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
13259
+ if (!sessionId) return { success: false, error: "sessionId required" };
13260
+ if (!clientId) return { success: false, error: "clientId required" };
13261
+ const record = await this.deps.sessionHostControl.forceDetachClient(sessionId, clientId);
13262
+ return { success: true, record };
13263
+ }
13264
+ case "session_host_acquire_write": {
13265
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13266
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
13267
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
13268
+ const ownerType = args?.ownerType === "agent" ? "agent" : "user";
13269
+ if (!sessionId) return { success: false, error: "sessionId required" };
13270
+ if (!clientId) return { success: false, error: "clientId required" };
13271
+ const record = await this.deps.sessionHostControl.acquireWrite({
13272
+ sessionId,
13273
+ clientId,
13274
+ ownerType,
13275
+ force: args?.force !== false
13276
+ });
13277
+ return { success: true, record };
13278
+ }
13279
+ case "session_host_release_write": {
13280
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
13281
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
13282
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
13283
+ if (!sessionId) return { success: false, error: "sessionId required" };
13284
+ if (!clientId) return { success: false, error: "clientId required" };
13285
+ const record = await this.deps.sessionHostControl.releaseWrite({ sessionId, clientId });
13286
+ return { success: true, record };
13287
+ }
13112
13288
  case "list_saved_sessions": {
13113
13289
  const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : typeof args?.agentType === "string" ? args.agentType.trim() : "";
13114
13290
  const kind = args?.kind === "acp" ? "acp" : "cli";
@@ -13637,6 +13813,14 @@ var ProviderStreamAdapter = class {
13637
13813
  hasScript(name) {
13638
13814
  return typeof this.provider.scripts?.[name] === "function";
13639
13815
  }
13816
+ parseMaybeJson(raw) {
13817
+ if (typeof raw !== "string") return raw;
13818
+ try {
13819
+ return JSON.parse(raw);
13820
+ } catch {
13821
+ return raw;
13822
+ }
13823
+ }
13640
13824
  summarizeRaw(raw) {
13641
13825
  try {
13642
13826
  if (typeof raw === "string") return raw.replace(/\s+/g, " ").trim().slice(0, 240);
@@ -13697,12 +13881,30 @@ var ProviderStreamAdapter = class {
13697
13881
  }
13698
13882
  }
13699
13883
  async sendMessage(evaluate, text) {
13700
- const script = this.callScript("sendMessage", text);
13884
+ const params = { message: text };
13885
+ const script = this.callScript("sendMessage", params) || this.callScript("sendMessage", text);
13701
13886
  if (!script) throw new Error(`[${this.agentName}] sendMessage script not available`);
13702
13887
  const result = await evaluate(script);
13703
13888
  if (result && typeof result === "string" && result.startsWith("error:")) {
13704
13889
  throw new Error(`[${this.agentName}] sendMessage failed: ${result}`);
13705
13890
  }
13891
+ const parsed = this.parseMaybeJson(result);
13892
+ if (parsed === true) return;
13893
+ if (typeof parsed === "string") {
13894
+ const normalized = parsed.trim().toLowerCase();
13895
+ if (normalized === "ok" || normalized === "sent" || normalized === "success" || normalized === "true") {
13896
+ return;
13897
+ }
13898
+ }
13899
+ if (parsed && typeof parsed === "object") {
13900
+ if (parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true) {
13901
+ return;
13902
+ }
13903
+ if (typeof parsed.error === "string" && parsed.error.trim()) {
13904
+ throw new Error(`[${this.agentName}] sendMessage failed: ${parsed.error}`);
13905
+ }
13906
+ }
13907
+ throw new Error(`[${this.agentName}] sendMessage was not confirmed`);
13706
13908
  }
13707
13909
  async resolveAction(evaluate, action, button) {
13708
13910
  const script = this.callScript("resolveAction", { action, button });
@@ -19953,6 +20155,7 @@ var SessionHostRuntimeTransport = class {
19953
20155
  }
19954
20156
  }
19955
20157
  handleEvent(event) {
20158
+ if (!("sessionId" in event)) return;
19956
20159
  if (event.sessionId !== this.options.runtimeId) return;
19957
20160
  if ((event.type === "session_started" || event.type === "session_resumed") && typeof event.pid === "number") {
19958
20161
  this.currentPid = event.pid;
@@ -20028,7 +20231,10 @@ var SessionHostRuntimeTransport = class {
20028
20231
  clientId: client.clientId,
20029
20232
  type: client.type,
20030
20233
  readOnly: client.readOnly
20031
- }))
20234
+ })),
20235
+ restoredFromStorage: record.meta?.restoredFromStorage === true,
20236
+ recoveryState: typeof record.meta?.runtimeRecoveryState === "string" ? String(record.meta.runtimeRecoveryState) : null,
20237
+ recoveryError: typeof record.meta?.runtimeRecoveryError === "string" ? String(record.meta.runtimeRecoveryError) : null
20032
20238
  };
20033
20239
  }
20034
20240
  enqueue(action) {
@@ -20472,6 +20678,7 @@ async function initDaemonComponents(config) {
20472
20678
  onIdeConnected: () => poller?.start(),
20473
20679
  onStatusChange: config.onStatusChange,
20474
20680
  onPostChatCommand: config.onPostChatCommand,
20681
+ sessionHostControl: config.sessionHostControl,
20475
20682
  getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
20476
20683
  });
20477
20684
  poller = new AgentStreamPoller({