@adhdev/daemon-core 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/agent-stream/provider-adapter.d.ts +1 -0
- package/dist/boot/daemon-lifecycle.d.ts +2 -0
- package/dist/cli-adapters/pty-transport.d.ts +3 -0
- package/dist/commands/router.d.ts +24 -0
- package/dist/index.js +309 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +309 -19
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/dist/providers/extension-provider-instance.d.ts +7 -0
- package/dist/sessions/reconcile.d.ts +22 -0
- package/dist/status/normalize.js +14 -2
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +14 -2
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/snapshot.d.ts +0 -2
- package/node_modules/@adhdev/session-host-core/dist/index.d.mts +72 -1
- package/node_modules/@adhdev/session-host-core/dist/index.d.ts +72 -1
- package/node_modules/@adhdev/session-host-core/dist/index.js.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/agent-stream/poller.ts +4 -0
- package/src/agent-stream/provider-adapter.ts +30 -1
- package/src/boot/daemon-lifecycle.ts +3 -0
- package/src/cli-adapters/pty-transport.ts +3 -0
- package/src/cli-adapters/session-host-transport.ts +8 -0
- package/src/commands/chat-commands.ts +2 -2
- package/src/commands/handler.ts +79 -13
- package/src/commands/router.ts +132 -0
- package/src/providers/cli-provider-instance.ts +29 -1
- package/src/providers/extension-provider-instance.ts +24 -1
- package/src/sessions/reconcile.ts +85 -0
- package/src/status/normalize.ts +19 -2
- package/src/status/snapshot.ts +6 -13
package/dist/index.mjs
CHANGED
|
@@ -5116,6 +5116,7 @@ var ExtensionProviderInstance = class {
|
|
|
5116
5116
|
currentStatus = "idle";
|
|
5117
5117
|
agentStreams = [];
|
|
5118
5118
|
messages = [];
|
|
5119
|
+
prevMessageHashes = /* @__PURE__ */ new Map();
|
|
5119
5120
|
activeModal = null;
|
|
5120
5121
|
currentModel = "";
|
|
5121
5122
|
currentMode = "";
|
|
@@ -5181,7 +5182,7 @@ var ExtensionProviderInstance = class {
|
|
|
5181
5182
|
onEvent(event, data) {
|
|
5182
5183
|
if (event === "stream_update") {
|
|
5183
5184
|
if (data?.streams) this.agentStreams = data.streams;
|
|
5184
|
-
if (data?.messages) this.messages = data.messages;
|
|
5185
|
+
if (data?.messages) this.messages = this.assignReceivedAt(data.messages);
|
|
5185
5186
|
if (data?.activeModal !== void 0) this.activeModal = data.activeModal;
|
|
5186
5187
|
if (data?.model) this.currentModel = data.model;
|
|
5187
5188
|
if (data?.mode) this.currentMode = data.mode;
|
|
@@ -5207,6 +5208,7 @@ var ExtensionProviderInstance = class {
|
|
|
5207
5208
|
dispose() {
|
|
5208
5209
|
this.agentStreams = [];
|
|
5209
5210
|
this.messages = [];
|
|
5211
|
+
this.prevMessageHashes.clear();
|
|
5210
5212
|
this.monitor.reset();
|
|
5211
5213
|
this.appliedEffectKeys.clear();
|
|
5212
5214
|
this.runtimeMessages = [];
|
|
@@ -5362,6 +5364,23 @@ var ExtensionProviderInstance = class {
|
|
|
5362
5364
|
this.chatId || this.instanceId
|
|
5363
5365
|
);
|
|
5364
5366
|
}
|
|
5367
|
+
/**
|
|
5368
|
+
* Assign stable receivedAt to extension messages.
|
|
5369
|
+
* Same pattern as IdeProviderInstance.readChat() prevByHash —
|
|
5370
|
+
* preserves first-seen timestamp across polling cycles.
|
|
5371
|
+
*/
|
|
5372
|
+
assignReceivedAt(messages) {
|
|
5373
|
+
const now = Date.now();
|
|
5374
|
+
const nextHashes = /* @__PURE__ */ new Map();
|
|
5375
|
+
for (const msg of messages) {
|
|
5376
|
+
const hash = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
|
|
5377
|
+
const prevTime = this.prevMessageHashes.get(hash);
|
|
5378
|
+
msg.receivedAt = prevTime || now;
|
|
5379
|
+
nextHashes.set(hash, msg.receivedAt);
|
|
5380
|
+
}
|
|
5381
|
+
this.prevMessageHashes = nextHashes;
|
|
5382
|
+
return messages;
|
|
5383
|
+
}
|
|
5365
5384
|
mergeConversationMessages(messages) {
|
|
5366
5385
|
if (this.runtimeMessages.length === 0) return messages;
|
|
5367
5386
|
return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
|
|
@@ -5418,6 +5437,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
5418
5437
|
}
|
|
5419
5438
|
this.agentStreams = [];
|
|
5420
5439
|
this.messages = [];
|
|
5440
|
+
this.prevMessageHashes.clear();
|
|
5421
5441
|
this.activeModal = null;
|
|
5422
5442
|
this.currentModel = "";
|
|
5423
5443
|
this.currentMode = "";
|
|
@@ -6403,16 +6423,28 @@ function trimMessageForStatus(message, stringLimit) {
|
|
|
6403
6423
|
if (!message || typeof message !== "object") return message;
|
|
6404
6424
|
return trimStructuredStrings(message, stringLimit);
|
|
6405
6425
|
}
|
|
6426
|
+
function normalizeMessageTime(message) {
|
|
6427
|
+
if (!message || typeof message !== "object") return message;
|
|
6428
|
+
const msg = message;
|
|
6429
|
+
if (msg.receivedAt == null) {
|
|
6430
|
+
const fallback = msg.timestamp ?? msg.createdAt;
|
|
6431
|
+
if (fallback != null) {
|
|
6432
|
+
const ts2 = typeof fallback === "string" ? Date.parse(fallback) : Number(fallback);
|
|
6433
|
+
if (Number.isFinite(ts2) && ts2 > 0) msg.receivedAt = ts2;
|
|
6434
|
+
}
|
|
6435
|
+
}
|
|
6436
|
+
return msg;
|
|
6437
|
+
}
|
|
6406
6438
|
function trimMessagesForStatus(messages) {
|
|
6407
6439
|
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
6408
6440
|
const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
|
|
6409
6441
|
const kept = [];
|
|
6410
6442
|
let totalBytes = 0;
|
|
6411
6443
|
for (let i = recent.length - 1; i >= 0; i -= 1) {
|
|
6412
|
-
let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
|
|
6444
|
+
let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
|
|
6413
6445
|
let size = estimateBytes(normalized);
|
|
6414
6446
|
if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
6415
|
-
normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
|
|
6447
|
+
normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
|
|
6416
6448
|
size = estimateBytes(normalized);
|
|
6417
6449
|
}
|
|
6418
6450
|
if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
@@ -6724,6 +6756,51 @@ function buildSessionEntries(allStates, cdpManagers) {
|
|
|
6724
6756
|
return sessions;
|
|
6725
6757
|
}
|
|
6726
6758
|
|
|
6759
|
+
// src/sessions/reconcile.ts
|
|
6760
|
+
function upsertSessionTarget(sessionRegistry, target) {
|
|
6761
|
+
const existing = sessionRegistry.get(target.sessionId);
|
|
6762
|
+
if (existing && existing.parentSessionId === target.parentSessionId && existing.providerType === target.providerType && existing.transport === target.transport && existing.cdpManagerKey === target.cdpManagerKey && existing.instanceKey === target.instanceKey) {
|
|
6763
|
+
return;
|
|
6764
|
+
}
|
|
6765
|
+
sessionRegistry.register(target);
|
|
6766
|
+
}
|
|
6767
|
+
function reconcileIdeRuntimeSessions(instanceManager, sessionRegistry) {
|
|
6768
|
+
if (!instanceManager || !sessionRegistry) return;
|
|
6769
|
+
for (const instanceKey of instanceManager.listInstanceIds()) {
|
|
6770
|
+
if (!instanceKey.startsWith("ide:")) continue;
|
|
6771
|
+
const ideInstance = instanceManager.getInstance(instanceKey);
|
|
6772
|
+
if (!ideInstance || ideInstance.category !== "ide" || typeof ideInstance.getInstanceId !== "function") {
|
|
6773
|
+
continue;
|
|
6774
|
+
}
|
|
6775
|
+
const managerKey = instanceKey.slice(4);
|
|
6776
|
+
const ideType = typeof ideInstance.type === "string" && ideInstance.type.trim() ? ideInstance.type.trim() : managerKey.split("_")[0];
|
|
6777
|
+
const parentSessionId = ideInstance.getInstanceId();
|
|
6778
|
+
if (!parentSessionId) continue;
|
|
6779
|
+
upsertSessionTarget(sessionRegistry, {
|
|
6780
|
+
sessionId: parentSessionId,
|
|
6781
|
+
parentSessionId: null,
|
|
6782
|
+
providerType: ideType,
|
|
6783
|
+
transport: "cdp-page",
|
|
6784
|
+
cdpManagerKey: managerKey,
|
|
6785
|
+
instanceKey
|
|
6786
|
+
});
|
|
6787
|
+
const extensions = ideInstance.getExtensionInstances?.() || [];
|
|
6788
|
+
for (const ext of extensions) {
|
|
6789
|
+
const extType = typeof ext?.type === "string" ? ext.type.trim() : "";
|
|
6790
|
+
const extSessionId = ext?.getInstanceId?.();
|
|
6791
|
+
if (!extType || !extSessionId) continue;
|
|
6792
|
+
upsertSessionTarget(sessionRegistry, {
|
|
6793
|
+
sessionId: extSessionId,
|
|
6794
|
+
parentSessionId,
|
|
6795
|
+
providerType: extType,
|
|
6796
|
+
transport: "cdp-webview",
|
|
6797
|
+
cdpManagerKey: managerKey,
|
|
6798
|
+
instanceKey
|
|
6799
|
+
});
|
|
6800
|
+
}
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
|
|
6727
6804
|
// src/commands/handler.ts
|
|
6728
6805
|
init_logger();
|
|
6729
6806
|
|
|
@@ -6990,7 +7067,7 @@ async function handleSendChat(h, args) {
|
|
|
6990
7067
|
if (isExtensionTransport(transport)) {
|
|
6991
7068
|
_log(`Extension: ${provider?.type || "unknown_extension"}`);
|
|
6992
7069
|
try {
|
|
6993
|
-
const evalResult = await h.evaluateProviderScript("sendMessage", {
|
|
7070
|
+
const evalResult = await h.evaluateProviderScript("sendMessage", { message: text }, 3e4);
|
|
6994
7071
|
if (evalResult?.result) {
|
|
6995
7072
|
const parsed = parseMaybeJson(evalResult.result);
|
|
6996
7073
|
if (didProviderConfirmSend(parsed)) {
|
|
@@ -7021,7 +7098,7 @@ async function handleSendChat(h, args) {
|
|
|
7021
7098
|
return { success: false, error: `CDP for ${managerKey || "unknown"} not connected` };
|
|
7022
7099
|
}
|
|
7023
7100
|
_log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
|
|
7024
|
-
const sendScript = h.getProviderScript("sendMessage", {
|
|
7101
|
+
const sendScript = h.getProviderScript("sendMessage", { message: text });
|
|
7025
7102
|
if (sendScript) {
|
|
7026
7103
|
try {
|
|
7027
7104
|
const result = await targetCdp.evaluate(sendScript, 3e4);
|
|
@@ -8423,9 +8500,26 @@ var DaemonCommandHandler = class {
|
|
|
8423
8500
|
if (provider?.scripts) {
|
|
8424
8501
|
const fn = provider.scripts[scriptName];
|
|
8425
8502
|
if (typeof fn === "function") {
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8503
|
+
if (params && Object.keys(params).length > 0) {
|
|
8504
|
+
const firstVal = Object.values(params)[0];
|
|
8505
|
+
if (scriptName === "sendMessage" && typeof firstVal === "string") {
|
|
8506
|
+
const legacyScript = fn(firstVal);
|
|
8507
|
+
if (legacyScript) return legacyScript;
|
|
8508
|
+
}
|
|
8509
|
+
const script = fn(params);
|
|
8510
|
+
if (script) {
|
|
8511
|
+
const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
|
|
8512
|
+
if (!likelyLegacyObjectLeak) return script;
|
|
8513
|
+
}
|
|
8514
|
+
if (firstVal !== void 0) {
|
|
8515
|
+
const legacyScript = fn(firstVal);
|
|
8516
|
+
if (legacyScript) return legacyScript;
|
|
8517
|
+
}
|
|
8518
|
+
if (script) return script;
|
|
8519
|
+
} else {
|
|
8520
|
+
const script = fn();
|
|
8521
|
+
if (script) return script;
|
|
8522
|
+
}
|
|
8429
8523
|
}
|
|
8430
8524
|
}
|
|
8431
8525
|
return null;
|
|
@@ -8481,17 +8575,27 @@ var DaemonCommandHandler = class {
|
|
|
8481
8575
|
return key.split("_")[0];
|
|
8482
8576
|
}
|
|
8483
8577
|
resolveRoute(args) {
|
|
8484
|
-
const
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8578
|
+
const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
|
|
8579
|
+
let session = targetSessionId ? this._ctx.sessionRegistry?.get(targetSessionId) : void 0;
|
|
8580
|
+
if (targetSessionId && !session) {
|
|
8581
|
+
reconcileIdeRuntimeSessions(this._ctx.instanceManager, this._ctx.sessionRegistry);
|
|
8582
|
+
session = this._ctx.sessionRegistry?.get(targetSessionId);
|
|
8583
|
+
}
|
|
8584
|
+
const sessionLookupFailed = !!targetSessionId && !session;
|
|
8585
|
+
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
8586
|
+
let providerType;
|
|
8587
|
+
if (!sessionLookupFailed) {
|
|
8588
|
+
providerType = session?.providerType || args?.agentType || args?.providerType || this.inferProviderType(managerKey);
|
|
8589
|
+
}
|
|
8590
|
+
return { session, managerKey, providerType, sessionLookupFailed };
|
|
8488
8591
|
}
|
|
8489
8592
|
/** Extract CDP scope key from target session or explicit ideType */
|
|
8490
|
-
extractIdeType(args) {
|
|
8593
|
+
extractIdeType(args, sessionLookupFailed = false) {
|
|
8491
8594
|
if (args?.targetSessionId) {
|
|
8492
8595
|
const target = this._ctx.sessionRegistry?.get(args.targetSessionId);
|
|
8493
8596
|
if (target?.cdpManagerKey) return target.cdpManagerKey;
|
|
8494
8597
|
if (this._ctx.cdpManagers.has(args.targetSessionId)) return args.targetSessionId;
|
|
8598
|
+
if (sessionLookupFailed) return void 0;
|
|
8495
8599
|
}
|
|
8496
8600
|
if (args?.ideType) {
|
|
8497
8601
|
const target = this._ctx.sessionRegistry?.get(args.ideType);
|
|
@@ -8538,6 +8642,33 @@ var DaemonCommandHandler = class {
|
|
|
8538
8642
|
this._currentRoute = this.resolveRoute(args);
|
|
8539
8643
|
const startedAt = Date.now();
|
|
8540
8644
|
this.logCommandStart(cmd, args);
|
|
8645
|
+
const sessionScopedCommands = /* @__PURE__ */ new Set([
|
|
8646
|
+
"read_chat",
|
|
8647
|
+
"send_chat",
|
|
8648
|
+
"list_chats",
|
|
8649
|
+
"new_chat",
|
|
8650
|
+
"switch_chat",
|
|
8651
|
+
"set_mode",
|
|
8652
|
+
"change_model",
|
|
8653
|
+
"set_thought_level",
|
|
8654
|
+
"resolve_action",
|
|
8655
|
+
"focus_session",
|
|
8656
|
+
"pty_input",
|
|
8657
|
+
"pty_resize",
|
|
8658
|
+
"invoke_provider_script",
|
|
8659
|
+
"list_extension_models",
|
|
8660
|
+
"set_extension_model",
|
|
8661
|
+
"list_extension_modes",
|
|
8662
|
+
"set_extension_mode"
|
|
8663
|
+
]);
|
|
8664
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
|
|
8665
|
+
const result2 = {
|
|
8666
|
+
success: false,
|
|
8667
|
+
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
8668
|
+
};
|
|
8669
|
+
this.logCommandEnd(cmd, result2, startedAt);
|
|
8670
|
+
return result2;
|
|
8671
|
+
}
|
|
8541
8672
|
let result;
|
|
8542
8673
|
if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
|
|
8543
8674
|
const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
|
|
@@ -8849,6 +8980,7 @@ var CliProviderInstance = class {
|
|
|
8849
8980
|
this.detectStatusTransition();
|
|
8850
8981
|
});
|
|
8851
8982
|
await this.adapter.spawn();
|
|
8983
|
+
this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
|
|
8852
8984
|
if (this.providerSessionId) {
|
|
8853
8985
|
const restoredHistory = readChatHistory(this.type, 0, 200, this.providerSessionId);
|
|
8854
8986
|
if (restoredHistory.messages.length > 0) {
|
|
@@ -8943,6 +9075,7 @@ var CliProviderInstance = class {
|
|
|
8943
9075
|
this.promoteProviderSessionId(parsedProviderSessionId);
|
|
8944
9076
|
}
|
|
8945
9077
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
9078
|
+
this.maybeAppendRuntimeRecoveryMessage(runtime);
|
|
8946
9079
|
const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
|
|
8947
9080
|
const controlValues = extractProviderControlValues(this.provider.controls, parsedStatus);
|
|
8948
9081
|
if (controlValues) {
|
|
@@ -9269,6 +9402,28 @@ ${effect.notification.body || ""}`.trim();
|
|
|
9269
9402
|
const pad = (value) => String(value).padStart(2, "0");
|
|
9270
9403
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
9271
9404
|
}
|
|
9405
|
+
maybeAppendRuntimeRecoveryMessage(runtime) {
|
|
9406
|
+
if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
|
|
9407
|
+
const recoveryState = String(runtime.recoveryState || "").trim();
|
|
9408
|
+
if (!recoveryState) return;
|
|
9409
|
+
let content = "";
|
|
9410
|
+
if (recoveryState === "auto_resumed") {
|
|
9411
|
+
content = "Session host restored this CLI after restart and reattached it from a saved snapshot.";
|
|
9412
|
+
} else if (recoveryState === "resume_failed") {
|
|
9413
|
+
const errorSuffix = runtime.recoveryError ? ` Resume failed: ${runtime.recoveryError}` : "";
|
|
9414
|
+
content = `Session host found this CLI after restart, but automatic resume failed.${errorSuffix}`;
|
|
9415
|
+
} else if (recoveryState === "host_restart_interrupted") {
|
|
9416
|
+
content = "Session host found this CLI in interrupted state after restart and is attempting to resume it.";
|
|
9417
|
+
} else if (recoveryState === "orphan_snapshot") {
|
|
9418
|
+
content = "Session host restored the last snapshot for this CLI, but the original runtime was not resumed automatically.";
|
|
9419
|
+
} else {
|
|
9420
|
+
content = `Session host restored this CLI after restart (${recoveryState}).`;
|
|
9421
|
+
}
|
|
9422
|
+
this.appendRuntimeSystemMessage(
|
|
9423
|
+
content,
|
|
9424
|
+
`runtime_recovery:${runtime.runtimeId}:${recoveryState}`
|
|
9425
|
+
);
|
|
9426
|
+
}
|
|
9272
9427
|
appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
|
|
9273
9428
|
const normalizedContent = String(content || "").trim();
|
|
9274
9429
|
if (!normalizedContent) return;
|
|
@@ -12562,17 +12717,17 @@ function parseMessageTime(value) {
|
|
|
12562
12717
|
function getSessionMessageUpdatedAt(session) {
|
|
12563
12718
|
const lastMessage = session.activeChat?.messages?.at?.(-1);
|
|
12564
12719
|
if (!lastMessage) return 0;
|
|
12565
|
-
return parseMessageTime(lastMessage.
|
|
12720
|
+
return parseMessageTime(lastMessage.receivedAt) || 0;
|
|
12566
12721
|
}
|
|
12567
12722
|
function getSessionCompletionMarker(session) {
|
|
12568
12723
|
const lastMessage = session.activeChat?.messages?.at?.(-1);
|
|
12569
12724
|
if (!lastMessage) return "";
|
|
12570
12725
|
const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
|
|
12571
|
-
if (role === "user" || role === "human") return "";
|
|
12726
|
+
if (role === "user" || role === "human" || role === "system") return "";
|
|
12572
12727
|
if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
|
|
12573
12728
|
if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
|
|
12574
12729
|
if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
|
|
12575
|
-
const timestamp = parseMessageTime(lastMessage.
|
|
12730
|
+
const timestamp = parseMessageTime(lastMessage.receivedAt);
|
|
12576
12731
|
return timestamp > 0 ? `ts:${timestamp}` : "";
|
|
12577
12732
|
}
|
|
12578
12733
|
function getSessionLastUsedAt(session) {
|
|
@@ -12589,7 +12744,7 @@ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRo
|
|
|
12589
12744
|
if (status === "generating" || status === "starting") {
|
|
12590
12745
|
return { unread: false, inboxBucket: "working" };
|
|
12591
12746
|
}
|
|
12592
|
-
const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
|
|
12747
|
+
const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human" && lastRole !== "system";
|
|
12593
12748
|
return { unread, inboxBucket: unread ? "task_complete" : "idle" };
|
|
12594
12749
|
}
|
|
12595
12750
|
function buildRecentLaunches(recentActivity) {
|
|
@@ -12874,6 +13029,25 @@ var CHAT_COMMANDS = [
|
|
|
12874
13029
|
"change_model"
|
|
12875
13030
|
];
|
|
12876
13031
|
var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
13032
|
+
function toHostedCliRuntimeDescriptor(record) {
|
|
13033
|
+
if (!record || typeof record !== "object") return null;
|
|
13034
|
+
const runtimeId = typeof record.sessionId === "string" ? record.sessionId : "";
|
|
13035
|
+
const cliType = typeof record.providerType === "string" ? record.providerType : "";
|
|
13036
|
+
const workspace = typeof record.workspace === "string" ? record.workspace : "";
|
|
13037
|
+
if (!runtimeId || !cliType || !workspace) return null;
|
|
13038
|
+
return {
|
|
13039
|
+
runtimeId,
|
|
13040
|
+
runtimeKey: typeof record.runtimeKey === "string" ? record.runtimeKey : void 0,
|
|
13041
|
+
displayName: typeof record.displayName === "string" ? record.displayName : void 0,
|
|
13042
|
+
workspaceLabel: typeof record.workspaceLabel === "string" ? record.workspaceLabel : void 0,
|
|
13043
|
+
lifecycle: typeof record.lifecycle === "string" ? record.lifecycle : void 0,
|
|
13044
|
+
recoveryState: typeof record.meta?.runtimeRecoveryState === "string" ? String(record.meta.runtimeRecoveryState) : null,
|
|
13045
|
+
cliType,
|
|
13046
|
+
workspace,
|
|
13047
|
+
cliArgs: Array.isArray(record.meta?.cliArgs) ? record.meta.cliArgs : [],
|
|
13048
|
+
providerSessionId: typeof record.meta?.providerSessionId === "string" ? String(record.meta.providerSessionId) : void 0
|
|
13049
|
+
};
|
|
13050
|
+
}
|
|
12877
13051
|
var DaemonCommandRouter = class {
|
|
12878
13052
|
deps;
|
|
12879
13053
|
constructor(deps) {
|
|
@@ -12947,6 +13121,90 @@ var DaemonCommandRouter = class {
|
|
|
12947
13121
|
return { success: false, error: e.message };
|
|
12948
13122
|
}
|
|
12949
13123
|
}
|
|
13124
|
+
case "session_host_get_diagnostics": {
|
|
13125
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13126
|
+
const diagnostics = await this.deps.sessionHostControl.getDiagnostics({
|
|
13127
|
+
includeSessions: args?.includeSessions !== false,
|
|
13128
|
+
limit: Number(args?.limit) || void 0
|
|
13129
|
+
});
|
|
13130
|
+
return { success: true, diagnostics };
|
|
13131
|
+
}
|
|
13132
|
+
case "session_host_list_sessions": {
|
|
13133
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13134
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
13135
|
+
return { success: true, sessions };
|
|
13136
|
+
}
|
|
13137
|
+
case "session_host_stop_session": {
|
|
13138
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13139
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13140
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13141
|
+
const record = await this.deps.sessionHostControl.stopSession(sessionId);
|
|
13142
|
+
return { success: true, record };
|
|
13143
|
+
}
|
|
13144
|
+
case "session_host_resume_session": {
|
|
13145
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13146
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13147
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13148
|
+
const record = await this.deps.sessionHostControl.resumeSession(sessionId);
|
|
13149
|
+
const hosted = toHostedCliRuntimeDescriptor(record);
|
|
13150
|
+
if (hosted) {
|
|
13151
|
+
await this.deps.cliManager.restoreHostedSessions([hosted]);
|
|
13152
|
+
}
|
|
13153
|
+
return { success: true, record };
|
|
13154
|
+
}
|
|
13155
|
+
case "session_host_restart_session": {
|
|
13156
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13157
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13158
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13159
|
+
const record = await this.deps.sessionHostControl.restartSession(sessionId);
|
|
13160
|
+
const hosted = toHostedCliRuntimeDescriptor(record);
|
|
13161
|
+
if (hosted) {
|
|
13162
|
+
await this.deps.cliManager.restoreHostedSessions([hosted]);
|
|
13163
|
+
}
|
|
13164
|
+
return { success: true, record };
|
|
13165
|
+
}
|
|
13166
|
+
case "session_host_send_signal": {
|
|
13167
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13168
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13169
|
+
const signal = typeof args?.signal === "string" ? args.signal : "";
|
|
13170
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13171
|
+
if (!signal) return { success: false, error: "signal required" };
|
|
13172
|
+
const record = await this.deps.sessionHostControl.sendSignal(sessionId, signal);
|
|
13173
|
+
return { success: true, record };
|
|
13174
|
+
}
|
|
13175
|
+
case "session_host_force_detach_client": {
|
|
13176
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13177
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13178
|
+
const clientId = typeof args?.clientId === "string" ? args.clientId : "";
|
|
13179
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13180
|
+
if (!clientId) return { success: false, error: "clientId required" };
|
|
13181
|
+
const record = await this.deps.sessionHostControl.forceDetachClient(sessionId, clientId);
|
|
13182
|
+
return { success: true, record };
|
|
13183
|
+
}
|
|
13184
|
+
case "session_host_acquire_write": {
|
|
13185
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13186
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13187
|
+
const clientId = typeof args?.clientId === "string" ? args.clientId : "";
|
|
13188
|
+
const ownerType = args?.ownerType === "agent" ? "agent" : "user";
|
|
13189
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13190
|
+
if (!clientId) return { success: false, error: "clientId required" };
|
|
13191
|
+
const record = await this.deps.sessionHostControl.acquireWrite({
|
|
13192
|
+
sessionId,
|
|
13193
|
+
clientId,
|
|
13194
|
+
ownerType,
|
|
13195
|
+
force: args?.force !== false
|
|
13196
|
+
});
|
|
13197
|
+
return { success: true, record };
|
|
13198
|
+
}
|
|
13199
|
+
case "session_host_release_write": {
|
|
13200
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
13201
|
+
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
13202
|
+
const clientId = typeof args?.clientId === "string" ? args.clientId : "";
|
|
13203
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
13204
|
+
if (!clientId) return { success: false, error: "clientId required" };
|
|
13205
|
+
const record = await this.deps.sessionHostControl.releaseWrite({ sessionId, clientId });
|
|
13206
|
+
return { success: true, record };
|
|
13207
|
+
}
|
|
12950
13208
|
case "list_saved_sessions": {
|
|
12951
13209
|
const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : typeof args?.agentType === "string" ? args.agentType.trim() : "";
|
|
12952
13210
|
const kind = args?.kind === "acp" ? "acp" : "cli";
|
|
@@ -13475,6 +13733,14 @@ var ProviderStreamAdapter = class {
|
|
|
13475
13733
|
hasScript(name) {
|
|
13476
13734
|
return typeof this.provider.scripts?.[name] === "function";
|
|
13477
13735
|
}
|
|
13736
|
+
parseMaybeJson(raw) {
|
|
13737
|
+
if (typeof raw !== "string") return raw;
|
|
13738
|
+
try {
|
|
13739
|
+
return JSON.parse(raw);
|
|
13740
|
+
} catch {
|
|
13741
|
+
return raw;
|
|
13742
|
+
}
|
|
13743
|
+
}
|
|
13478
13744
|
summarizeRaw(raw) {
|
|
13479
13745
|
try {
|
|
13480
13746
|
if (typeof raw === "string") return raw.replace(/\s+/g, " ").trim().slice(0, 240);
|
|
@@ -13535,12 +13801,30 @@ var ProviderStreamAdapter = class {
|
|
|
13535
13801
|
}
|
|
13536
13802
|
}
|
|
13537
13803
|
async sendMessage(evaluate, text) {
|
|
13538
|
-
const
|
|
13804
|
+
const params = { message: text };
|
|
13805
|
+
const script = this.callScript("sendMessage", params) || this.callScript("sendMessage", text);
|
|
13539
13806
|
if (!script) throw new Error(`[${this.agentName}] sendMessage script not available`);
|
|
13540
13807
|
const result = await evaluate(script);
|
|
13541
13808
|
if (result && typeof result === "string" && result.startsWith("error:")) {
|
|
13542
13809
|
throw new Error(`[${this.agentName}] sendMessage failed: ${result}`);
|
|
13543
13810
|
}
|
|
13811
|
+
const parsed = this.parseMaybeJson(result);
|
|
13812
|
+
if (parsed === true) return;
|
|
13813
|
+
if (typeof parsed === "string") {
|
|
13814
|
+
const normalized = parsed.trim().toLowerCase();
|
|
13815
|
+
if (normalized === "ok" || normalized === "sent" || normalized === "success" || normalized === "true") {
|
|
13816
|
+
return;
|
|
13817
|
+
}
|
|
13818
|
+
}
|
|
13819
|
+
if (parsed && typeof parsed === "object") {
|
|
13820
|
+
if (parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true) {
|
|
13821
|
+
return;
|
|
13822
|
+
}
|
|
13823
|
+
if (typeof parsed.error === "string" && parsed.error.trim()) {
|
|
13824
|
+
throw new Error(`[${this.agentName}] sendMessage failed: ${parsed.error}`);
|
|
13825
|
+
}
|
|
13826
|
+
}
|
|
13827
|
+
throw new Error(`[${this.agentName}] sendMessage was not confirmed`);
|
|
13544
13828
|
}
|
|
13545
13829
|
async resolveAction(evaluate, action, button) {
|
|
13546
13830
|
const script = this.callScript("resolveAction", { action, button });
|
|
@@ -13925,6 +14209,7 @@ var AgentStreamPoller = class {
|
|
|
13925
14209
|
sessionRegistry
|
|
13926
14210
|
} = this.deps;
|
|
13927
14211
|
if (!agentStreamManager || cdpManagers.size === 0) return;
|
|
14212
|
+
reconcileIdeRuntimeSessions(instanceManager, sessionRegistry);
|
|
13928
14213
|
for (const [ideType, cdp] of cdpManagers) {
|
|
13929
14214
|
registerExtensionProviders(providerLoader, cdp, ideType);
|
|
13930
14215
|
const ideInstance = instanceManager.getInstance(`ide:${ideType}`);
|
|
@@ -19792,6 +20077,7 @@ var SessionHostRuntimeTransport = class {
|
|
|
19792
20077
|
}
|
|
19793
20078
|
}
|
|
19794
20079
|
handleEvent(event) {
|
|
20080
|
+
if (!("sessionId" in event)) return;
|
|
19795
20081
|
if (event.sessionId !== this.options.runtimeId) return;
|
|
19796
20082
|
if ((event.type === "session_started" || event.type === "session_resumed") && typeof event.pid === "number") {
|
|
19797
20083
|
this.currentPid = event.pid;
|
|
@@ -19867,7 +20153,10 @@ var SessionHostRuntimeTransport = class {
|
|
|
19867
20153
|
clientId: client.clientId,
|
|
19868
20154
|
type: client.type,
|
|
19869
20155
|
readOnly: client.readOnly
|
|
19870
|
-
}))
|
|
20156
|
+
})),
|
|
20157
|
+
restoredFromStorage: record.meta?.restoredFromStorage === true,
|
|
20158
|
+
recoveryState: typeof record.meta?.runtimeRecoveryState === "string" ? String(record.meta.runtimeRecoveryState) : null,
|
|
20159
|
+
recoveryError: typeof record.meta?.runtimeRecoveryError === "string" ? String(record.meta.runtimeRecoveryError) : null
|
|
19871
20160
|
};
|
|
19872
20161
|
}
|
|
19873
20162
|
enqueue(action) {
|
|
@@ -20314,6 +20603,7 @@ async function initDaemonComponents(config) {
|
|
|
20314
20603
|
onIdeConnected: () => poller?.start(),
|
|
20315
20604
|
onStatusChange: config.onStatusChange,
|
|
20316
20605
|
onPostChatCommand: config.onPostChatCommand,
|
|
20606
|
+
sessionHostControl: config.sessionHostControl,
|
|
20317
20607
|
getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
|
|
20318
20608
|
});
|
|
20319
20609
|
poller = new AgentStreamPoller({
|