adhdev 0.8.34 → 0.8.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +1320 -312
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1210 -299
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -67,6 +67,7 @@ function normalizeConfig(raw) {
|
|
|
67
67
|
const parsed = isPlainObject(raw) ? raw : {};
|
|
68
68
|
return {
|
|
69
69
|
serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
|
|
70
|
+
allowServerApiProxy: asBoolean(parsed.allowServerApiProxy, DEFAULT_CONFIG.allowServerApiProxy ?? false),
|
|
70
71
|
selectedIde: asNullableString(parsed.selectedIde),
|
|
71
72
|
configuredIdes: asStringArray(parsed.configuredIdes),
|
|
72
73
|
installedExtensions: asStringArray(parsed.installedExtensions),
|
|
@@ -215,6 +216,7 @@ var init_config = __esm({
|
|
|
215
216
|
import_crypto = require("crypto");
|
|
216
217
|
DEFAULT_CONFIG = {
|
|
217
218
|
serverUrl: "https://api.adhf.dev",
|
|
219
|
+
allowServerApiProxy: false,
|
|
218
220
|
selectedIde: null,
|
|
219
221
|
configuredIdes: [],
|
|
220
222
|
installedExtensions: [],
|
|
@@ -4500,19 +4502,20 @@ function normalizeMessageTime(message) {
|
|
|
4500
4502
|
}
|
|
4501
4503
|
return msg;
|
|
4502
4504
|
}
|
|
4503
|
-
function trimMessagesForStatus(messages) {
|
|
4505
|
+
function trimMessagesForStatus(messages, options) {
|
|
4506
|
+
if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];
|
|
4504
4507
|
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
4505
|
-
const recent = messages.slice(-
|
|
4508
|
+
const recent = messages.slice(-options.messageLimit);
|
|
4506
4509
|
const kept = [];
|
|
4507
4510
|
let totalBytes = 0;
|
|
4508
4511
|
for (let i = recent.length - 1; i >= 0; i -= 1) {
|
|
4509
|
-
let normalized = normalizeMessageTime(trimMessageForStatus(recent[i],
|
|
4512
|
+
let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));
|
|
4510
4513
|
let size = estimateBytes(normalized);
|
|
4511
|
-
if (size >
|
|
4512
|
-
normalized = normalizeMessageTime(trimMessageForStatus(recent[i],
|
|
4514
|
+
if (size > options.totalBytesLimit) {
|
|
4515
|
+
normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));
|
|
4513
4516
|
size = estimateBytes(normalized);
|
|
4514
4517
|
}
|
|
4515
|
-
if (kept.length > 0 && totalBytes + size >
|
|
4518
|
+
if (kept.length > 0 && totalBytes + size > options.totalBytesLimit) {
|
|
4516
4519
|
continue;
|
|
4517
4520
|
}
|
|
4518
4521
|
kept.push(normalized);
|
|
@@ -4542,22 +4545,26 @@ function isManagedStatusWorking(status) {
|
|
|
4542
4545
|
function isManagedStatusWaiting(status, opts) {
|
|
4543
4546
|
return normalizeManagedStatus(status, opts) === "waiting_approval";
|
|
4544
4547
|
}
|
|
4545
|
-
function normalizeActiveChatData(activeChat) {
|
|
4548
|
+
function normalizeActiveChatData(activeChat, options = FULL_STATUS_ACTIVE_CHAT_OPTIONS) {
|
|
4546
4549
|
if (!activeChat) return activeChat;
|
|
4550
|
+
const resolvedOptions = {
|
|
4551
|
+
...FULL_STATUS_ACTIVE_CHAT_OPTIONS,
|
|
4552
|
+
...options
|
|
4553
|
+
};
|
|
4547
4554
|
return {
|
|
4548
4555
|
...activeChat,
|
|
4549
4556
|
status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
|
|
4550
|
-
messages: trimMessagesForStatus(activeChat.messages),
|
|
4551
|
-
activeModal: activeChat.activeModal ? {
|
|
4557
|
+
messages: trimMessagesForStatus(activeChat.messages, resolvedOptions),
|
|
4558
|
+
activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {
|
|
4552
4559
|
message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
|
|
4553
4560
|
buttons: (activeChat.activeModal.buttons || []).map(
|
|
4554
4561
|
(button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
|
|
4555
4562
|
)
|
|
4556
|
-
} :
|
|
4557
|
-
inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent,
|
|
4563
|
+
} : null,
|
|
4564
|
+
inputContent: resolvedOptions.includeInputContent && activeChat.inputContent ? truncateString(activeChat.inputContent, 2 * 1024) : void 0
|
|
4558
4565
|
};
|
|
4559
4566
|
}
|
|
4560
|
-
var WORKING_STATUSES,
|
|
4567
|
+
var WORKING_STATUSES, FULL_STATUS_ACTIVE_CHAT_OPTIONS, LIVE_STATUS_ACTIVE_CHAT_OPTIONS, STATUS_MODAL_MESSAGE_LIMIT, STATUS_MODAL_BUTTON_LIMIT;
|
|
4561
4568
|
var init_normalize = __esm({
|
|
4562
4569
|
"../../oss/packages/daemon-core/src/status/normalize.ts"() {
|
|
4563
4570
|
"use strict";
|
|
@@ -4569,17 +4576,43 @@ var init_normalize = __esm({
|
|
|
4569
4576
|
"thinking",
|
|
4570
4577
|
"active"
|
|
4571
4578
|
]);
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4579
|
+
FULL_STATUS_ACTIVE_CHAT_OPTIONS = {
|
|
4580
|
+
includeMessages: true,
|
|
4581
|
+
includeInputContent: true,
|
|
4582
|
+
includeActiveModal: true,
|
|
4583
|
+
messageLimit: 60,
|
|
4584
|
+
totalBytesLimit: 96 * 1024,
|
|
4585
|
+
stringLimit: 4 * 1024,
|
|
4586
|
+
fallbackStringLimit: 1024
|
|
4587
|
+
};
|
|
4588
|
+
LIVE_STATUS_ACTIVE_CHAT_OPTIONS = {
|
|
4589
|
+
includeMessages: false,
|
|
4590
|
+
includeInputContent: false,
|
|
4591
|
+
includeActiveModal: false,
|
|
4592
|
+
messageLimit: 0,
|
|
4593
|
+
totalBytesLimit: 0,
|
|
4594
|
+
stringLimit: 512,
|
|
4595
|
+
fallbackStringLimit: 256
|
|
4596
|
+
};
|
|
4577
4597
|
STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
|
|
4578
4598
|
STATUS_MODAL_BUTTON_LIMIT = 120;
|
|
4579
4599
|
}
|
|
4580
4600
|
});
|
|
4581
4601
|
|
|
4582
4602
|
// ../../oss/packages/daemon-core/src/status/builders.ts
|
|
4603
|
+
function getActiveChatOptions(profile) {
|
|
4604
|
+
if (profile === "full") return {};
|
|
4605
|
+
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
4606
|
+
}
|
|
4607
|
+
function shouldIncludeSessionControls(profile) {
|
|
4608
|
+
return profile !== "live";
|
|
4609
|
+
}
|
|
4610
|
+
function shouldIncludeSessionMetadata(profile) {
|
|
4611
|
+
return profile !== "live";
|
|
4612
|
+
}
|
|
4613
|
+
function shouldIncludeRuntimeMetadata(profile) {
|
|
4614
|
+
return profile !== "live";
|
|
4615
|
+
}
|
|
4583
4616
|
function findCdpManager(cdpManagers, key) {
|
|
4584
4617
|
const exact = cdpManagers.get(key);
|
|
4585
4618
|
if (exact) return exact;
|
|
@@ -4645,74 +4678,88 @@ function buildFallbackControls(providerControls, serverModel, serverMode, acpCon
|
|
|
4645
4678
|
}
|
|
4646
4679
|
return controls;
|
|
4647
4680
|
}
|
|
4648
|
-
function buildIdeWorkspaceSession(state, cdpManagers) {
|
|
4649
|
-
const
|
|
4681
|
+
function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
4682
|
+
const profile = options.profile || "full";
|
|
4683
|
+
const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
|
|
4684
|
+
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
4685
|
+
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
4650
4686
|
const title = activeChat?.title || state.name;
|
|
4651
4687
|
return {
|
|
4652
4688
|
id: state.instanceId || state.type,
|
|
4653
4689
|
parentId: null,
|
|
4654
4690
|
providerType: state.type,
|
|
4655
|
-
providerName: state.name,
|
|
4691
|
+
...includeSessionMetadata && { providerName: state.name },
|
|
4656
4692
|
kind: "workspace",
|
|
4657
4693
|
transport: "cdp-page",
|
|
4658
4694
|
status: normalizeManagedStatus(activeChat?.status || state.status, {
|
|
4659
4695
|
activeModal: activeChat?.activeModal || null
|
|
4660
4696
|
}),
|
|
4661
4697
|
title,
|
|
4662
|
-
workspace: state.workspace || null,
|
|
4698
|
+
...includeSessionMetadata && { workspace: state.workspace || null },
|
|
4663
4699
|
activeChat,
|
|
4664
|
-
capabilities: IDE_SESSION_CAPABILITIES,
|
|
4700
|
+
...includeSessionMetadata && { capabilities: IDE_SESSION_CAPABILITIES },
|
|
4665
4701
|
cdpConnected: state.cdpConnected ?? isCdpConnected(cdpManagers, state.type),
|
|
4666
4702
|
currentModel: state.currentModel,
|
|
4667
4703
|
currentPlan: state.currentPlan,
|
|
4668
4704
|
currentAutoApprove: state.currentAutoApprove,
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4705
|
+
...includeSessionControls && {
|
|
4706
|
+
controlValues: state.controlValues,
|
|
4707
|
+
providerControls: buildFallbackControls(
|
|
4708
|
+
state.providerControls,
|
|
4709
|
+
state.currentModel,
|
|
4710
|
+
state.currentPlan
|
|
4711
|
+
)
|
|
4712
|
+
},
|
|
4675
4713
|
errorMessage: state.errorMessage,
|
|
4676
4714
|
errorReason: state.errorReason,
|
|
4677
4715
|
lastUpdated: state.lastUpdated
|
|
4678
4716
|
};
|
|
4679
4717
|
}
|
|
4680
|
-
function buildExtensionAgentSession(parent, ext) {
|
|
4681
|
-
const
|
|
4718
|
+
function buildExtensionAgentSession(parent, ext, options) {
|
|
4719
|
+
const profile = options.profile || "full";
|
|
4720
|
+
const activeChat = normalizeActiveChatData(ext.activeChat, getActiveChatOptions(profile));
|
|
4721
|
+
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
4722
|
+
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
4682
4723
|
return {
|
|
4683
4724
|
id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
|
|
4684
4725
|
parentId: parent.instanceId || parent.type,
|
|
4685
4726
|
providerType: ext.type,
|
|
4686
|
-
providerName: ext.name,
|
|
4727
|
+
...includeSessionMetadata && { providerName: ext.name },
|
|
4687
4728
|
kind: "agent",
|
|
4688
4729
|
transport: "cdp-webview",
|
|
4689
4730
|
status: normalizeManagedStatus(activeChat?.status || ext.status, {
|
|
4690
4731
|
activeModal: activeChat?.activeModal || null
|
|
4691
4732
|
}),
|
|
4692
4733
|
title: activeChat?.title || ext.name,
|
|
4693
|
-
workspace: parent.workspace || null,
|
|
4734
|
+
...includeSessionMetadata && { workspace: parent.workspace || null },
|
|
4694
4735
|
activeChat,
|
|
4695
|
-
capabilities: EXTENSION_SESSION_CAPABILITIES,
|
|
4736
|
+
...includeSessionMetadata && { capabilities: EXTENSION_SESSION_CAPABILITIES },
|
|
4696
4737
|
currentModel: ext.currentModel,
|
|
4697
4738
|
currentPlan: ext.currentPlan,
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4739
|
+
...includeSessionControls && {
|
|
4740
|
+
controlValues: ext.controlValues,
|
|
4741
|
+
providerControls: buildFallbackControls(
|
|
4742
|
+
ext.providerControls,
|
|
4743
|
+
ext.currentModel,
|
|
4744
|
+
ext.currentPlan
|
|
4745
|
+
)
|
|
4746
|
+
},
|
|
4704
4747
|
errorMessage: ext.errorMessage,
|
|
4705
4748
|
errorReason: ext.errorReason,
|
|
4706
4749
|
lastUpdated: ext.lastUpdated
|
|
4707
4750
|
};
|
|
4708
4751
|
}
|
|
4709
|
-
function buildCliSession(state) {
|
|
4710
|
-
const
|
|
4752
|
+
function buildCliSession(state, options) {
|
|
4753
|
+
const profile = options.profile || "full";
|
|
4754
|
+
const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
|
|
4755
|
+
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
4756
|
+
const includeRuntimeMetadata = shouldIncludeRuntimeMetadata(profile);
|
|
4757
|
+
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
4711
4758
|
return {
|
|
4712
4759
|
id: state.instanceId,
|
|
4713
4760
|
parentId: null,
|
|
4714
4761
|
providerType: state.type,
|
|
4715
|
-
providerName: state.name,
|
|
4762
|
+
...includeSessionMetadata && { providerName: state.name },
|
|
4716
4763
|
providerSessionId: state.providerSessionId,
|
|
4717
4764
|
kind: "agent",
|
|
4718
4765
|
transport: "pty",
|
|
@@ -4720,74 +4767,85 @@ function buildCliSession(state) {
|
|
|
4720
4767
|
activeModal: activeChat?.activeModal || null
|
|
4721
4768
|
}),
|
|
4722
4769
|
title: activeChat?.title || state.name,
|
|
4723
|
-
workspace: state.workspace || null,
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4770
|
+
...includeSessionMetadata && { workspace: state.workspace || null },
|
|
4771
|
+
...includeRuntimeMetadata && {
|
|
4772
|
+
runtimeKey: state.runtime?.runtimeKey,
|
|
4773
|
+
runtimeDisplayName: state.runtime?.displayName,
|
|
4774
|
+
runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
|
|
4775
|
+
runtimeWriteOwner: state.runtime?.writeOwner || null,
|
|
4776
|
+
runtimeAttachedClients: state.runtime?.attachedClients || []
|
|
4777
|
+
},
|
|
4729
4778
|
mode: state.mode,
|
|
4730
4779
|
resume: state.resume,
|
|
4731
4780
|
activeChat,
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4781
|
+
...includeSessionMetadata && {
|
|
4782
|
+
capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES
|
|
4783
|
+
},
|
|
4784
|
+
...includeSessionControls && {
|
|
4785
|
+
controlValues: state.controlValues,
|
|
4786
|
+
providerControls: buildFallbackControls(
|
|
4787
|
+
state.providerControls
|
|
4788
|
+
)
|
|
4789
|
+
},
|
|
4737
4790
|
errorMessage: state.errorMessage,
|
|
4738
4791
|
errorReason: state.errorReason,
|
|
4739
4792
|
lastUpdated: state.lastUpdated
|
|
4740
4793
|
};
|
|
4741
4794
|
}
|
|
4742
|
-
function buildAcpSession(state) {
|
|
4743
|
-
const
|
|
4795
|
+
function buildAcpSession(state, options) {
|
|
4796
|
+
const profile = options.profile || "full";
|
|
4797
|
+
const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
|
|
4798
|
+
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
4799
|
+
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
4744
4800
|
return {
|
|
4745
4801
|
id: state.instanceId,
|
|
4746
4802
|
parentId: null,
|
|
4747
4803
|
providerType: state.type,
|
|
4748
|
-
providerName: state.name,
|
|
4804
|
+
...includeSessionMetadata && { providerName: state.name },
|
|
4749
4805
|
kind: "agent",
|
|
4750
4806
|
transport: "acp",
|
|
4751
4807
|
status: normalizeManagedStatus(activeChat?.status || state.status, {
|
|
4752
4808
|
activeModal: activeChat?.activeModal || null
|
|
4753
4809
|
}),
|
|
4754
4810
|
title: activeChat?.title || state.name,
|
|
4755
|
-
workspace: state.workspace || null,
|
|
4811
|
+
...includeSessionMetadata && { workspace: state.workspace || null },
|
|
4756
4812
|
activeChat,
|
|
4757
|
-
capabilities: ACP_SESSION_CAPABILITIES,
|
|
4813
|
+
...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
|
|
4758
4814
|
currentModel: state.currentModel,
|
|
4759
4815
|
currentPlan: state.currentPlan,
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4816
|
+
...includeSessionControls && {
|
|
4817
|
+
acpConfigOptions: state.acpConfigOptions,
|
|
4818
|
+
acpModes: state.acpModes,
|
|
4819
|
+
controlValues: state.controlValues,
|
|
4820
|
+
providerControls: buildFallbackControls(
|
|
4821
|
+
state.providerControls,
|
|
4822
|
+
state.currentModel,
|
|
4823
|
+
state.currentPlan,
|
|
4824
|
+
state.acpConfigOptions,
|
|
4825
|
+
state.acpModes
|
|
4826
|
+
)
|
|
4827
|
+
},
|
|
4770
4828
|
errorMessage: state.errorMessage,
|
|
4771
4829
|
errorReason: state.errorReason,
|
|
4772
4830
|
lastUpdated: state.lastUpdated
|
|
4773
4831
|
};
|
|
4774
4832
|
}
|
|
4775
|
-
function buildSessionEntries(allStates, cdpManagers) {
|
|
4833
|
+
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
4776
4834
|
const sessions = [];
|
|
4777
4835
|
const ideStates = allStates.filter((s) => s.category === "ide");
|
|
4778
4836
|
const cliStates = allStates.filter((s) => s.category === "cli");
|
|
4779
4837
|
const acpStates = allStates.filter((s) => s.category === "acp");
|
|
4780
4838
|
for (const state of ideStates) {
|
|
4781
|
-
sessions.push(buildIdeWorkspaceSession(state, cdpManagers));
|
|
4839
|
+
sessions.push(buildIdeWorkspaceSession(state, cdpManagers, options));
|
|
4782
4840
|
for (const ext of state.extensions) {
|
|
4783
|
-
sessions.push(buildExtensionAgentSession(state, ext));
|
|
4841
|
+
sessions.push(buildExtensionAgentSession(state, ext, options));
|
|
4784
4842
|
}
|
|
4785
4843
|
}
|
|
4786
4844
|
for (const state of cliStates) {
|
|
4787
|
-
sessions.push(buildCliSession(state));
|
|
4845
|
+
sessions.push(buildCliSession(state, options));
|
|
4788
4846
|
}
|
|
4789
4847
|
for (const state of acpStates) {
|
|
4790
|
-
sessions.push(buildAcpSession(state));
|
|
4848
|
+
sessions.push(buildAcpSession(state, options));
|
|
4791
4849
|
}
|
|
4792
4850
|
const extensionParentIds = new Set(
|
|
4793
4851
|
sessions.filter((session) => session.transport === "cdp-webview" && !!session.parentId).map((session) => session.parentId)
|
|
@@ -4899,7 +4957,31 @@ var init_reconcile = __esm({
|
|
|
4899
4957
|
}
|
|
4900
4958
|
});
|
|
4901
4959
|
|
|
4960
|
+
// ../../oss/packages/daemon-core/src/providers/contracts.ts
|
|
4961
|
+
function flattenContent(content) {
|
|
4962
|
+
if (typeof content === "string") return content;
|
|
4963
|
+
return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
4964
|
+
}
|
|
4965
|
+
var init_contracts = __esm({
|
|
4966
|
+
"../../oss/packages/daemon-core/src/providers/contracts.ts"() {
|
|
4967
|
+
"use strict";
|
|
4968
|
+
}
|
|
4969
|
+
});
|
|
4970
|
+
|
|
4902
4971
|
// ../../oss/packages/daemon-core/src/commands/chat-commands.ts
|
|
4972
|
+
function hashSignatureParts(parts) {
|
|
4973
|
+
let hash2 = 2166136261;
|
|
4974
|
+
for (const part of parts) {
|
|
4975
|
+
const text = String(part || "");
|
|
4976
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
4977
|
+
hash2 ^= text.charCodeAt(i);
|
|
4978
|
+
hash2 = Math.imul(hash2, 16777619) >>> 0;
|
|
4979
|
+
}
|
|
4980
|
+
hash2 ^= 255;
|
|
4981
|
+
hash2 = Math.imul(hash2, 16777619) >>> 0;
|
|
4982
|
+
}
|
|
4983
|
+
return hash2.toString(16).padStart(8, "0");
|
|
4984
|
+
}
|
|
4903
4985
|
function getCurrentProviderType(h, fallback = "") {
|
|
4904
4986
|
return h.currentSession?.providerType || h.currentProviderType || fallback;
|
|
4905
4987
|
}
|
|
@@ -4973,6 +5055,134 @@ function parseMaybeJson(value) {
|
|
|
4973
5055
|
return value;
|
|
4974
5056
|
}
|
|
4975
5057
|
}
|
|
5058
|
+
function getChatMessageSignature(message) {
|
|
5059
|
+
if (!message) return "";
|
|
5060
|
+
let content = "";
|
|
5061
|
+
try {
|
|
5062
|
+
content = JSON.stringify(message.content ?? "");
|
|
5063
|
+
} catch {
|
|
5064
|
+
content = String(message.content ?? "");
|
|
5065
|
+
}
|
|
5066
|
+
return hashSignatureParts([
|
|
5067
|
+
String(message.id || ""),
|
|
5068
|
+
String(message.index ?? ""),
|
|
5069
|
+
String(message.role || ""),
|
|
5070
|
+
String(message.receivedAt ?? message.timestamp ?? ""),
|
|
5071
|
+
content
|
|
5072
|
+
]);
|
|
5073
|
+
}
|
|
5074
|
+
function normalizeReadChatCursor(args) {
|
|
5075
|
+
const knownMessageCount = Math.max(0, Number(args?.knownMessageCount || 0));
|
|
5076
|
+
const lastMessageSignature = typeof args?.lastMessageSignature === "string" ? args.lastMessageSignature : "";
|
|
5077
|
+
const tailLimit = Math.max(0, Number(args?.tailLimit || 0));
|
|
5078
|
+
return { knownMessageCount, lastMessageSignature, tailLimit };
|
|
5079
|
+
}
|
|
5080
|
+
function normalizeReadChatMessages(payload) {
|
|
5081
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
5082
|
+
return messages;
|
|
5083
|
+
}
|
|
5084
|
+
function deriveHistoryDedupKey(message) {
|
|
5085
|
+
const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
|
|
5086
|
+
if (unitKey) return `read_chat:${unitKey}`;
|
|
5087
|
+
const turnKey = typeof message._turnKey === "string" ? message._turnKey.trim() : "";
|
|
5088
|
+
if (!turnKey) return void 0;
|
|
5089
|
+
let content = "";
|
|
5090
|
+
try {
|
|
5091
|
+
content = JSON.stringify(message.content ?? "");
|
|
5092
|
+
} catch {
|
|
5093
|
+
content = String(message.content ?? "");
|
|
5094
|
+
}
|
|
5095
|
+
return `read_chat:${turnKey}:${String(message.role || "").toLowerCase()}:${content}`;
|
|
5096
|
+
}
|
|
5097
|
+
function toHistoryPersistedMessages(messages) {
|
|
5098
|
+
return messages.map((message) => ({
|
|
5099
|
+
role: message.role,
|
|
5100
|
+
content: flattenContent(message.content),
|
|
5101
|
+
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : void 0,
|
|
5102
|
+
kind: typeof message.kind === "string" ? message.kind : void 0,
|
|
5103
|
+
senderName: typeof message.senderName === "string" ? message.senderName : void 0,
|
|
5104
|
+
historyDedupKey: deriveHistoryDedupKey(message)
|
|
5105
|
+
}));
|
|
5106
|
+
}
|
|
5107
|
+
function computeReadChatSync(messages, cursor) {
|
|
5108
|
+
const totalMessages = messages.length;
|
|
5109
|
+
const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
|
|
5110
|
+
const { knownMessageCount, lastMessageSignature: knownSignature } = cursor;
|
|
5111
|
+
if (!knownMessageCount || !knownSignature) {
|
|
5112
|
+
return {
|
|
5113
|
+
syncMode: "full",
|
|
5114
|
+
replaceFrom: 0,
|
|
5115
|
+
messages,
|
|
5116
|
+
totalMessages,
|
|
5117
|
+
lastMessageSignature
|
|
5118
|
+
};
|
|
5119
|
+
}
|
|
5120
|
+
if (knownMessageCount > totalMessages) {
|
|
5121
|
+
return {
|
|
5122
|
+
syncMode: "full",
|
|
5123
|
+
replaceFrom: 0,
|
|
5124
|
+
messages,
|
|
5125
|
+
totalMessages,
|
|
5126
|
+
lastMessageSignature
|
|
5127
|
+
};
|
|
5128
|
+
}
|
|
5129
|
+
if (knownMessageCount === totalMessages && knownSignature === lastMessageSignature) {
|
|
5130
|
+
return {
|
|
5131
|
+
syncMode: "noop",
|
|
5132
|
+
replaceFrom: totalMessages,
|
|
5133
|
+
messages: [],
|
|
5134
|
+
totalMessages,
|
|
5135
|
+
lastMessageSignature
|
|
5136
|
+
};
|
|
5137
|
+
}
|
|
5138
|
+
if (knownMessageCount < totalMessages) {
|
|
5139
|
+
const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
|
|
5140
|
+
if (anchorSignature === knownSignature) {
|
|
5141
|
+
return {
|
|
5142
|
+
syncMode: "append",
|
|
5143
|
+
replaceFrom: knownMessageCount,
|
|
5144
|
+
messages: messages.slice(knownMessageCount),
|
|
5145
|
+
totalMessages,
|
|
5146
|
+
lastMessageSignature
|
|
5147
|
+
};
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
|
|
5151
|
+
return {
|
|
5152
|
+
syncMode: replaceFrom === 0 ? "full" : "replace_tail",
|
|
5153
|
+
replaceFrom,
|
|
5154
|
+
messages: replaceFrom === 0 ? messages : messages.slice(replaceFrom),
|
|
5155
|
+
totalMessages,
|
|
5156
|
+
lastMessageSignature
|
|
5157
|
+
};
|
|
5158
|
+
}
|
|
5159
|
+
function buildReadChatCommandResult(payload, args) {
|
|
5160
|
+
const messages = normalizeReadChatMessages(payload);
|
|
5161
|
+
const cursor = normalizeReadChatCursor(args);
|
|
5162
|
+
if (!cursor.knownMessageCount && !cursor.lastMessageSignature && cursor.tailLimit > 0 && messages.length > cursor.tailLimit) {
|
|
5163
|
+
const tailMessages = messages.slice(-cursor.tailLimit);
|
|
5164
|
+
const lastMessageSignature = getChatMessageSignature(tailMessages[tailMessages.length - 1]);
|
|
5165
|
+
return {
|
|
5166
|
+
success: true,
|
|
5167
|
+
...payload,
|
|
5168
|
+
messages: tailMessages,
|
|
5169
|
+
syncMode: "full",
|
|
5170
|
+
replaceFrom: 0,
|
|
5171
|
+
totalMessages: messages.length,
|
|
5172
|
+
lastMessageSignature
|
|
5173
|
+
};
|
|
5174
|
+
}
|
|
5175
|
+
const sync = computeReadChatSync(messages, cursor);
|
|
5176
|
+
return {
|
|
5177
|
+
success: true,
|
|
5178
|
+
...payload,
|
|
5179
|
+
messages: sync.messages,
|
|
5180
|
+
syncMode: sync.syncMode,
|
|
5181
|
+
replaceFrom: sync.replaceFrom,
|
|
5182
|
+
totalMessages: sync.totalMessages,
|
|
5183
|
+
lastMessageSignature: sync.lastMessageSignature
|
|
5184
|
+
};
|
|
5185
|
+
}
|
|
4976
5186
|
function didProviderConfirmSend(result) {
|
|
4977
5187
|
const parsed = parseMaybeJson(result);
|
|
4978
5188
|
if (parsed === true) return true;
|
|
@@ -5046,12 +5256,11 @@ async function handleReadChat(h, args) {
|
|
|
5046
5256
|
_log(`${transport} adapter: ${adapter.cliType}`);
|
|
5047
5257
|
const status = adapter.getStatus();
|
|
5048
5258
|
if (status) {
|
|
5049
|
-
return {
|
|
5050
|
-
success: true,
|
|
5259
|
+
return buildReadChatCommandResult({
|
|
5051
5260
|
messages: status.messages || [],
|
|
5052
5261
|
status: status.status,
|
|
5053
5262
|
activeModal: status.activeModal
|
|
5054
|
-
};
|
|
5263
|
+
}, args);
|
|
5055
5264
|
}
|
|
5056
5265
|
}
|
|
5057
5266
|
return { success: false, error: `${transport} adapter not found` };
|
|
@@ -5071,12 +5280,12 @@ async function handleReadChat(h, args) {
|
|
|
5071
5280
|
_log(`Extension OK: ${parsed.messages?.length || 0} msgs`);
|
|
5072
5281
|
h.historyWriter.appendNewMessages(
|
|
5073
5282
|
provider?.type || "unknown_extension",
|
|
5074
|
-
parsed
|
|
5283
|
+
toHistoryPersistedMessages(normalizeReadChatMessages(parsed)),
|
|
5075
5284
|
parsed.title,
|
|
5076
5285
|
args?.targetSessionId,
|
|
5077
5286
|
historySessionId
|
|
5078
5287
|
);
|
|
5079
|
-
return
|
|
5288
|
+
return buildReadChatCommandResult(parsed, args);
|
|
5080
5289
|
}
|
|
5081
5290
|
}
|
|
5082
5291
|
} catch (e) {
|
|
@@ -5088,21 +5297,25 @@ async function handleReadChat(h, args) {
|
|
|
5088
5297
|
if (cdp2 && parentSessionId) {
|
|
5089
5298
|
const stream = await h.agentStream.collectActiveSession(cdp2, parentSessionId);
|
|
5090
5299
|
if (stream?.agentType !== provider?.type) {
|
|
5091
|
-
return {
|
|
5300
|
+
return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
|
|
5092
5301
|
}
|
|
5093
5302
|
if (stream) {
|
|
5094
5303
|
h.historyWriter.appendNewMessages(
|
|
5095
5304
|
stream.agentType,
|
|
5096
|
-
stream.messages || [],
|
|
5305
|
+
toHistoryPersistedMessages(stream.messages || []),
|
|
5097
5306
|
void 0,
|
|
5098
5307
|
args?.targetSessionId,
|
|
5099
5308
|
historySessionId
|
|
5100
5309
|
);
|
|
5101
|
-
return {
|
|
5310
|
+
return buildReadChatCommandResult({
|
|
5311
|
+
messages: stream.messages || [],
|
|
5312
|
+
status: stream.status,
|
|
5313
|
+
agentType: stream.agentType
|
|
5314
|
+
}, args);
|
|
5102
5315
|
}
|
|
5103
5316
|
}
|
|
5104
5317
|
}
|
|
5105
|
-
return {
|
|
5318
|
+
return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
|
|
5106
5319
|
}
|
|
5107
5320
|
const cdp = h.getCdp();
|
|
5108
5321
|
if (!cdp?.isConnected) return { success: false, error: "CDP not connected" };
|
|
@@ -5124,18 +5337,18 @@ async function handleReadChat(h, args) {
|
|
|
5124
5337
|
_log(`Webview OK: ${parsed.messages?.length || 0} msgs`);
|
|
5125
5338
|
h.historyWriter.appendNewMessages(
|
|
5126
5339
|
provider?.type || getCurrentProviderType(h, "unknown_webview"),
|
|
5127
|
-
parsed
|
|
5340
|
+
toHistoryPersistedMessages(normalizeReadChatMessages(parsed)),
|
|
5128
5341
|
parsed.title,
|
|
5129
5342
|
args?.targetSessionId,
|
|
5130
5343
|
historySessionId
|
|
5131
5344
|
);
|
|
5132
|
-
return
|
|
5345
|
+
return buildReadChatCommandResult(parsed, args);
|
|
5133
5346
|
}
|
|
5134
5347
|
}
|
|
5135
5348
|
} catch (e) {
|
|
5136
5349
|
_log(`Webview readChat error: ${e.message}`);
|
|
5137
5350
|
}
|
|
5138
|
-
return {
|
|
5351
|
+
return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
|
|
5139
5352
|
}
|
|
5140
5353
|
const script = h.getProviderScript("readChat") || h.getProviderScript("read_chat");
|
|
5141
5354
|
if (script) {
|
|
@@ -5152,18 +5365,18 @@ async function handleReadChat(h, args) {
|
|
|
5152
5365
|
_log(`OK: ${parsed.messages?.length} msgs`);
|
|
5153
5366
|
h.historyWriter.appendNewMessages(
|
|
5154
5367
|
provider?.type || getCurrentProviderType(h, "unknown_ide"),
|
|
5155
|
-
parsed
|
|
5368
|
+
toHistoryPersistedMessages(normalizeReadChatMessages(parsed)),
|
|
5156
5369
|
parsed.title,
|
|
5157
5370
|
args?.targetSessionId,
|
|
5158
5371
|
historySessionId
|
|
5159
5372
|
);
|
|
5160
|
-
return
|
|
5373
|
+
return buildReadChatCommandResult(parsed, args);
|
|
5161
5374
|
}
|
|
5162
5375
|
} catch (e) {
|
|
5163
5376
|
LOG.info("Command", `[read_chat] Script error: ${e.message}`);
|
|
5164
5377
|
}
|
|
5165
5378
|
}
|
|
5166
|
-
return {
|
|
5379
|
+
return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
|
|
5167
5380
|
}
|
|
5168
5381
|
async function handleSendChat(h, args) {
|
|
5169
5382
|
const text = args?.text || args?.message;
|
|
@@ -5814,6 +6027,7 @@ var RECENT_SEND_WINDOW_MS, recentSendByTarget;
|
|
|
5814
6027
|
var init_chat_commands = __esm({
|
|
5815
6028
|
"../../oss/packages/daemon-core/src/commands/chat-commands.ts"() {
|
|
5816
6029
|
"use strict";
|
|
6030
|
+
init_contracts();
|
|
5817
6031
|
init_chat_history();
|
|
5818
6032
|
init_logger();
|
|
5819
6033
|
RECENT_SEND_WINDOW_MS = 1200;
|
|
@@ -6299,21 +6513,21 @@ function applyProviderPatch(h, args, payload) {
|
|
|
6299
6513
|
});
|
|
6300
6514
|
}
|
|
6301
6515
|
async function executeProviderScript(h, args, scriptName) {
|
|
6302
|
-
const
|
|
6303
|
-
if (!
|
|
6516
|
+
const resolvedProviderType = h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
|
|
6517
|
+
if (!resolvedProviderType) return { success: false, error: "targetSessionId or providerType is required" };
|
|
6304
6518
|
const loader = h.ctx.providerLoader;
|
|
6305
6519
|
if (!loader) return { success: false, error: "ProviderLoader not initialized" };
|
|
6306
|
-
const provider = loader.resolve(
|
|
6307
|
-
if (!provider) return { success: false, error: `Provider not found: ${
|
|
6520
|
+
const provider = loader.resolve(resolvedProviderType);
|
|
6521
|
+
if (!provider) return { success: false, error: `Provider not found: ${resolvedProviderType}` };
|
|
6308
6522
|
const webviewScriptName = `webview${scriptName.charAt(0).toUpperCase() + scriptName.slice(1)}`;
|
|
6309
6523
|
const hasWebviewScript = provider.category === "ide" && !!provider.scripts?.[webviewScriptName];
|
|
6310
6524
|
const actualScriptName = hasWebviewScript ? webviewScriptName : scriptName;
|
|
6311
6525
|
if (!provider.scripts?.[actualScriptName]) {
|
|
6312
|
-
return { success: false, error: `Script '${actualScriptName}' not available for ${
|
|
6526
|
+
return { success: false, error: `Script '${actualScriptName}' not available for ${resolvedProviderType}` };
|
|
6313
6527
|
}
|
|
6314
6528
|
const normalizedArgs = normalizeProviderScriptArgs(args);
|
|
6315
6529
|
if (provider.category === "cli") {
|
|
6316
|
-
const adapter = h.getCliAdapter(args?.targetSessionId ||
|
|
6530
|
+
const adapter = h.getCliAdapter(args?.targetSessionId || resolvedProviderType);
|
|
6317
6531
|
if (!adapter?.invokeScript) {
|
|
6318
6532
|
return { success: false, error: `CLI adapter does not support script '${actualScriptName}'` };
|
|
6319
6533
|
}
|
|
@@ -6338,7 +6552,7 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
6338
6552
|
const scriptFn = provider.scripts[actualScriptName];
|
|
6339
6553
|
const scriptCode = scriptFn(normalizedArgs);
|
|
6340
6554
|
if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
|
|
6341
|
-
const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey ||
|
|
6555
|
+
const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : h.currentSession?.cdpManagerKey || h.currentManagerKey;
|
|
6342
6556
|
LOG.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
|
|
6343
6557
|
const cdp = h.getCdp(cdpKey);
|
|
6344
6558
|
if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
|
|
@@ -6346,7 +6560,7 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
6346
6560
|
let result;
|
|
6347
6561
|
if (provider.category === "extension") {
|
|
6348
6562
|
const runtimeSessionId = h.currentSession?.sessionId || args?.targetSessionId;
|
|
6349
|
-
if (!runtimeSessionId) return { success: false, error: `No target session found for ${
|
|
6563
|
+
if (!runtimeSessionId) return { success: false, error: `No target session found for ${resolvedProviderType}` };
|
|
6350
6564
|
const parentSessionId = h.currentSession?.parentSessionId;
|
|
6351
6565
|
if (parentSessionId) {
|
|
6352
6566
|
await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
|
|
@@ -6375,7 +6589,7 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
6375
6589
|
}
|
|
6376
6590
|
} else {
|
|
6377
6591
|
if (!targetSessionId) {
|
|
6378
|
-
return { success: false, error: `No active session found for ${
|
|
6592
|
+
return { success: false, error: `No active session found for ${resolvedProviderType}` };
|
|
6379
6593
|
}
|
|
6380
6594
|
result = await cdp.evaluateInSessionFrame(targetSessionId, scriptCode);
|
|
6381
6595
|
}
|
|
@@ -9724,8 +9938,6 @@ ${data.message || ""}`.trim();
|
|
|
9724
9938
|
if (blockingModal || this.currentStatus === "waiting_approval") {
|
|
9725
9939
|
throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
|
|
9726
9940
|
}
|
|
9727
|
-
this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
9728
|
-
this.syncMessageViews();
|
|
9729
9941
|
this.isWaitingForResponse = true;
|
|
9730
9942
|
this.responseBuffer = "";
|
|
9731
9943
|
this.finishRetryCount = 0;
|
|
@@ -9757,6 +9969,13 @@ ${data.message || ""}`.trim();
|
|
|
9757
9969
|
const submitDelayMs = this.sendDelayMs + Math.min(2e3, Math.max(0, estimatedLines - 1) * 350);
|
|
9758
9970
|
const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5e3, estimatedLines * 500));
|
|
9759
9971
|
const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
|
|
9972
|
+
let didCommitUserTurn = false;
|
|
9973
|
+
const commitUserTurn = () => {
|
|
9974
|
+
if (didCommitUserTurn) return;
|
|
9975
|
+
didCommitUserTurn = true;
|
|
9976
|
+
this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
9977
|
+
this.syncMessageViews();
|
|
9978
|
+
};
|
|
9760
9979
|
if (this.settleTimer) {
|
|
9761
9980
|
clearTimeout(this.settleTimer);
|
|
9762
9981
|
this.settleTimer = null;
|
|
@@ -9769,109 +9988,128 @@ ${data.message || ""}`.trim();
|
|
|
9769
9988
|
if (this.isWaitingForResponse) this.finishResponse();
|
|
9770
9989
|
}, this.timeouts.maxResponse);
|
|
9771
9990
|
};
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9991
|
+
await new Promise((resolve17) => {
|
|
9992
|
+
let resolved = false;
|
|
9993
|
+
const resolveOnce = () => {
|
|
9994
|
+
if (resolved) return;
|
|
9995
|
+
resolved = true;
|
|
9996
|
+
resolve17();
|
|
9997
|
+
};
|
|
9998
|
+
const submit = () => {
|
|
9999
|
+
if (!this.ptyProcess) {
|
|
10000
|
+
resolveOnce();
|
|
10001
|
+
return;
|
|
10002
|
+
}
|
|
10003
|
+
commitUserTurn();
|
|
10004
|
+
this.submitPendingUntil = 0;
|
|
9786
10005
|
const screenText = this.terminalScreen.getText();
|
|
9787
|
-
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
9788
|
-
if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
|
|
9789
|
-
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
9790
|
-
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
9791
10006
|
this.recordTrace("submit_write", {
|
|
9792
|
-
mode: "
|
|
9793
|
-
attempt,
|
|
10007
|
+
mode: "submit_key",
|
|
9794
10008
|
sendKey: this.sendKey,
|
|
9795
10009
|
screenText: summarizeCliTraceText(screenText, 500)
|
|
9796
10010
|
});
|
|
9797
10011
|
this.ptyProcess.write(this.sendKey);
|
|
9798
|
-
|
|
9799
|
-
this.
|
|
9800
|
-
return;
|
|
9801
|
-
|
|
9802
|
-
|
|
10012
|
+
const retrySubmitIfStuck = (attempt) => {
|
|
10013
|
+
this.submitRetryTimer = null;
|
|
10014
|
+
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
10015
|
+
if (this.currentStatus === "waiting_approval") return;
|
|
10016
|
+
if ((this.responseBuffer || "").trim()) return;
|
|
10017
|
+
const screenText2 = this.terminalScreen.getText();
|
|
10018
|
+
if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
|
|
10019
|
+
if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText2)) return;
|
|
10020
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
10021
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
10022
|
+
this.recordTrace("submit_write", {
|
|
10023
|
+
mode: "submit_retry",
|
|
10024
|
+
attempt,
|
|
10025
|
+
sendKey: this.sendKey,
|
|
10026
|
+
screenText: summarizeCliTraceText(screenText2, 500)
|
|
10027
|
+
});
|
|
10028
|
+
this.ptyProcess.write(this.sendKey);
|
|
10029
|
+
if (attempt >= 3) {
|
|
10030
|
+
this.submitRetryUsed = true;
|
|
10031
|
+
return;
|
|
10032
|
+
}
|
|
10033
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
|
|
10034
|
+
};
|
|
10035
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
|
|
10036
|
+
startResponseTimeout();
|
|
10037
|
+
resolveOnce();
|
|
9803
10038
|
};
|
|
9804
|
-
this.
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
10039
|
+
if (this.submitStrategy === "immediate") {
|
|
10040
|
+
commitUserTurn();
|
|
10041
|
+
this.submitPendingUntil = 0;
|
|
10042
|
+
this.recordTrace("submit_write", {
|
|
10043
|
+
mode: "immediate",
|
|
10044
|
+
text: summarizeCliTraceText(text, 500),
|
|
10045
|
+
sendKey: this.sendKey,
|
|
10046
|
+
screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
|
|
10047
|
+
});
|
|
10048
|
+
this.ptyProcess.write(text + this.sendKey);
|
|
10049
|
+
this.submitRetryTimer = setTimeout(() => {
|
|
10050
|
+
this.submitRetryTimer = null;
|
|
10051
|
+
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
10052
|
+
if (this.currentStatus === "waiting_approval") return;
|
|
10053
|
+
if ((this.responseBuffer || "").trim()) return;
|
|
10054
|
+
const screenText = this.terminalScreen.getText();
|
|
10055
|
+
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
10056
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
|
|
10057
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
10058
|
+
this.recordTrace("submit_write", {
|
|
10059
|
+
mode: "immediate_retry",
|
|
10060
|
+
attempt: 1,
|
|
10061
|
+
sendKey: this.sendKey,
|
|
10062
|
+
screenText: summarizeCliTraceText(screenText, 500)
|
|
10063
|
+
});
|
|
10064
|
+
this.ptyProcess.write(this.sendKey);
|
|
10065
|
+
this.submitRetryUsed = true;
|
|
10066
|
+
}, retryDelayMs);
|
|
10067
|
+
startResponseTimeout();
|
|
10068
|
+
resolveOnce();
|
|
10069
|
+
return;
|
|
10070
|
+
}
|
|
10071
|
+
if (submitDelayMs > 0) {
|
|
10072
|
+
this.submitPendingUntil = Date.now() + submitDelayMs;
|
|
10073
|
+
}
|
|
10074
|
+
this.ptyProcess.write(text);
|
|
9809
10075
|
this.recordTrace("submit_write", {
|
|
9810
|
-
mode: "
|
|
10076
|
+
mode: "type_then_submit",
|
|
9811
10077
|
text: summarizeCliTraceText(text, 500),
|
|
9812
10078
|
sendKey: this.sendKey,
|
|
9813
10079
|
screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
|
|
9814
10080
|
});
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
if (this.
|
|
9820
|
-
|
|
10081
|
+
const submitStartedAt = Date.now();
|
|
10082
|
+
let lastNormalizedScreen = "";
|
|
10083
|
+
let lastScreenChangeAt = submitStartedAt;
|
|
10084
|
+
const waitForEchoAndSubmit = () => {
|
|
10085
|
+
if (!this.ptyProcess) {
|
|
10086
|
+
resolveOnce();
|
|
10087
|
+
return;
|
|
10088
|
+
}
|
|
10089
|
+
const now = Date.now();
|
|
10090
|
+
const elapsed = now - submitStartedAt;
|
|
9821
10091
|
const screenText = this.terminalScreen.getText();
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
}
|
|
9837
|
-
if (submitDelayMs > 0) {
|
|
9838
|
-
this.submitPendingUntil = Date.now() + submitDelayMs;
|
|
9839
|
-
}
|
|
9840
|
-
this.ptyProcess.write(text);
|
|
9841
|
-
this.recordTrace("submit_write", {
|
|
9842
|
-
mode: "type_then_submit",
|
|
9843
|
-
text: summarizeCliTraceText(text, 500),
|
|
9844
|
-
sendKey: this.sendKey,
|
|
9845
|
-
screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
|
|
9846
|
-
});
|
|
9847
|
-
const submitStartedAt = Date.now();
|
|
9848
|
-
let lastNormalizedScreen = "";
|
|
9849
|
-
let lastScreenChangeAt = submitStartedAt;
|
|
9850
|
-
const waitForEchoAndSubmit = () => {
|
|
9851
|
-
if (!this.ptyProcess) return;
|
|
9852
|
-
const now = Date.now();
|
|
9853
|
-
const elapsed = now - submitStartedAt;
|
|
9854
|
-
const screenText = this.terminalScreen.getText();
|
|
9855
|
-
const normalizedScreen = normalizePromptText(screenText);
|
|
9856
|
-
if (normalizedScreen !== lastNormalizedScreen) {
|
|
9857
|
-
lastNormalizedScreen = normalizedScreen;
|
|
9858
|
-
lastScreenChangeAt = now;
|
|
9859
|
-
}
|
|
9860
|
-
const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
|
|
9861
|
-
if (echoVisible) {
|
|
9862
|
-
const screenSettled = now - lastScreenChangeAt >= 500;
|
|
9863
|
-
if (elapsed >= submitDelayMs && screenSettled) {
|
|
10092
|
+
const normalizedScreen = normalizePromptText(screenText);
|
|
10093
|
+
if (normalizedScreen !== lastNormalizedScreen) {
|
|
10094
|
+
lastNormalizedScreen = normalizedScreen;
|
|
10095
|
+
lastScreenChangeAt = now;
|
|
10096
|
+
}
|
|
10097
|
+
const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
|
|
10098
|
+
if (echoVisible) {
|
|
10099
|
+
const screenSettled = now - lastScreenChangeAt >= 500;
|
|
10100
|
+
if (elapsed >= submitDelayMs && screenSettled) {
|
|
10101
|
+
submit();
|
|
10102
|
+
return;
|
|
10103
|
+
}
|
|
10104
|
+
}
|
|
10105
|
+
if (elapsed >= maxEchoWaitMs) {
|
|
9864
10106
|
submit();
|
|
9865
10107
|
return;
|
|
9866
10108
|
}
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
}
|
|
9872
|
-
setTimeout(waitForEchoAndSubmit, 50);
|
|
9873
|
-
};
|
|
9874
|
-
waitForEchoAndSubmit();
|
|
10109
|
+
setTimeout(waitForEchoAndSubmit, 50);
|
|
10110
|
+
};
|
|
10111
|
+
waitForEchoAndSubmit();
|
|
10112
|
+
});
|
|
9875
10113
|
}
|
|
9876
10114
|
getPartialResponse() {
|
|
9877
10115
|
if (!this.isWaitingForResponse) return "";
|
|
@@ -27177,17 +27415,6 @@ var init_acp = __esm({
|
|
|
27177
27415
|
}
|
|
27178
27416
|
});
|
|
27179
27417
|
|
|
27180
|
-
// ../../oss/packages/daemon-core/src/providers/contracts.ts
|
|
27181
|
-
function flattenContent(content) {
|
|
27182
|
-
if (typeof content === "string") return content;
|
|
27183
|
-
return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
27184
|
-
}
|
|
27185
|
-
var init_contracts = __esm({
|
|
27186
|
-
"../../oss/packages/daemon-core/src/providers/contracts.ts"() {
|
|
27187
|
-
"use strict";
|
|
27188
|
-
}
|
|
27189
|
-
});
|
|
27190
|
-
|
|
27191
27418
|
// ../../oss/packages/daemon-core/src/providers/acp-provider-instance.ts
|
|
27192
27419
|
var import_stream, import_child_process5, AcpProviderInstance;
|
|
27193
27420
|
var init_acp_provider_instance = __esm({
|
|
@@ -32340,6 +32567,37 @@ function buildAvailableProviders(providerLoader) {
|
|
|
32340
32567
|
...provider.detectedPath !== void 0 ? { detectedPath: provider.detectedPath } : {}
|
|
32341
32568
|
}));
|
|
32342
32569
|
}
|
|
32570
|
+
function buildMachineInfo(profile = "full") {
|
|
32571
|
+
const base = {
|
|
32572
|
+
hostname: os17.hostname(),
|
|
32573
|
+
platform: os17.platform()
|
|
32574
|
+
};
|
|
32575
|
+
if (profile === "live") {
|
|
32576
|
+
return base;
|
|
32577
|
+
}
|
|
32578
|
+
if (profile === "metadata") {
|
|
32579
|
+
const memSnap2 = getHostMemorySnapshot();
|
|
32580
|
+
return {
|
|
32581
|
+
...base,
|
|
32582
|
+
arch: os17.arch(),
|
|
32583
|
+
cpus: os17.cpus().length,
|
|
32584
|
+
totalMem: memSnap2.totalMem,
|
|
32585
|
+
release: os17.release()
|
|
32586
|
+
};
|
|
32587
|
+
}
|
|
32588
|
+
const memSnap = getHostMemorySnapshot();
|
|
32589
|
+
return {
|
|
32590
|
+
...base,
|
|
32591
|
+
arch: os17.arch(),
|
|
32592
|
+
cpus: os17.cpus().length,
|
|
32593
|
+
totalMem: memSnap.totalMem,
|
|
32594
|
+
freeMem: memSnap.freeMem,
|
|
32595
|
+
availableMem: memSnap.availableMem,
|
|
32596
|
+
loadavg: os17.loadavg(),
|
|
32597
|
+
uptime: os17.uptime(),
|
|
32598
|
+
release: os17.release()
|
|
32599
|
+
};
|
|
32600
|
+
}
|
|
32343
32601
|
function parseMessageTime(value) {
|
|
32344
32602
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
32345
32603
|
if (typeof value === "string") {
|
|
@@ -32395,26 +32653,35 @@ function buildRecentLaunches(recentActivity) {
|
|
|
32395
32653
|
})).sort((a, b) => b.lastLaunchedAt - a.lastLaunchedAt).slice(0, 12);
|
|
32396
32654
|
}
|
|
32397
32655
|
function buildStatusSnapshot(options) {
|
|
32656
|
+
const profile = options.profile || "full";
|
|
32398
32657
|
const cfg = loadConfig();
|
|
32399
32658
|
const state = loadState();
|
|
32400
32659
|
const wsState = getWorkspaceState(cfg);
|
|
32401
|
-
const memSnap = getHostMemorySnapshot();
|
|
32402
32660
|
const recentActivity = getRecentActivity(state, 20);
|
|
32403
|
-
const
|
|
32661
|
+
const unreadSourceSessions = buildSessionEntries(
|
|
32404
32662
|
options.allStates,
|
|
32405
|
-
options.cdpManagers
|
|
32663
|
+
options.cdpManagers,
|
|
32664
|
+
{ profile: "full" }
|
|
32406
32665
|
);
|
|
32407
|
-
|
|
32408
|
-
|
|
32409
|
-
|
|
32410
|
-
|
|
32411
|
-
|
|
32412
|
-
|
|
32413
|
-
|
|
32414
|
-
|
|
32666
|
+
const sessions = profile === "full" ? unreadSourceSessions : buildSessionEntries(
|
|
32667
|
+
options.allStates,
|
|
32668
|
+
options.cdpManagers,
|
|
32669
|
+
{ profile }
|
|
32670
|
+
);
|
|
32671
|
+
const sessionsById = new Map(sessions.map((session) => [session.id, session]));
|
|
32672
|
+
for (const sourceSession of unreadSourceSessions) {
|
|
32673
|
+
const session = sessionsById.get(sourceSession.id);
|
|
32674
|
+
if (!session) continue;
|
|
32675
|
+
const lastSeenAt = getSessionSeenAt(state, sourceSession.id);
|
|
32676
|
+
const seenCompletionMarker = getSessionSeenMarker(state, sourceSession.id);
|
|
32677
|
+
const lastUsedAt = getSessionLastUsedAt(sourceSession);
|
|
32678
|
+
const completionMarker = getSessionCompletionMarker(sourceSession);
|
|
32679
|
+
const { unread, inboxBucket } = sourceSession.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
|
|
32680
|
+
getSessionMessageUpdatedAt(sourceSession) > 0,
|
|
32681
|
+
sourceSession.status,
|
|
32415
32682
|
lastUsedAt,
|
|
32416
32683
|
lastSeenAt,
|
|
32417
|
-
getLastMessageRole(
|
|
32684
|
+
getLastMessageRole(sourceSession),
|
|
32418
32685
|
completionMarker,
|
|
32419
32686
|
seenCompletionMarker
|
|
32420
32687
|
);
|
|
@@ -32424,39 +32691,30 @@ function buildStatusSnapshot(options) {
|
|
|
32424
32691
|
if (READ_DEBUG_ENABLED && (session.unread || session.inboxBucket !== "idle" || session.providerType.includes("codex"))) {
|
|
32425
32692
|
LOG.info(
|
|
32426
32693
|
"RecentRead",
|
|
32427
|
-
`snapshot session id=${session.id} provider=${session.providerType} status=${String(session.status || "")} bucket=${inboxBucket} unread=${String(unread)} lastSeenAt=${lastSeenAt} completionMarker=${completionMarker || "-"} seenMarker=${seenCompletionMarker || "-"} lastUpdated=${String(session.lastUpdated || 0)} lastUsedAt=${lastUsedAt} lastRole=${getLastMessageRole(
|
|
32694
|
+
`snapshot session id=${session.id} provider=${session.providerType} status=${String(session.status || "")} bucket=${inboxBucket} unread=${String(unread)} lastSeenAt=${lastSeenAt} completionMarker=${completionMarker || "-"} seenMarker=${seenCompletionMarker || "-"} lastUpdated=${String(session.lastUpdated || 0)} lastUsedAt=${lastUsedAt} lastRole=${getLastMessageRole(sourceSession)} msgUpdatedAt=${getSessionMessageUpdatedAt(sourceSession)}`
|
|
32428
32695
|
);
|
|
32429
32696
|
}
|
|
32430
32697
|
}
|
|
32431
|
-
const
|
|
32698
|
+
const includeMachineMetadata = profile !== "live";
|
|
32699
|
+
const terminalBackend = includeMachineMetadata ? getTerminalBackendRuntimeStatus() : void 0;
|
|
32432
32700
|
return {
|
|
32433
32701
|
instanceId: options.instanceId,
|
|
32434
|
-
version: options.version,
|
|
32435
|
-
|
|
32436
|
-
|
|
32437
|
-
hostname: os17.hostname(),
|
|
32438
|
-
platform: os17.platform(),
|
|
32439
|
-
arch: os17.arch(),
|
|
32440
|
-
cpus: os17.cpus().length,
|
|
32441
|
-
totalMem: memSnap.totalMem,
|
|
32442
|
-
freeMem: memSnap.freeMem,
|
|
32443
|
-
availableMem: memSnap.availableMem,
|
|
32444
|
-
loadavg: os17.loadavg(),
|
|
32445
|
-
uptime: os17.uptime(),
|
|
32446
|
-
release: os17.release()
|
|
32447
|
-
},
|
|
32448
|
-
machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
|
|
32702
|
+
...includeMachineMetadata ? { version: options.version } : {},
|
|
32703
|
+
machine: buildMachineInfo(profile),
|
|
32704
|
+
...includeMachineMetadata ? { machineNickname: options.machineNickname ?? cfg.machineNickname ?? null } : {},
|
|
32449
32705
|
timestamp: options.timestamp ?? Date.now(),
|
|
32450
|
-
detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
|
|
32451
32706
|
...options.p2p ? { p2p: options.p2p } : {},
|
|
32452
32707
|
sessions,
|
|
32453
|
-
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
|
|
32458
|
-
|
|
32459
|
-
|
|
32708
|
+
...terminalBackend ? { terminalBackend } : {},
|
|
32709
|
+
...includeMachineMetadata && {
|
|
32710
|
+
detectedIdes: buildDetectedIdeInfos(options.detectedIdes, options.cdpManagers),
|
|
32711
|
+
workspaces: wsState.workspaces,
|
|
32712
|
+
defaultWorkspaceId: wsState.defaultWorkspaceId,
|
|
32713
|
+
defaultWorkspacePath: wsState.defaultWorkspacePath,
|
|
32714
|
+
terminalSizingMode: cfg.terminalSizingMode || "measured",
|
|
32715
|
+
recentLaunches: buildRecentLaunches(recentActivity),
|
|
32716
|
+
availableProviders: buildAvailableProviders(options.providerLoader)
|
|
32717
|
+
}
|
|
32460
32718
|
};
|
|
32461
32719
|
}
|
|
32462
32720
|
var os17, READ_DEBUG_ENABLED;
|
|
@@ -32727,6 +32985,7 @@ var init_router = __esm({
|
|
|
32727
32985
|
init_logger();
|
|
32728
32986
|
init_builders();
|
|
32729
32987
|
init_snapshot();
|
|
32988
|
+
init_snapshot();
|
|
32730
32989
|
init_upgrade_helper();
|
|
32731
32990
|
fs9 = __toESM(require("fs"));
|
|
32732
32991
|
CHAT_COMMANDS = [
|
|
@@ -33055,6 +33314,25 @@ var init_router = __esm({
|
|
|
33055
33314
|
updateConfig({ userName: name });
|
|
33056
33315
|
return { success: true, userName: name };
|
|
33057
33316
|
}
|
|
33317
|
+
case "get_status_metadata": {
|
|
33318
|
+
const snapshot = buildStatusSnapshot({
|
|
33319
|
+
allStates: this.deps.instanceManager.collectAllStates(),
|
|
33320
|
+
cdpManagers: this.deps.cdpManagers,
|
|
33321
|
+
providerLoader: this.deps.providerLoader,
|
|
33322
|
+
detectedIdes: this.deps.detectedIdes.value,
|
|
33323
|
+
instanceId: this.deps.statusInstanceId || loadConfig().machineId || "daemon",
|
|
33324
|
+
version: this.deps.statusVersion || "unknown",
|
|
33325
|
+
profile: "metadata"
|
|
33326
|
+
});
|
|
33327
|
+
return { success: true, status: snapshot };
|
|
33328
|
+
}
|
|
33329
|
+
case "get_machine_runtime_stats": {
|
|
33330
|
+
return {
|
|
33331
|
+
success: true,
|
|
33332
|
+
machine: buildMachineInfo("full"),
|
|
33333
|
+
timestamp: Date.now()
|
|
33334
|
+
};
|
|
33335
|
+
}
|
|
33058
33336
|
case "mark_session_seen": {
|
|
33059
33337
|
const sessionId = args?.sessionId;
|
|
33060
33338
|
if (!sessionId || typeof sessionId !== "string") {
|
|
@@ -33216,6 +33494,7 @@ var init_reporter = __esm({
|
|
|
33216
33494
|
lastStatusSentAt = 0;
|
|
33217
33495
|
statusPendingThrottle = false;
|
|
33218
33496
|
lastP2PStatusHash = "";
|
|
33497
|
+
lastServerStatusHash = "";
|
|
33219
33498
|
lastStatusSummary = "";
|
|
33220
33499
|
statusTimer = null;
|
|
33221
33500
|
p2pTimer = null;
|
|
@@ -33226,11 +33505,11 @@ var init_reporter = __esm({
|
|
|
33226
33505
|
// ─── Lifecycle ───────────────────────────────────
|
|
33227
33506
|
startReporting() {
|
|
33228
33507
|
setTimeout(() => {
|
|
33229
|
-
this.sendUnifiedStatusReport().catch((e) => LOG.warn("Status", `Initial report failed: ${e?.message}`));
|
|
33508
|
+
this.sendUnifiedStatusReport({ forceServer: true, reason: "initial" }).catch((e) => LOG.warn("Status", `Initial report failed: ${e?.message}`));
|
|
33230
33509
|
}, 2e3);
|
|
33231
33510
|
const scheduleServerReport = () => {
|
|
33232
33511
|
this.statusTimer = setTimeout(() => {
|
|
33233
|
-
this.sendUnifiedStatusReport().catch((e) => LOG.warn("Status", `Periodic report failed: ${e?.message}`));
|
|
33512
|
+
this.sendUnifiedStatusReport({ forceServer: true, reason: "periodic" }).catch((e) => LOG.warn("Status", `Periodic report failed: ${e?.message}`));
|
|
33234
33513
|
scheduleServerReport();
|
|
33235
33514
|
}, 3e4);
|
|
33236
33515
|
};
|
|
@@ -33267,9 +33546,58 @@ var init_reporter = __esm({
|
|
|
33267
33546
|
}, 5e3 - elapsed);
|
|
33268
33547
|
}
|
|
33269
33548
|
}
|
|
33549
|
+
toDaemonStatusEventName(value) {
|
|
33550
|
+
switch (value) {
|
|
33551
|
+
case "agent:generating_started":
|
|
33552
|
+
case "agent:waiting_approval":
|
|
33553
|
+
case "agent:generating_completed":
|
|
33554
|
+
case "agent:stopped":
|
|
33555
|
+
case "monitor:long_generating":
|
|
33556
|
+
return value;
|
|
33557
|
+
default:
|
|
33558
|
+
return null;
|
|
33559
|
+
}
|
|
33560
|
+
}
|
|
33561
|
+
buildServerStatusEvent(event) {
|
|
33562
|
+
const eventName = this.toDaemonStatusEventName(event.event);
|
|
33563
|
+
if (!eventName) return null;
|
|
33564
|
+
if (eventName.startsWith("provider:")) {
|
|
33565
|
+
return null;
|
|
33566
|
+
}
|
|
33567
|
+
const payload = {
|
|
33568
|
+
event: eventName,
|
|
33569
|
+
timestamp: typeof event.timestamp === "number" && Number.isFinite(event.timestamp) ? event.timestamp : Date.now()
|
|
33570
|
+
};
|
|
33571
|
+
if (typeof event.targetSessionId === "string" && event.targetSessionId.trim()) {
|
|
33572
|
+
payload.targetSessionId = event.targetSessionId.trim();
|
|
33573
|
+
}
|
|
33574
|
+
const providerType = typeof event.providerType === "string" && event.providerType.trim() ? event.providerType.trim() : typeof event.ideType === "string" && event.ideType.trim() ? event.ideType.trim() : "";
|
|
33575
|
+
if (providerType) {
|
|
33576
|
+
payload.providerType = providerType;
|
|
33577
|
+
}
|
|
33578
|
+
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
33579
|
+
payload.duration = event.duration;
|
|
33580
|
+
}
|
|
33581
|
+
if (typeof event.elapsedSec === "number" && Number.isFinite(event.elapsedSec)) {
|
|
33582
|
+
payload.elapsedSec = event.elapsedSec;
|
|
33583
|
+
}
|
|
33584
|
+
if (typeof event.modalMessage === "string" && event.modalMessage.trim()) {
|
|
33585
|
+
payload.modalMessage = event.modalMessage;
|
|
33586
|
+
}
|
|
33587
|
+
if (Array.isArray(event.modalButtons)) {
|
|
33588
|
+
const modalButtons = event.modalButtons.filter((button) => typeof button === "string" && button.trim().length > 0);
|
|
33589
|
+
if (modalButtons.length > 0) {
|
|
33590
|
+
payload.modalButtons = modalButtons;
|
|
33591
|
+
}
|
|
33592
|
+
}
|
|
33593
|
+
return payload;
|
|
33594
|
+
}
|
|
33270
33595
|
emitStatusEvent(event) {
|
|
33271
33596
|
LOG.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
|
|
33272
|
-
this.
|
|
33597
|
+
const serverEvent = this.buildServerStatusEvent(event);
|
|
33598
|
+
if (!serverEvent) return;
|
|
33599
|
+
this.deps.p2p?.sendStatusEvent(serverEvent);
|
|
33600
|
+
this.deps.serverConn?.sendMessage("status_event", serverEvent);
|
|
33273
33601
|
}
|
|
33274
33602
|
removeAgentTracking(_key) {
|
|
33275
33603
|
}
|
|
@@ -33338,17 +33666,16 @@ var init_reporter = __esm({
|
|
|
33338
33666
|
detectedIdes: this.deps.detectedIdes || [],
|
|
33339
33667
|
instanceId: this.deps.instanceId,
|
|
33340
33668
|
version: this.deps.daemonVersion || "unknown",
|
|
33341
|
-
daemonMode: true,
|
|
33342
33669
|
timestamp: now,
|
|
33343
33670
|
p2p: {
|
|
33344
33671
|
available: p2p?.isAvailable || false,
|
|
33345
33672
|
state: p2p?.connectionState || "unavailable",
|
|
33346
33673
|
peers: p2p?.connectedPeerCount || 0,
|
|
33347
33674
|
screenshotActive: p2p?.screenshotActive || false
|
|
33348
|
-
}
|
|
33675
|
+
},
|
|
33676
|
+
profile: "live"
|
|
33349
33677
|
}),
|
|
33350
|
-
screenshotUsage: this.deps.getScreenshotUsage?.() || null
|
|
33351
|
-
connectedExtensions: []
|
|
33678
|
+
screenshotUsage: this.deps.getScreenshotUsage?.() || null
|
|
33352
33679
|
};
|
|
33353
33680
|
const payloadBytes = JSON.stringify(payload).length;
|
|
33354
33681
|
const p2pSent = this.sendP2PPayload(payload);
|
|
@@ -33363,46 +33690,48 @@ var init_reporter = __esm({
|
|
|
33363
33690
|
}
|
|
33364
33691
|
if (opts?.p2pOnly) return;
|
|
33365
33692
|
const wsPayload = {
|
|
33366
|
-
daemonMode: true,
|
|
33367
33693
|
sessions: sessions.map((session) => ({
|
|
33368
33694
|
id: session.id,
|
|
33369
33695
|
parentId: session.parentId,
|
|
33370
33696
|
providerType: session.providerType,
|
|
33371
|
-
providerName: session.providerName,
|
|
33697
|
+
providerName: session.providerName || session.providerType,
|
|
33372
33698
|
kind: session.kind,
|
|
33373
33699
|
transport: session.transport,
|
|
33374
33700
|
status: session.status,
|
|
33375
|
-
workspace: session.workspace,
|
|
33701
|
+
workspace: session.workspace ?? null,
|
|
33376
33702
|
title: session.title,
|
|
33377
33703
|
cdpConnected: session.cdpConnected,
|
|
33378
33704
|
currentModel: session.currentModel,
|
|
33379
33705
|
currentPlan: session.currentPlan,
|
|
33380
|
-
currentAutoApprove: session.currentAutoApprove
|
|
33381
|
-
lastUpdated: session.lastUpdated,
|
|
33382
|
-
unread: session.unread,
|
|
33383
|
-
lastSeenAt: session.lastSeenAt,
|
|
33384
|
-
inboxBucket: session.inboxBucket,
|
|
33385
|
-
surfaceHidden: session.surfaceHidden,
|
|
33386
|
-
controlValues: session.controlValues,
|
|
33387
|
-
providerControls: session.providerControls,
|
|
33388
|
-
acpConfigOptions: session.acpConfigOptions,
|
|
33389
|
-
acpModes: session.acpModes
|
|
33706
|
+
currentAutoApprove: session.currentAutoApprove
|
|
33390
33707
|
})),
|
|
33391
33708
|
p2p: payload.p2p,
|
|
33392
|
-
timestamp: now
|
|
33393
|
-
detectedIdes: payload.detectedIdes,
|
|
33394
|
-
availableProviders: payload.availableProviders
|
|
33709
|
+
timestamp: now
|
|
33395
33710
|
};
|
|
33711
|
+
const wsHash = this.simpleHash(JSON.stringify({
|
|
33712
|
+
...wsPayload,
|
|
33713
|
+
timestamp: void 0
|
|
33714
|
+
}));
|
|
33715
|
+
if (!opts?.forceServer && wsHash === this.lastServerStatusHash) {
|
|
33716
|
+
LOG.debug("Server", `skip duplicate status_report${opts?.reason ? ` (${opts.reason})` : ""}`);
|
|
33717
|
+
return;
|
|
33718
|
+
}
|
|
33719
|
+
this.lastServerStatusHash = wsHash;
|
|
33396
33720
|
serverConn.sendMessage("status_report", wsPayload);
|
|
33397
|
-
LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
|
|
33721
|
+
LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)${opts?.reason ? ` [${opts.reason}]` : ""}`);
|
|
33398
33722
|
}
|
|
33399
33723
|
// ─── P2P ─────────────────────────────────────────
|
|
33400
33724
|
sendP2PPayload(payload) {
|
|
33401
33725
|
const { timestamp: _ts, system: _sys, ...hashTarget } = payload;
|
|
33726
|
+
const sessions = Array.isArray(hashTarget.sessions) ? hashTarget.sessions.map((session) => {
|
|
33727
|
+
if (!session || typeof session !== "object") return session;
|
|
33728
|
+
const { lastUpdated: _lu, ...stableSession } = session;
|
|
33729
|
+
return stableSession;
|
|
33730
|
+
}) : hashTarget.sessions;
|
|
33402
33731
|
const hashPayload = hashTarget.machine ? (() => {
|
|
33403
33732
|
const { freeMem: _f, availableMem: _a2, loadavg: _l, uptime: _u, ...stableMachine } = hashTarget.machine;
|
|
33404
|
-
return { ...hashTarget, machine: stableMachine };
|
|
33405
|
-
})() : hashTarget;
|
|
33733
|
+
return { ...hashTarget, sessions, machine: stableMachine };
|
|
33734
|
+
})() : { ...hashTarget, sessions };
|
|
33406
33735
|
const h = this.simpleHash(JSON.stringify(hashPayload));
|
|
33407
33736
|
if (h !== this.lastP2PStatusHash) {
|
|
33408
33737
|
this.lastP2PStatusHash = h;
|
|
@@ -40613,6 +40942,8 @@ async function initDaemonComponents(config2) {
|
|
|
40613
40942
|
onStatusChange: config2.onStatusChange,
|
|
40614
40943
|
onPostChatCommand: config2.onPostChatCommand,
|
|
40615
40944
|
sessionHostControl: config2.sessionHostControl,
|
|
40945
|
+
statusInstanceId: config2.statusInstanceId,
|
|
40946
|
+
statusVersion: config2.statusVersion,
|
|
40616
40947
|
getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
|
|
40617
40948
|
});
|
|
40618
40949
|
poller = new AgentStreamPoller({
|
|
@@ -40738,6 +41069,7 @@ __export(src_exports, {
|
|
|
40738
41069
|
SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
|
|
40739
41070
|
VersionArchive: () => VersionArchive,
|
|
40740
41071
|
appendRecentActivity: () => appendRecentActivity,
|
|
41072
|
+
buildMachineInfo: () => buildMachineInfo,
|
|
40741
41073
|
buildSessionEntries: () => buildSessionEntries,
|
|
40742
41074
|
buildStatusSnapshot: () => buildStatusSnapshot,
|
|
40743
41075
|
connectCdpManager: () => connectCdpManager,
|
|
@@ -40990,6 +41322,7 @@ var init_server_connection = __esm({
|
|
|
40990
41322
|
reconnectTimer = null;
|
|
40991
41323
|
pingTimer = null;
|
|
40992
41324
|
pongTimeout = null;
|
|
41325
|
+
missedPongCount = 0;
|
|
40993
41326
|
messageHandlers = /* @__PURE__ */ new Map();
|
|
40994
41327
|
stateChangeCallbacks = [];
|
|
40995
41328
|
/** Fallback handler for message types without specific on() registration */
|
|
@@ -41010,6 +41343,7 @@ var init_server_connection = __esm({
|
|
|
41010
41343
|
this.ws = new import_ws2.default(fullUrl, {
|
|
41011
41344
|
headers: {
|
|
41012
41345
|
"X-ADHDev-Token": this.options.token,
|
|
41346
|
+
"X-ADHDev-Daemon": JSON.stringify(this.options.cliInfo),
|
|
41013
41347
|
"X-ADHDev-IDE": JSON.stringify(this.options.cliInfo),
|
|
41014
41348
|
"X-ADHDev-Version": this.options.daemonVersion || "unknown"
|
|
41015
41349
|
}
|
|
@@ -41088,18 +41422,21 @@ var init_server_connection = __esm({
|
|
|
41088
41422
|
// --- Private ---
|
|
41089
41423
|
onOpen() {
|
|
41090
41424
|
LOG.info("Server", `[ServerConn] WebSocket open, sending auth...`);
|
|
41425
|
+
this.missedPongCount = 0;
|
|
41091
41426
|
this.setState("authenticating");
|
|
41092
41427
|
this.send({
|
|
41093
41428
|
type: "auth",
|
|
41094
41429
|
payload: {
|
|
41095
41430
|
token: this.options.token,
|
|
41096
|
-
|
|
41431
|
+
daemon: this.options.cliInfo
|
|
41097
41432
|
},
|
|
41098
41433
|
timestamp: Date.now()
|
|
41099
41434
|
});
|
|
41100
41435
|
}
|
|
41101
41436
|
onMessage(text) {
|
|
41102
41437
|
try {
|
|
41438
|
+
this.clearPongTimeout();
|
|
41439
|
+
this.missedPongCount = 0;
|
|
41103
41440
|
const message = JSON.parse(text);
|
|
41104
41441
|
if (message.type === "auth_ok") {
|
|
41105
41442
|
this.reconnectAttempts = 0;
|
|
@@ -41200,6 +41537,7 @@ var init_server_connection = __esm({
|
|
|
41200
41537
|
this.reconnectTimer = null;
|
|
41201
41538
|
}
|
|
41202
41539
|
this.stopHeartbeat();
|
|
41540
|
+
this.missedPongCount = 0;
|
|
41203
41541
|
}
|
|
41204
41542
|
// ─── WS Heartbeat (ping/pong) ─────────────────────
|
|
41205
41543
|
startHeartbeat() {
|
|
@@ -41209,9 +41547,14 @@ var init_server_connection = __esm({
|
|
|
41209
41547
|
try {
|
|
41210
41548
|
this.ws.ping();
|
|
41211
41549
|
this.pongTimeout = setTimeout(() => {
|
|
41212
|
-
|
|
41213
|
-
|
|
41550
|
+
this.pongTimeout = null;
|
|
41551
|
+
this.missedPongCount += 1;
|
|
41552
|
+
const misses = this.missedPongCount;
|
|
41553
|
+
if (misses >= 3 && this.ws) {
|
|
41554
|
+
LOG.warn("Server", `[ServerConn] Pong timeout (${misses}x) \u2014 closing stale WS`);
|
|
41214
41555
|
this.ws.terminate();
|
|
41556
|
+
} else {
|
|
41557
|
+
LOG.warn("Server", `[ServerConn] Pong timeout (${misses}x) \u2014 keeping WS open and retrying`);
|
|
41215
41558
|
}
|
|
41216
41559
|
}, 15e3);
|
|
41217
41560
|
} catch {
|
|
@@ -41223,12 +41566,13 @@ var init_server_connection = __esm({
|
|
|
41223
41566
|
clearInterval(this.pingTimer);
|
|
41224
41567
|
this.pingTimer = null;
|
|
41225
41568
|
}
|
|
41226
|
-
|
|
41227
|
-
clearTimeout(this.pongTimeout);
|
|
41228
|
-
this.pongTimeout = null;
|
|
41229
|
-
}
|
|
41569
|
+
this.clearPongTimeout();
|
|
41230
41570
|
}
|
|
41231
41571
|
onPong() {
|
|
41572
|
+
this.clearPongTimeout();
|
|
41573
|
+
this.missedPongCount = 0;
|
|
41574
|
+
}
|
|
41575
|
+
clearPongTimeout() {
|
|
41232
41576
|
if (this.pongTimeout) {
|
|
41233
41577
|
clearTimeout(this.pongTimeout);
|
|
41234
41578
|
this.pongTimeout = null;
|
|
@@ -41324,11 +41668,19 @@ function routeDataChannelMessage(peerId, msg, peers, handlers) {
|
|
|
41324
41668
|
if (peer) peer.lastPongAt = Date.now();
|
|
41325
41669
|
return;
|
|
41326
41670
|
}
|
|
41671
|
+
if (parsed.type === "subscribe") {
|
|
41672
|
+
handleSubscribe(peerId, parsed, peers, handlers);
|
|
41673
|
+
return;
|
|
41674
|
+
}
|
|
41675
|
+
if (parsed.type === "unsubscribe") {
|
|
41676
|
+
handleUnsubscribe(peerId, parsed, peers);
|
|
41677
|
+
return;
|
|
41678
|
+
}
|
|
41327
41679
|
if (parsed.type === "screenshot_start") {
|
|
41328
41680
|
const peer = peers.get(peerId);
|
|
41329
41681
|
const permission = peer?.sharePermission;
|
|
41330
|
-
if (!parsed.
|
|
41331
|
-
log(`screenshot_start: REJECTED \u2014 no
|
|
41682
|
+
if (!parsed.targetSessionId) {
|
|
41683
|
+
log(`screenshot_start: REJECTED \u2014 no targetSessionId from peer ${peerId}`);
|
|
41332
41684
|
return;
|
|
41333
41685
|
}
|
|
41334
41686
|
if (!canPeerStartScreenshots(permission)) {
|
|
@@ -41337,9 +41689,9 @@ function routeDataChannelMessage(peerId, msg, peers, handlers) {
|
|
|
41337
41689
|
}
|
|
41338
41690
|
if (peer) {
|
|
41339
41691
|
peer.screenshotActive = true;
|
|
41340
|
-
peer.
|
|
41692
|
+
peer.screenshotTargetSessionId = parsed.targetSessionId;
|
|
41341
41693
|
peer.needsFirstFrame = true;
|
|
41342
|
-
log(`screenshot_start: peer=${peerId},
|
|
41694
|
+
log(`screenshot_start: peer=${peerId}, targetSessionId=${parsed.targetSessionId}, channelOpen=${!!peer.dataChannel}, state=${peer.state}`);
|
|
41343
41695
|
handlers.screenshotStartHandler?.();
|
|
41344
41696
|
} else {
|
|
41345
41697
|
log(`screenshot_start: peer ${peerId} NOT FOUND in peers map!`);
|
|
@@ -41391,6 +41743,87 @@ function routeDataChannelMessage(peerId, msg, peers, handlers) {
|
|
|
41391
41743
|
log(`Parse error from peer ${peerId}: ${e?.message}`);
|
|
41392
41744
|
}
|
|
41393
41745
|
}
|
|
41746
|
+
function handleSubscribe(peerId, msg, peers, handlers) {
|
|
41747
|
+
const peer = peers.get(peerId);
|
|
41748
|
+
if (!peer) return;
|
|
41749
|
+
if (msg.topic === "session.chat_tail") {
|
|
41750
|
+
const targetSessionId = typeof msg.params?.targetSessionId === "string" ? msg.params.targetSessionId.trim() : "";
|
|
41751
|
+
if (!targetSessionId) return;
|
|
41752
|
+
if (!peer.chatSubscriptions) peer.chatSubscriptions = /* @__PURE__ */ new Map();
|
|
41753
|
+
peer.chatSubscriptions.set(msg.key, {
|
|
41754
|
+
key: msg.key,
|
|
41755
|
+
params: msg.params,
|
|
41756
|
+
seq: 0,
|
|
41757
|
+
cursor: {
|
|
41758
|
+
knownMessageCount: Math.max(0, Number(msg.params.knownMessageCount || 0)),
|
|
41759
|
+
lastMessageSignature: typeof msg.params.lastMessageSignature === "string" ? msg.params.lastMessageSignature : "",
|
|
41760
|
+
tailLimit: Math.max(0, Number(msg.params.tailLimit || 0))
|
|
41761
|
+
},
|
|
41762
|
+
lastDeliveredSignature: ""
|
|
41763
|
+
});
|
|
41764
|
+
} else if (msg.topic === "machine.runtime") {
|
|
41765
|
+
if (!peer.machineRuntimeSubscriptions) peer.machineRuntimeSubscriptions = /* @__PURE__ */ new Map();
|
|
41766
|
+
peer.machineRuntimeSubscriptions.set(msg.key, {
|
|
41767
|
+
key: msg.key,
|
|
41768
|
+
params: msg.params,
|
|
41769
|
+
seq: 0,
|
|
41770
|
+
lastSentAt: 0
|
|
41771
|
+
});
|
|
41772
|
+
} else if (msg.topic === "session_host.diagnostics") {
|
|
41773
|
+
if (!peer.sessionHostDiagnosticsSubscriptions) peer.sessionHostDiagnosticsSubscriptions = /* @__PURE__ */ new Map();
|
|
41774
|
+
peer.sessionHostDiagnosticsSubscriptions.set(msg.key, {
|
|
41775
|
+
key: msg.key,
|
|
41776
|
+
params: msg.params,
|
|
41777
|
+
seq: 0,
|
|
41778
|
+
lastSentAt: 0
|
|
41779
|
+
});
|
|
41780
|
+
} else if (msg.topic === "session.modal") {
|
|
41781
|
+
const targetSessionId = typeof msg.params?.targetSessionId === "string" ? msg.params.targetSessionId.trim() : "";
|
|
41782
|
+
if (!targetSessionId) return;
|
|
41783
|
+
if (!peer.sessionModalSubscriptions) peer.sessionModalSubscriptions = /* @__PURE__ */ new Map();
|
|
41784
|
+
peer.sessionModalSubscriptions.set(msg.key, {
|
|
41785
|
+
key: msg.key,
|
|
41786
|
+
params: msg.params,
|
|
41787
|
+
seq: 0,
|
|
41788
|
+
lastSentAt: 0,
|
|
41789
|
+
lastDeliveredSignature: ""
|
|
41790
|
+
});
|
|
41791
|
+
} else if (msg.topic === "daemon.metadata") {
|
|
41792
|
+
if (!peer.daemonMetadataSubscriptions) peer.daemonMetadataSubscriptions = /* @__PURE__ */ new Map();
|
|
41793
|
+
peer.daemonMetadataSubscriptions.set(msg.key, {
|
|
41794
|
+
key: msg.key,
|
|
41795
|
+
params: msg.params,
|
|
41796
|
+
seq: 0,
|
|
41797
|
+
lastSentAt: 0
|
|
41798
|
+
});
|
|
41799
|
+
} else {
|
|
41800
|
+
return;
|
|
41801
|
+
}
|
|
41802
|
+
handlers.subscriptionChangeHandler?.();
|
|
41803
|
+
}
|
|
41804
|
+
function handleUnsubscribe(peerId, msg, peers) {
|
|
41805
|
+
const peer = peers.get(peerId);
|
|
41806
|
+
if (!peer) return;
|
|
41807
|
+
if (msg.topic === "session.chat_tail") {
|
|
41808
|
+
peer.chatSubscriptions?.delete(msg.key);
|
|
41809
|
+
return;
|
|
41810
|
+
}
|
|
41811
|
+
if (msg.topic === "machine.runtime") {
|
|
41812
|
+
peer.machineRuntimeSubscriptions?.delete(msg.key);
|
|
41813
|
+
return;
|
|
41814
|
+
}
|
|
41815
|
+
if (msg.topic === "session_host.diagnostics") {
|
|
41816
|
+
peer.sessionHostDiagnosticsSubscriptions?.delete(msg.key);
|
|
41817
|
+
return;
|
|
41818
|
+
}
|
|
41819
|
+
if (msg.topic === "session.modal") {
|
|
41820
|
+
peer.sessionModalSubscriptions?.delete(msg.key);
|
|
41821
|
+
return;
|
|
41822
|
+
}
|
|
41823
|
+
if (msg.topic === "daemon.metadata") {
|
|
41824
|
+
peer.daemonMetadataSubscriptions?.delete(msg.key);
|
|
41825
|
+
}
|
|
41826
|
+
}
|
|
41394
41827
|
async function handleP2PCommand(peerId, msg, peers, handlers) {
|
|
41395
41828
|
const { id, commandType, data } = msg;
|
|
41396
41829
|
const peer = peers.get(peerId);
|
|
@@ -41411,7 +41844,7 @@ async function handleP2PCommand(peerId, msg, peers, handlers) {
|
|
|
41411
41844
|
}
|
|
41412
41845
|
}
|
|
41413
41846
|
async function handleInputEvent(peerId, msg, peers, handlers) {
|
|
41414
|
-
const { id, action, params,
|
|
41847
|
+
const { id, action, params, targetSessionId: explicitTargetSessionId } = msg;
|
|
41415
41848
|
const peer = peers.get(peerId);
|
|
41416
41849
|
const permission = peer?.sharePermission;
|
|
41417
41850
|
if (!canPeerUseRemoteInput(permission)) {
|
|
@@ -41423,11 +41856,11 @@ async function handleInputEvent(peerId, msg, peers, handlers) {
|
|
|
41423
41856
|
return;
|
|
41424
41857
|
}
|
|
41425
41858
|
try {
|
|
41426
|
-
const
|
|
41427
|
-
if (!
|
|
41428
|
-
log(`[Input] WARNING: No
|
|
41859
|
+
const targetSessionId = explicitTargetSessionId || peer?.screenshotTargetSessionId;
|
|
41860
|
+
if (!targetSessionId) {
|
|
41861
|
+
log(`[Input] WARNING: No targetSessionId for peer ${peerId}`);
|
|
41429
41862
|
}
|
|
41430
|
-
const result = await handlers.inputHandler({ action, params,
|
|
41863
|
+
const result = await handlers.inputHandler({ action, params, targetSessionId });
|
|
41431
41864
|
sendToPeer(peer, { id, type: "response", success: true, result });
|
|
41432
41865
|
} catch (e) {
|
|
41433
41866
|
sendToPeer(peer, { id, type: "response", success: false, error: e?.message });
|
|
@@ -41486,6 +41919,35 @@ var init_screenshot_sender = __esm({
|
|
|
41486
41919
|
}
|
|
41487
41920
|
return sentAny;
|
|
41488
41921
|
}
|
|
41922
|
+
sendStatusEvent(peers, event) {
|
|
41923
|
+
const payload = JSON.stringify({
|
|
41924
|
+
type: "status_event",
|
|
41925
|
+
payload: event,
|
|
41926
|
+
timestamp: Date.now()
|
|
41927
|
+
});
|
|
41928
|
+
let sentAny = false;
|
|
41929
|
+
for (const peer of peers.values()) {
|
|
41930
|
+
if (peer.state !== "connected" || !peer.dataChannel) continue;
|
|
41931
|
+
try {
|
|
41932
|
+
peer.dataChannel.sendMessage(payload);
|
|
41933
|
+
sentAny = true;
|
|
41934
|
+
} catch {
|
|
41935
|
+
}
|
|
41936
|
+
}
|
|
41937
|
+
return sentAny;
|
|
41938
|
+
}
|
|
41939
|
+
sendTopicUpdateToPeer(peer, update) {
|
|
41940
|
+
if (!peer?.dataChannel || peer.state !== "connected") return false;
|
|
41941
|
+
try {
|
|
41942
|
+
peer.dataChannel.sendMessage(JSON.stringify({
|
|
41943
|
+
type: "topic_update",
|
|
41944
|
+
update
|
|
41945
|
+
}));
|
|
41946
|
+
return true;
|
|
41947
|
+
} catch {
|
|
41948
|
+
return false;
|
|
41949
|
+
}
|
|
41950
|
+
}
|
|
41489
41951
|
/** Broadcast runtime session output to all connected peers */
|
|
41490
41952
|
broadcastSessionOutput(peers, sessionId, data) {
|
|
41491
41953
|
const msg = JSON.stringify({ type: "session_output", sessionId, data });
|
|
@@ -41578,8 +42040,14 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
41578
42040
|
}
|
|
41579
42041
|
const pid = peerId || `legacy_${Date.now()}`;
|
|
41580
42042
|
const existing = deps.peers.get(pid);
|
|
41581
|
-
if (existing?.state === "connected")
|
|
41582
|
-
|
|
42043
|
+
if (existing?.state === "connected") {
|
|
42044
|
+
log(`initiateconnection() ignored for peer ${pid} \u2014 already connected`);
|
|
42045
|
+
return;
|
|
42046
|
+
}
|
|
42047
|
+
if (existing?.state === "connecting") {
|
|
42048
|
+
log(`initiateconnection() ignored for peer ${pid} \u2014 connection already in progress`);
|
|
42049
|
+
return;
|
|
42050
|
+
}
|
|
41583
42051
|
log(`initiateconnection() for peer ${pid}...`);
|
|
41584
42052
|
const mod = deps.nodeDatachannel;
|
|
41585
42053
|
const PeerConnectionCtor = mod.PeerConnection || mod.default?.PeerConnection || mod.default || mod;
|
|
@@ -41641,7 +42109,12 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
41641
42109
|
pendingCandidates: [],
|
|
41642
42110
|
remoteDescriptionSet: false,
|
|
41643
42111
|
isRelay: false,
|
|
41644
|
-
lastPongAt: Date.now()
|
|
42112
|
+
lastPongAt: Date.now(),
|
|
42113
|
+
chatSubscriptions: /* @__PURE__ */ new Map(),
|
|
42114
|
+
machineRuntimeSubscriptions: /* @__PURE__ */ new Map(),
|
|
42115
|
+
sessionHostDiagnosticsSubscriptions: /* @__PURE__ */ new Map(),
|
|
42116
|
+
sessionModalSubscriptions: /* @__PURE__ */ new Map(),
|
|
42117
|
+
daemonMetadataSubscriptions: /* @__PURE__ */ new Map()
|
|
41645
42118
|
};
|
|
41646
42119
|
deps.peers.set(pid, entry);
|
|
41647
42120
|
deps.notifyStateChange();
|
|
@@ -41879,6 +42352,7 @@ var init_daemon_p2p = __esm({
|
|
|
41879
42352
|
peers = /* @__PURE__ */ new Map();
|
|
41880
42353
|
nodeDatachannel = null;
|
|
41881
42354
|
stateListeners = [];
|
|
42355
|
+
lastNotifiedState = null;
|
|
41882
42356
|
screenshotSender = new ScreenshotSender();
|
|
41883
42357
|
// Handler storage — exposed to router via DataChannelHandlers interface
|
|
41884
42358
|
handlers = {
|
|
@@ -41887,7 +42361,8 @@ var init_daemon_p2p = __esm({
|
|
|
41887
42361
|
commandHandler: null,
|
|
41888
42362
|
ptyInputHandler: null,
|
|
41889
42363
|
ptyResizeHandler: null,
|
|
41890
|
-
screenshotStartHandler: null
|
|
42364
|
+
screenshotStartHandler: null,
|
|
42365
|
+
subscriptionChangeHandler: null
|
|
41891
42366
|
};
|
|
41892
42367
|
get screenshotActive() {
|
|
41893
42368
|
for (const peer of this.peers.values()) {
|
|
@@ -41895,11 +42370,11 @@ var init_daemon_p2p = __esm({
|
|
|
41895
42370
|
}
|
|
41896
42371
|
return false;
|
|
41897
42372
|
}
|
|
41898
|
-
/** Get the
|
|
41899
|
-
get
|
|
42373
|
+
/** Get the target session for the currently active screenshot request */
|
|
42374
|
+
get screenshotTargetSessionId() {
|
|
41900
42375
|
for (const peer of this.peers.values()) {
|
|
41901
|
-
if (peer.screenshotActive && peer.state === "connected" && peer.
|
|
41902
|
-
return peer.
|
|
42376
|
+
if (peer.screenshotActive && peer.state === "connected" && peer.screenshotTargetSessionId) {
|
|
42377
|
+
return peer.screenshotTargetSessionId;
|
|
41903
42378
|
}
|
|
41904
42379
|
}
|
|
41905
42380
|
return void 0;
|
|
@@ -42016,6 +42491,8 @@ ${e?.stack || ""}`);
|
|
|
42016
42491
|
}
|
|
42017
42492
|
notifyStateChange = () => {
|
|
42018
42493
|
const state = this.connectionState;
|
|
42494
|
+
if (state === this.lastNotifiedState) return;
|
|
42495
|
+
this.lastNotifiedState = state;
|
|
42019
42496
|
this.stateListeners.forEach((fn) => fn(state));
|
|
42020
42497
|
};
|
|
42021
42498
|
get connectionManagerDeps() {
|
|
@@ -42043,11 +42520,15 @@ ${e?.stack || ""}`);
|
|
|
42043
42520
|
for (const peerId of Array.from(this.peers.keys())) {
|
|
42044
42521
|
this.disconnectPeer(peerId);
|
|
42045
42522
|
}
|
|
42523
|
+
this.lastNotifiedState = null;
|
|
42046
42524
|
}
|
|
42047
42525
|
// ─── Delegated data sending ─────────────────────
|
|
42048
42526
|
sendStatus(status) {
|
|
42049
42527
|
return this.screenshotSender.sendStatus(this.peers, status);
|
|
42050
42528
|
}
|
|
42529
|
+
sendStatusEvent(event) {
|
|
42530
|
+
return this.screenshotSender.sendStatusEvent(this.peers, event);
|
|
42531
|
+
}
|
|
42051
42532
|
broadcastSessionOutput(sessionId, data) {
|
|
42052
42533
|
return this.screenshotSender.broadcastSessionOutput(this.peers, sessionId, data);
|
|
42053
42534
|
}
|
|
@@ -42076,6 +42557,89 @@ ${e?.stack || ""}`);
|
|
|
42076
42557
|
onScreenshotStart(handler) {
|
|
42077
42558
|
this.handlers.screenshotStartHandler = handler;
|
|
42078
42559
|
}
|
|
42560
|
+
onSubscriptionChange(handler) {
|
|
42561
|
+
this.handlers.subscriptionChangeHandler = handler;
|
|
42562
|
+
}
|
|
42563
|
+
hasChatSubscriptions() {
|
|
42564
|
+
for (const peer of this.peers.values()) {
|
|
42565
|
+
if (peer.chatSubscriptions && peer.chatSubscriptions.size > 0) return true;
|
|
42566
|
+
}
|
|
42567
|
+
return false;
|
|
42568
|
+
}
|
|
42569
|
+
hasMachineRuntimeSubscriptions() {
|
|
42570
|
+
for (const peer of this.peers.values()) {
|
|
42571
|
+
if (peer.machineRuntimeSubscriptions && peer.machineRuntimeSubscriptions.size > 0) return true;
|
|
42572
|
+
}
|
|
42573
|
+
return false;
|
|
42574
|
+
}
|
|
42575
|
+
hasSessionHostDiagnosticsSubscriptions() {
|
|
42576
|
+
for (const peer of this.peers.values()) {
|
|
42577
|
+
if (peer.sessionHostDiagnosticsSubscriptions && peer.sessionHostDiagnosticsSubscriptions.size > 0) return true;
|
|
42578
|
+
}
|
|
42579
|
+
return false;
|
|
42580
|
+
}
|
|
42581
|
+
hasSessionModalSubscriptions() {
|
|
42582
|
+
for (const peer of this.peers.values()) {
|
|
42583
|
+
if (peer.sessionModalSubscriptions && peer.sessionModalSubscriptions.size > 0) return true;
|
|
42584
|
+
}
|
|
42585
|
+
return false;
|
|
42586
|
+
}
|
|
42587
|
+
hasDaemonMetadataSubscriptions() {
|
|
42588
|
+
for (const peer of this.peers.values()) {
|
|
42589
|
+
if (peer.daemonMetadataSubscriptions && peer.daemonMetadataSubscriptions.size > 0) return true;
|
|
42590
|
+
}
|
|
42591
|
+
return false;
|
|
42592
|
+
}
|
|
42593
|
+
async flushChatSubscriptions(builder) {
|
|
42594
|
+
for (const peer of this.peers.values()) {
|
|
42595
|
+
if (peer.state !== "connected" || !peer.chatSubscriptions || peer.chatSubscriptions.size === 0) continue;
|
|
42596
|
+
for (const subscription of peer.chatSubscriptions.values()) {
|
|
42597
|
+
const update = await builder(subscription);
|
|
42598
|
+
if (!update) continue;
|
|
42599
|
+
this.screenshotSender.sendTopicUpdateToPeer(peer, update);
|
|
42600
|
+
}
|
|
42601
|
+
}
|
|
42602
|
+
}
|
|
42603
|
+
async flushMachineRuntimeSubscriptions(builder) {
|
|
42604
|
+
for (const peer of this.peers.values()) {
|
|
42605
|
+
if (peer.state !== "connected" || !peer.machineRuntimeSubscriptions || peer.machineRuntimeSubscriptions.size === 0) continue;
|
|
42606
|
+
for (const subscription of peer.machineRuntimeSubscriptions.values()) {
|
|
42607
|
+
const update = await builder(subscription);
|
|
42608
|
+
if (!update) continue;
|
|
42609
|
+
this.screenshotSender.sendTopicUpdateToPeer(peer, update);
|
|
42610
|
+
}
|
|
42611
|
+
}
|
|
42612
|
+
}
|
|
42613
|
+
async flushSessionHostDiagnosticsSubscriptions(builder) {
|
|
42614
|
+
for (const peer of this.peers.values()) {
|
|
42615
|
+
if (peer.state !== "connected" || !peer.sessionHostDiagnosticsSubscriptions || peer.sessionHostDiagnosticsSubscriptions.size === 0) continue;
|
|
42616
|
+
for (const subscription of peer.sessionHostDiagnosticsSubscriptions.values()) {
|
|
42617
|
+
const update = await builder(subscription);
|
|
42618
|
+
if (!update) continue;
|
|
42619
|
+
this.screenshotSender.sendTopicUpdateToPeer(peer, update);
|
|
42620
|
+
}
|
|
42621
|
+
}
|
|
42622
|
+
}
|
|
42623
|
+
async flushSessionModalSubscriptions(builder) {
|
|
42624
|
+
for (const peer of this.peers.values()) {
|
|
42625
|
+
if (peer.state !== "connected" || !peer.sessionModalSubscriptions || peer.sessionModalSubscriptions.size === 0) continue;
|
|
42626
|
+
for (const subscription of peer.sessionModalSubscriptions.values()) {
|
|
42627
|
+
const update = await builder(subscription);
|
|
42628
|
+
if (!update) continue;
|
|
42629
|
+
this.screenshotSender.sendTopicUpdateToPeer(peer, update);
|
|
42630
|
+
}
|
|
42631
|
+
}
|
|
42632
|
+
}
|
|
42633
|
+
async flushDaemonMetadataSubscriptions(builder) {
|
|
42634
|
+
for (const peer of this.peers.values()) {
|
|
42635
|
+
if (peer.state !== "connected" || !peer.daemonMetadataSubscriptions || peer.daemonMetadataSubscriptions.size === 0) continue;
|
|
42636
|
+
for (const subscription of peer.daemonMetadataSubscriptions.values()) {
|
|
42637
|
+
const update = await builder(subscription);
|
|
42638
|
+
if (!update) continue;
|
|
42639
|
+
this.screenshotSender.sendTopicUpdateToPeer(peer, update);
|
|
42640
|
+
}
|
|
42641
|
+
}
|
|
42642
|
+
}
|
|
42079
42643
|
};
|
|
42080
42644
|
}
|
|
42081
42645
|
});
|
|
@@ -48736,12 +49300,12 @@ var init_screenshot_controller = __esm({
|
|
|
48736
49300
|
async tick() {
|
|
48737
49301
|
if (!this.deps.isRunning()) return;
|
|
48738
49302
|
const active = this.deps.isScreenshotActive();
|
|
48739
|
-
const
|
|
48740
|
-
if (active && !
|
|
49303
|
+
const targetSessionId = this.deps.getScreenshotTargetSessionId();
|
|
49304
|
+
if (active && !targetSessionId) {
|
|
48741
49305
|
this.timer = setTimeout(() => this.tick(), 500);
|
|
48742
49306
|
return;
|
|
48743
49307
|
}
|
|
48744
|
-
const cdp =
|
|
49308
|
+
const cdp = targetSessionId ? this.deps.getCdp(targetSessionId) : null;
|
|
48745
49309
|
const isRelay = this.deps.isUsingRelay();
|
|
48746
49310
|
const profile = isRelay ? this.profileRelay : this.profileDirect;
|
|
48747
49311
|
this.checkBudgetReset();
|
|
@@ -49272,6 +49836,48 @@ __export(adhdev_daemon_exports, {
|
|
|
49272
49836
|
isDaemonRunning: () => isDaemonRunning,
|
|
49273
49837
|
stopDaemon: () => stopDaemon
|
|
49274
49838
|
});
|
|
49839
|
+
function hashSignatureParts2(parts) {
|
|
49840
|
+
let hash2 = 2166136261;
|
|
49841
|
+
for (const part of parts) {
|
|
49842
|
+
const text = String(part || "");
|
|
49843
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
49844
|
+
hash2 ^= text.charCodeAt(i);
|
|
49845
|
+
hash2 = Math.imul(hash2, 16777619) >>> 0;
|
|
49846
|
+
}
|
|
49847
|
+
hash2 ^= 255;
|
|
49848
|
+
hash2 = Math.imul(hash2, 16777619) >>> 0;
|
|
49849
|
+
}
|
|
49850
|
+
return hash2.toString(16).padStart(8, "0");
|
|
49851
|
+
}
|
|
49852
|
+
function buildChatTailDeliverySignature(payload) {
|
|
49853
|
+
let messages = "";
|
|
49854
|
+
try {
|
|
49855
|
+
messages = JSON.stringify(payload.messages);
|
|
49856
|
+
} catch {
|
|
49857
|
+
messages = String(payload.messages.length);
|
|
49858
|
+
}
|
|
49859
|
+
return hashSignatureParts2([
|
|
49860
|
+
payload.sessionId,
|
|
49861
|
+
payload.historySessionId || "",
|
|
49862
|
+
payload.status,
|
|
49863
|
+
payload.title || "",
|
|
49864
|
+
payload.syncMode,
|
|
49865
|
+
String(payload.replaceFrom),
|
|
49866
|
+
String(payload.totalMessages),
|
|
49867
|
+
payload.lastMessageSignature,
|
|
49868
|
+
payload.activeModal ? `${payload.activeModal.message}|${payload.activeModal.buttons.join("")}` : "",
|
|
49869
|
+
messages
|
|
49870
|
+
]);
|
|
49871
|
+
}
|
|
49872
|
+
function buildSessionModalDeliverySignature(payload) {
|
|
49873
|
+
return hashSignatureParts2([
|
|
49874
|
+
payload.sessionId,
|
|
49875
|
+
payload.status,
|
|
49876
|
+
payload.title || "",
|
|
49877
|
+
payload.modalMessage || "",
|
|
49878
|
+
Array.isArray(payload.modalButtons) ? payload.modalButtons.join("") : ""
|
|
49879
|
+
]);
|
|
49880
|
+
}
|
|
49275
49881
|
function getDaemonPidFile() {
|
|
49276
49882
|
const dir = path26.join(os23.homedir(), ".adhdev");
|
|
49277
49883
|
if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
|
|
@@ -49335,7 +49941,7 @@ function stopDaemon() {
|
|
|
49335
49941
|
return false;
|
|
49336
49942
|
}
|
|
49337
49943
|
}
|
|
49338
|
-
var os23, fs17, path26, import_http, import_ws3, import_chalk2, pkgVersion, AdhdevDaemon;
|
|
49944
|
+
var os23, fs17, path26, import_http, import_ws3, import_chalk2, pkgVersion, ACTIVE_CHAT_POLL_STATUSES, AdhdevDaemon;
|
|
49339
49945
|
var init_adhdev_daemon = __esm({
|
|
49340
49946
|
"src/adhdev-daemon.ts"() {
|
|
49341
49947
|
"use strict";
|
|
@@ -49353,7 +49959,12 @@ var init_adhdev_daemon = __esm({
|
|
|
49353
49959
|
import_ws3 = require("ws");
|
|
49354
49960
|
import_chalk2 = __toESM(require("chalk"));
|
|
49355
49961
|
init_version();
|
|
49356
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.
|
|
49962
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.36" });
|
|
49963
|
+
ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
|
|
49964
|
+
"generating",
|
|
49965
|
+
"waiting_approval",
|
|
49966
|
+
"starting"
|
|
49967
|
+
]);
|
|
49357
49968
|
AdhdevDaemon = class {
|
|
49358
49969
|
localHttpServer = null;
|
|
49359
49970
|
localWss = null;
|
|
@@ -49362,6 +49973,11 @@ var init_adhdev_daemon = __esm({
|
|
|
49362
49973
|
p2p = null;
|
|
49363
49974
|
screenshotController = null;
|
|
49364
49975
|
statusReporter = null;
|
|
49976
|
+
topicSubscriptionTimer = null;
|
|
49977
|
+
p2pChatFlushInFlight = false;
|
|
49978
|
+
pendingP2PChatFlush = false;
|
|
49979
|
+
pendingP2PChatFlushOnlyActive = true;
|
|
49980
|
+
hotP2PChatSessionIds = /* @__PURE__ */ new Set();
|
|
49365
49981
|
components = null;
|
|
49366
49982
|
sessionHostEndpoint = null;
|
|
49367
49983
|
sessionHostController = null;
|
|
@@ -49385,6 +50001,252 @@ var init_adhdev_daemon = __esm({
|
|
|
49385
50001
|
const mode = this.getCliPresentationMode(sessionId);
|
|
49386
50002
|
return mode === "chat" || mode === "terminal";
|
|
49387
50003
|
}
|
|
50004
|
+
async buildChatTailUpdateForSubscription(subscription) {
|
|
50005
|
+
const result = await this.components.router.execute("read_chat", {
|
|
50006
|
+
targetSessionId: subscription.params.targetSessionId,
|
|
50007
|
+
...subscription.params.historySessionId ? { historySessionId: subscription.params.historySessionId } : {},
|
|
50008
|
+
knownMessageCount: subscription.cursor.knownMessageCount,
|
|
50009
|
+
lastMessageSignature: subscription.cursor.lastMessageSignature,
|
|
50010
|
+
...subscription.cursor.tailLimit > 0 ? { tailLimit: subscription.cursor.tailLimit } : {}
|
|
50011
|
+
}, "p2p");
|
|
50012
|
+
if (!result?.success || result.syncMode === "noop") {
|
|
50013
|
+
if (result?.success) {
|
|
50014
|
+
subscription.cursor = {
|
|
50015
|
+
knownMessageCount: Math.max(0, Number(result.totalMessages || subscription.cursor.knownMessageCount)),
|
|
50016
|
+
lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : subscription.cursor.lastMessageSignature,
|
|
50017
|
+
tailLimit: subscription.cursor.tailLimit
|
|
50018
|
+
};
|
|
50019
|
+
}
|
|
50020
|
+
return null;
|
|
50021
|
+
}
|
|
50022
|
+
subscription.seq += 1;
|
|
50023
|
+
const syncMode = result.syncMode === "append" || result.syncMode === "replace_tail" || result.syncMode === "noop" || result.syncMode === "full" ? result.syncMode : "full";
|
|
50024
|
+
subscription.cursor = {
|
|
50025
|
+
knownMessageCount: Math.max(0, Number(result.totalMessages || 0)),
|
|
50026
|
+
lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : "",
|
|
50027
|
+
tailLimit: subscription.cursor.tailLimit
|
|
50028
|
+
};
|
|
50029
|
+
const activeModal = result.activeModal && typeof result.activeModal === "object" && typeof result.activeModal.message === "string" && Array.isArray(result.activeModal.buttons) ? {
|
|
50030
|
+
message: result.activeModal.message,
|
|
50031
|
+
buttons: result.activeModal.buttons.filter((button) => typeof button === "string")
|
|
50032
|
+
} : null;
|
|
50033
|
+
const deliverySignature = buildChatTailDeliverySignature({
|
|
50034
|
+
sessionId: subscription.params.targetSessionId,
|
|
50035
|
+
...subscription.params.historySessionId ? { historySessionId: subscription.params.historySessionId } : {},
|
|
50036
|
+
messages: Array.isArray(result.messages) ? result.messages : [],
|
|
50037
|
+
status: typeof result.status === "string" ? result.status : "idle",
|
|
50038
|
+
...typeof result.title === "string" ? { title: result.title } : {},
|
|
50039
|
+
...activeModal ? { activeModal } : {},
|
|
50040
|
+
syncMode,
|
|
50041
|
+
replaceFrom: Number(result.replaceFrom || 0),
|
|
50042
|
+
totalMessages: Number(result.totalMessages || 0),
|
|
50043
|
+
lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
|
|
50044
|
+
});
|
|
50045
|
+
if (deliverySignature === subscription.lastDeliveredSignature) {
|
|
50046
|
+
return null;
|
|
50047
|
+
}
|
|
50048
|
+
subscription.lastDeliveredSignature = deliverySignature;
|
|
50049
|
+
return {
|
|
50050
|
+
topic: "session.chat_tail",
|
|
50051
|
+
key: subscription.key,
|
|
50052
|
+
sessionId: subscription.params.targetSessionId,
|
|
50053
|
+
...subscription.params.historySessionId ? { historySessionId: subscription.params.historySessionId } : {},
|
|
50054
|
+
seq: subscription.seq,
|
|
50055
|
+
timestamp: Date.now(),
|
|
50056
|
+
messages: Array.isArray(result.messages) ? result.messages : [],
|
|
50057
|
+
status: typeof result.status === "string" ? result.status : "idle",
|
|
50058
|
+
...typeof result.title === "string" ? { title: result.title } : {},
|
|
50059
|
+
...activeModal ? { activeModal } : {},
|
|
50060
|
+
syncMode,
|
|
50061
|
+
replaceFrom: Number(result.replaceFrom || 0),
|
|
50062
|
+
totalMessages: Number(result.totalMessages || 0),
|
|
50063
|
+
lastMessageSignature: typeof result.lastMessageSignature === "string" ? result.lastMessageSignature : ""
|
|
50064
|
+
};
|
|
50065
|
+
}
|
|
50066
|
+
buildLiveStatusSnapshot() {
|
|
50067
|
+
return buildStatusSnapshot({
|
|
50068
|
+
allStates: this.components.instanceManager.collectAllStates(),
|
|
50069
|
+
cdpManagers: this.components.cdpManagers,
|
|
50070
|
+
providerLoader: this.components.providerLoader,
|
|
50071
|
+
detectedIdes: this.components.detectedIdes.value.map((ide) => ({
|
|
50072
|
+
...ide,
|
|
50073
|
+
path: ide.path ?? void 0
|
|
50074
|
+
})),
|
|
50075
|
+
instanceId: `daemon_${loadConfig().machineId || "daemon"}`,
|
|
50076
|
+
version: pkgVersion,
|
|
50077
|
+
profile: "live"
|
|
50078
|
+
});
|
|
50079
|
+
}
|
|
50080
|
+
getHotChatSessionIdsForP2PFlush() {
|
|
50081
|
+
const snapshot = this.buildLiveStatusSnapshot();
|
|
50082
|
+
const active = new Set(
|
|
50083
|
+
snapshot.sessions.filter((session) => ACTIVE_CHAT_POLL_STATUSES.has(String(session.status || "").toLowerCase())).map((session) => session.id)
|
|
50084
|
+
);
|
|
50085
|
+
const finalizing = new Set(
|
|
50086
|
+
Array.from(this.hotP2PChatSessionIds).filter((sessionId) => !active.has(sessionId))
|
|
50087
|
+
);
|
|
50088
|
+
this.hotP2PChatSessionIds = active;
|
|
50089
|
+
return { active, finalizing };
|
|
50090
|
+
}
|
|
50091
|
+
async flushP2PChatSubscriptions(options = {}) {
|
|
50092
|
+
if (!this.p2p?.isConnected || !this.p2p.hasChatSubscriptions()) return;
|
|
50093
|
+
const onlyActive = options.onlyActive === true;
|
|
50094
|
+
if (this.p2pChatFlushInFlight) {
|
|
50095
|
+
this.pendingP2PChatFlush = true;
|
|
50096
|
+
this.pendingP2PChatFlushOnlyActive = this.pendingP2PChatFlushOnlyActive && onlyActive;
|
|
50097
|
+
return;
|
|
50098
|
+
}
|
|
50099
|
+
this.p2pChatFlushInFlight = true;
|
|
50100
|
+
try {
|
|
50101
|
+
const hotSessionIds = onlyActive ? this.getHotChatSessionIdsForP2PFlush() : null;
|
|
50102
|
+
await this.p2p.flushChatSubscriptions(async (subscription) => {
|
|
50103
|
+
if (hotSessionIds && !hotSessionIds.active.has(subscription.params.targetSessionId) && !hotSessionIds.finalizing.has(subscription.params.targetSessionId)) {
|
|
50104
|
+
return null;
|
|
50105
|
+
}
|
|
50106
|
+
return this.buildChatTailUpdateForSubscription(subscription);
|
|
50107
|
+
});
|
|
50108
|
+
} finally {
|
|
50109
|
+
this.p2pChatFlushInFlight = false;
|
|
50110
|
+
if (this.pendingP2PChatFlush) {
|
|
50111
|
+
const pendingOnlyActive = this.pendingP2PChatFlushOnlyActive;
|
|
50112
|
+
this.pendingP2PChatFlush = false;
|
|
50113
|
+
this.pendingP2PChatFlushOnlyActive = true;
|
|
50114
|
+
void this.flushP2PChatSubscriptions({ onlyActive: pendingOnlyActive });
|
|
50115
|
+
}
|
|
50116
|
+
}
|
|
50117
|
+
}
|
|
50118
|
+
buildMachineRuntimeUpdateForSubscription(subscription) {
|
|
50119
|
+
const intervalMs = Math.max(5e3, Number(subscription.params.intervalMs || 15e3));
|
|
50120
|
+
const now = Date.now();
|
|
50121
|
+
if (subscription.lastSentAt > 0 && now - subscription.lastSentAt < intervalMs) {
|
|
50122
|
+
return null;
|
|
50123
|
+
}
|
|
50124
|
+
subscription.seq += 1;
|
|
50125
|
+
subscription.lastSentAt = now;
|
|
50126
|
+
return {
|
|
50127
|
+
topic: "machine.runtime",
|
|
50128
|
+
key: subscription.key,
|
|
50129
|
+
machine: buildMachineInfo("full"),
|
|
50130
|
+
seq: subscription.seq,
|
|
50131
|
+
timestamp: now
|
|
50132
|
+
};
|
|
50133
|
+
}
|
|
50134
|
+
async flushP2PMachineRuntimeSubscriptions() {
|
|
50135
|
+
if (!this.p2p?.isConnected || !this.p2p.hasMachineRuntimeSubscriptions()) return;
|
|
50136
|
+
await this.p2p.flushMachineRuntimeSubscriptions(async (subscription) => this.buildMachineRuntimeUpdateForSubscription(subscription));
|
|
50137
|
+
}
|
|
50138
|
+
async buildSessionHostDiagnosticsUpdateForSubscription(subscription) {
|
|
50139
|
+
if (!this.sessionHostController) return null;
|
|
50140
|
+
const intervalMs = Math.max(5e3, Number(subscription.params.intervalMs || 1e4));
|
|
50141
|
+
const now = Date.now();
|
|
50142
|
+
if (subscription.lastSentAt > 0 && now - subscription.lastSentAt < intervalMs) {
|
|
50143
|
+
return null;
|
|
50144
|
+
}
|
|
50145
|
+
const diagnostics = await this.sessionHostController.getDiagnostics({
|
|
50146
|
+
includeSessions: subscription.params.includeSessions !== false,
|
|
50147
|
+
limit: Number(subscription.params.limit) || void 0
|
|
50148
|
+
});
|
|
50149
|
+
subscription.seq += 1;
|
|
50150
|
+
subscription.lastSentAt = now;
|
|
50151
|
+
return {
|
|
50152
|
+
topic: "session_host.diagnostics",
|
|
50153
|
+
key: subscription.key,
|
|
50154
|
+
diagnostics,
|
|
50155
|
+
seq: subscription.seq,
|
|
50156
|
+
timestamp: now
|
|
50157
|
+
};
|
|
50158
|
+
}
|
|
50159
|
+
async flushP2PSessionHostDiagnosticsSubscriptions() {
|
|
50160
|
+
if (!this.p2p?.isConnected || !this.p2p.hasSessionHostDiagnosticsSubscriptions()) return;
|
|
50161
|
+
await this.p2p.flushSessionHostDiagnosticsSubscriptions(
|
|
50162
|
+
async (subscription) => this.buildSessionHostDiagnosticsUpdateForSubscription(subscription)
|
|
50163
|
+
);
|
|
50164
|
+
}
|
|
50165
|
+
findProviderStateBySessionId(sessionId) {
|
|
50166
|
+
if (!this.components || !sessionId) return null;
|
|
50167
|
+
const states = this.components.instanceManager.collectAllStates();
|
|
50168
|
+
for (const state of states) {
|
|
50169
|
+
if (state.instanceId === sessionId) return state;
|
|
50170
|
+
if (state.category === "ide") {
|
|
50171
|
+
const child = state.extensions.find((entry) => entry.instanceId === sessionId);
|
|
50172
|
+
if (child) return child;
|
|
50173
|
+
}
|
|
50174
|
+
}
|
|
50175
|
+
return null;
|
|
50176
|
+
}
|
|
50177
|
+
buildSessionModalUpdateForSubscription(subscription) {
|
|
50178
|
+
const state = this.findProviderStateBySessionId(subscription.params.targetSessionId);
|
|
50179
|
+
if (!state) return null;
|
|
50180
|
+
const now = Date.now();
|
|
50181
|
+
const activeModal = state.activeChat?.activeModal;
|
|
50182
|
+
const modalButtons = Array.isArray(activeModal?.buttons) ? activeModal.buttons.filter((button) => typeof button === "string") : [];
|
|
50183
|
+
const status = String(state.activeChat?.status || state.status || "idle");
|
|
50184
|
+
const title = typeof state.activeChat?.title === "string" ? state.activeChat.title : void 0;
|
|
50185
|
+
const modalMessage = typeof activeModal?.message === "string" ? activeModal.message : void 0;
|
|
50186
|
+
const deliverySignature = buildSessionModalDeliverySignature({
|
|
50187
|
+
sessionId: subscription.params.targetSessionId,
|
|
50188
|
+
status,
|
|
50189
|
+
...title ? { title } : {},
|
|
50190
|
+
...modalMessage ? { modalMessage } : {},
|
|
50191
|
+
...modalButtons.length > 0 ? { modalButtons } : {}
|
|
50192
|
+
});
|
|
50193
|
+
if (deliverySignature === subscription.lastDeliveredSignature) {
|
|
50194
|
+
return null;
|
|
50195
|
+
}
|
|
50196
|
+
subscription.lastDeliveredSignature = deliverySignature;
|
|
50197
|
+
subscription.seq += 1;
|
|
50198
|
+
subscription.lastSentAt = now;
|
|
50199
|
+
return {
|
|
50200
|
+
topic: "session.modal",
|
|
50201
|
+
key: subscription.key,
|
|
50202
|
+
sessionId: subscription.params.targetSessionId,
|
|
50203
|
+
status,
|
|
50204
|
+
...title ? { title } : {},
|
|
50205
|
+
...modalMessage ? { modalMessage } : {},
|
|
50206
|
+
...modalButtons.length > 0 ? { modalButtons } : {},
|
|
50207
|
+
seq: subscription.seq,
|
|
50208
|
+
timestamp: now
|
|
50209
|
+
};
|
|
50210
|
+
}
|
|
50211
|
+
async flushP2PSessionModalSubscriptions() {
|
|
50212
|
+
if (!this.p2p?.isConnected || !this.p2p.hasSessionModalSubscriptions()) return;
|
|
50213
|
+
await this.p2p.flushSessionModalSubscriptions(
|
|
50214
|
+
async (subscription) => this.buildSessionModalUpdateForSubscription(subscription)
|
|
50215
|
+
);
|
|
50216
|
+
}
|
|
50217
|
+
buildDaemonMetadataSnapshot() {
|
|
50218
|
+
return buildStatusSnapshot({
|
|
50219
|
+
allStates: this.components.instanceManager.collectAllStates(),
|
|
50220
|
+
cdpManagers: this.components.cdpManagers,
|
|
50221
|
+
providerLoader: this.components.providerLoader,
|
|
50222
|
+
detectedIdes: this.components.detectedIdes.value.map((ide) => ({
|
|
50223
|
+
...ide,
|
|
50224
|
+
path: ide.path ?? void 0
|
|
50225
|
+
})),
|
|
50226
|
+
instanceId: `daemon_${loadConfig().machineId || "daemon"}`,
|
|
50227
|
+
version: pkgVersion,
|
|
50228
|
+
profile: "metadata"
|
|
50229
|
+
});
|
|
50230
|
+
}
|
|
50231
|
+
buildDaemonMetadataUpdateForSubscription(subscription) {
|
|
50232
|
+
const now = Date.now();
|
|
50233
|
+
subscription.seq += 1;
|
|
50234
|
+
subscription.lastSentAt = now;
|
|
50235
|
+
return {
|
|
50236
|
+
topic: "daemon.metadata",
|
|
50237
|
+
key: subscription.key,
|
|
50238
|
+
daemonId: `daemon_${loadConfig().machineId || "daemon"}`,
|
|
50239
|
+
status: this.buildDaemonMetadataSnapshot(),
|
|
50240
|
+
seq: subscription.seq,
|
|
50241
|
+
timestamp: now
|
|
50242
|
+
};
|
|
50243
|
+
}
|
|
50244
|
+
async flushP2PDaemonMetadataSubscriptions() {
|
|
50245
|
+
if (!this.p2p?.isConnected || !this.p2p.hasDaemonMetadataSubscriptions()) return;
|
|
50246
|
+
await this.p2p.flushDaemonMetadataSubscriptions(
|
|
50247
|
+
async (subscription) => this.buildDaemonMetadataUpdateForSubscription(subscription)
|
|
50248
|
+
);
|
|
50249
|
+
}
|
|
49388
50250
|
async start(options = {}) {
|
|
49389
50251
|
installGlobalInterceptor();
|
|
49390
50252
|
process.on("uncaughtException", (err) => {
|
|
@@ -49417,9 +50279,14 @@ ${err?.stack || ""}`);
|
|
|
49417
50279
|
this.sessionHostEndpoint = sessionHostEndpoint;
|
|
49418
50280
|
this.sessionHostController = new SessionHostController(
|
|
49419
50281
|
sessionHostEndpoint,
|
|
49420
|
-
(event) =>
|
|
50282
|
+
(event) => {
|
|
50283
|
+
this.broadcastLocalIpcMessage("daemon:session_host_event", event);
|
|
50284
|
+
void this.flushP2PSessionHostDiagnosticsSubscriptions();
|
|
50285
|
+
void this.flushP2PSessionModalSubscriptions();
|
|
50286
|
+
}
|
|
49421
50287
|
);
|
|
49422
50288
|
await this.sessionHostController.start();
|
|
50289
|
+
const instanceId = `daemon_${config2.machineId}`;
|
|
49423
50290
|
this.components = await initDaemonComponents({
|
|
49424
50291
|
providerLogFn: LOG.forComponent("Provider").asLogFn(),
|
|
49425
50292
|
cliManagerDeps: {
|
|
@@ -49452,6 +50319,8 @@ ${err?.stack || ""}`);
|
|
|
49452
50319
|
listHostedCliRuntimes: async () => listHostedCliRuntimes2(sessionHostEndpoint)
|
|
49453
50320
|
},
|
|
49454
50321
|
enabledIdes: config2.enabledIdes,
|
|
50322
|
+
statusInstanceId: instanceId,
|
|
50323
|
+
statusVersion: pkgVersion,
|
|
49455
50324
|
onStatusChange: () => this.statusReporter?.onStatusChange(),
|
|
49456
50325
|
onPostChatCommand: () => {
|
|
49457
50326
|
setTimeout(() => this.statusReporter?.throttledReport(), 1e3);
|
|
@@ -49477,7 +50346,6 @@ ${err?.stack || ""}`);
|
|
|
49477
50346
|
}
|
|
49478
50347
|
}).catch(() => {
|
|
49479
50348
|
});
|
|
49480
|
-
const instanceId = `daemon_${config2.machineId}`;
|
|
49481
50349
|
this.serverConn = new ServerConnection({
|
|
49482
50350
|
serverUrl: options.serverUrl || config2.serverUrl,
|
|
49483
50351
|
token: authToken,
|
|
@@ -49527,14 +50395,21 @@ ${err?.stack || ""}`);
|
|
|
49527
50395
|
found.adapter.resize(cols, rows);
|
|
49528
50396
|
}
|
|
49529
50397
|
});
|
|
50398
|
+
this.p2p.onSubscriptionChange(() => {
|
|
50399
|
+
void this.flushP2PChatSubscriptions();
|
|
50400
|
+
void this.flushP2PMachineRuntimeSubscriptions();
|
|
50401
|
+
void this.flushP2PSessionHostDiagnosticsSubscriptions();
|
|
50402
|
+
void this.flushP2PSessionModalSubscriptions();
|
|
50403
|
+
void this.flushP2PDaemonMetadataSubscriptions();
|
|
50404
|
+
});
|
|
49530
50405
|
this.p2p.onStateChange((state) => {
|
|
49531
50406
|
if (state === "connected") {
|
|
49532
50407
|
LOG.info("P2P", "Peer connected \u2192 sending immediate full status report");
|
|
49533
50408
|
this.statusReporter?.resetP2PHash();
|
|
49534
|
-
this.statusReporter?.sendUnifiedStatusReport().catch((e) => LOG.warn("P2P", `Immediate status report failed: ${e?.message}`));
|
|
50409
|
+
this.statusReporter?.sendUnifiedStatusReport({ reason: "p2p-connect" }).catch((e) => LOG.warn("P2P", `Immediate status report failed: ${e?.message}`));
|
|
49535
50410
|
setTimeout(() => {
|
|
49536
50411
|
this.statusReporter?.resetP2PHash();
|
|
49537
|
-
this.statusReporter?.sendUnifiedStatusReport().catch(() => {
|
|
50412
|
+
this.statusReporter?.sendUnifiedStatusReport({ reason: "p2p-connect-followup" }).catch(() => {
|
|
49538
50413
|
});
|
|
49539
50414
|
}, 2e3);
|
|
49540
50415
|
}
|
|
@@ -49543,18 +50418,24 @@ ${err?.stack || ""}`);
|
|
|
49543
50418
|
this.screenshotController = new ScreenshotController({
|
|
49544
50419
|
isRunning: () => this.running,
|
|
49545
50420
|
isScreenshotActive: () => this.p2p?.screenshotActive ?? false,
|
|
49546
|
-
|
|
50421
|
+
getScreenshotTargetSessionId: () => this.p2p?.screenshotTargetSessionId,
|
|
49547
50422
|
isUsingRelay: () => this.p2p?.isUsingRelay ?? false,
|
|
49548
50423
|
hasAnyNeedingFirstFrame: () => this.p2p?.hasAnyNeedingFirstFrame() ?? false,
|
|
49549
|
-
getCdp: (
|
|
49550
|
-
if (
|
|
49551
|
-
LOG.warn("P2P", "Screenshot requested without
|
|
50424
|
+
getCdp: (targetSessionId) => {
|
|
50425
|
+
if (targetSessionId) return this.getCdpFor(targetSessionId);
|
|
50426
|
+
LOG.warn("P2P", "Screenshot requested without targetSessionId \u2014 cannot determine target session. Skipping frame.");
|
|
49552
50427
|
return null;
|
|
49553
50428
|
},
|
|
49554
50429
|
sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf)
|
|
49555
50430
|
}, planLimits ?? void 0);
|
|
49556
50431
|
this.screenshotController.start();
|
|
49557
50432
|
this.p2p.onScreenshotStart(() => this.screenshotController?.triggerImmediate());
|
|
50433
|
+
this.topicSubscriptionTimer = setInterval(() => {
|
|
50434
|
+
void this.flushP2PChatSubscriptions({ onlyActive: true });
|
|
50435
|
+
void this.flushP2PMachineRuntimeSubscriptions();
|
|
50436
|
+
void this.flushP2PSessionHostDiagnosticsSubscriptions();
|
|
50437
|
+
void this.flushP2PSessionModalSubscriptions();
|
|
50438
|
+
}, 2500);
|
|
49558
50439
|
} else {
|
|
49559
50440
|
console.log(import_chalk2.default.gray(" \u26A0 P2P unavailable \u2014 using server relay"));
|
|
49560
50441
|
}
|
|
@@ -49573,7 +50454,7 @@ ${err?.stack || ""}`);
|
|
|
49573
50454
|
this.serverConn.onStateChange((state) => {
|
|
49574
50455
|
if (state === "connected") {
|
|
49575
50456
|
console.log(import_chalk2.default.green(" \u{1F4E1} Connected to ADHDev server"));
|
|
49576
|
-
this.statusReporter?.sendUnifiedStatusReport();
|
|
50457
|
+
this.statusReporter?.sendUnifiedStatusReport({ forceServer: true, reason: "ws-connected" });
|
|
49577
50458
|
} else if (state === "disconnected") {
|
|
49578
50459
|
console.log(import_chalk2.default.yellow(" \u26A0 Server disconnected, will reconnect..."));
|
|
49579
50460
|
}
|
|
@@ -49659,10 +50540,26 @@ ${err?.stack || ""}`);
|
|
|
49659
50540
|
async handleCommand(msg, cmd, args) {
|
|
49660
50541
|
LOG.info("Command", `${cmd}${args?.targetSessionId ? ` \u2192 session:${String(args.targetSessionId).split("_")[0]}` : ""}`);
|
|
49661
50542
|
const cmdStart = Date.now();
|
|
49662
|
-
const source = msg.ipcWs ? "ext" : "ws";
|
|
50543
|
+
const source = msg.ipcWs ? "ext" : typeof msg.source === "string" && msg.source.trim() ? msg.source : "ws";
|
|
49663
50544
|
try {
|
|
50545
|
+
if (source === "api" && !loadConfig().allowServerApiProxy) {
|
|
50546
|
+
this.sendResult(msg, false, {
|
|
50547
|
+
error: "Server API relay is disabled on this daemon. Enable it explicitly with `adhdev daemon:api enable`.",
|
|
50548
|
+
code: "SERVER_API_DISABLED"
|
|
50549
|
+
});
|
|
50550
|
+
return;
|
|
50551
|
+
}
|
|
49664
50552
|
const result = await this.components.router.execute(cmd, args, source);
|
|
49665
50553
|
if (cmd.startsWith("workspace_")) this.statusReporter?.throttledReport();
|
|
50554
|
+
if (cmd === "get_status_metadata" || cmd.startsWith("workspace_") || cmd.startsWith("session_host_")) {
|
|
50555
|
+
void this.flushP2PDaemonMetadataSubscriptions();
|
|
50556
|
+
}
|
|
50557
|
+
if (cmd.startsWith("session_host_")) {
|
|
50558
|
+
void this.flushP2PSessionHostDiagnosticsSubscriptions();
|
|
50559
|
+
}
|
|
50560
|
+
if (cmd === "resolve_action" || cmd === "send_chat" || cmd === "read_chat") {
|
|
50561
|
+
void this.flushP2PSessionModalSubscriptions();
|
|
50562
|
+
}
|
|
49666
50563
|
this.sendResult(msg, result.success, result);
|
|
49667
50564
|
} catch (e) {
|
|
49668
50565
|
console.error(import_chalk2.default.red(` \u2717 Command failed: ${e.message}`));
|
|
@@ -49702,6 +50599,7 @@ ${err?.stack || ""}`);
|
|
|
49702
50599
|
const config2 = loadConfig();
|
|
49703
50600
|
config2.machineNickname = nickname;
|
|
49704
50601
|
saveConfig(config2);
|
|
50602
|
+
void this.flushP2PDaemonMetadataSubscriptions();
|
|
49705
50603
|
logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", args: { nickname }, success: true, durationMs: Date.now() - cmdStart });
|
|
49706
50604
|
return { success: true, nickname };
|
|
49707
50605
|
}
|
|
@@ -49714,6 +50612,15 @@ ${err?.stack || ""}`);
|
|
|
49714
50612
|
}
|
|
49715
50613
|
const routed = await this.components.router.execute(cmdType, data, "p2p");
|
|
49716
50614
|
if (cmdType.startsWith("workspace_")) this.statusReporter?.throttledReport();
|
|
50615
|
+
if (cmdType === "get_status_metadata" || cmdType.startsWith("workspace_") || cmdType.startsWith("session_host_")) {
|
|
50616
|
+
void this.flushP2PDaemonMetadataSubscriptions();
|
|
50617
|
+
}
|
|
50618
|
+
if (cmdType.startsWith("session_host_")) {
|
|
50619
|
+
void this.flushP2PSessionHostDiagnosticsSubscriptions();
|
|
50620
|
+
}
|
|
50621
|
+
if (cmdType === "resolve_action" || cmdType === "send_chat" || cmdType === "read_chat") {
|
|
50622
|
+
void this.flushP2PSessionModalSubscriptions();
|
|
50623
|
+
}
|
|
49717
50624
|
return routed;
|
|
49718
50625
|
} catch (e) {
|
|
49719
50626
|
logCommand({ ts: (/* @__PURE__ */ new Date()).toISOString(), cmd: cmdType, source: "p2p", success: false, error: e.message, durationMs: Date.now() - cmdStart });
|
|
@@ -49886,6 +50793,10 @@ ${err?.stack || ""}`);
|
|
|
49886
50793
|
this.statusReporter.stopReporting();
|
|
49887
50794
|
this.statusReporter = null;
|
|
49888
50795
|
}
|
|
50796
|
+
if (this.topicSubscriptionTimer) {
|
|
50797
|
+
clearInterval(this.topicSubscriptionTimer);
|
|
50798
|
+
this.topicSubscriptionTimer = null;
|
|
50799
|
+
}
|
|
49889
50800
|
if (this.components) {
|
|
49890
50801
|
await shutdownDaemonComponents(this.components);
|
|
49891
50802
|
}
|
|
@@ -51617,6 +52528,51 @@ function registerSetupCommands(program2, providerLoader) {
|
|
|
51617
52528
|
console.log(import_chalk4.default.gray(" Auth credentials cleared. IDE and workspace settings preserved."));
|
|
51618
52529
|
console.log(import_chalk4.default.gray(" Run `adhdev setup` to log in again.\n"));
|
|
51619
52530
|
});
|
|
52531
|
+
program2.command("uninstall").description("Completely wipe all setting, configuration, stop daemon and uninstall service").option("-f, --force", "Skip confirmation prompt").action(async (options) => {
|
|
52532
|
+
const inquirer2 = await import("inquirer");
|
|
52533
|
+
const fs20 = await import("fs");
|
|
52534
|
+
const path29 = await import("path");
|
|
52535
|
+
const os26 = await import("os");
|
|
52536
|
+
const { spawnSync: spawnSync2 } = await import("child_process");
|
|
52537
|
+
if (!options.force) {
|
|
52538
|
+
const { confirm } = await inquirer2.default.prompt([
|
|
52539
|
+
{
|
|
52540
|
+
type: "confirm",
|
|
52541
|
+
name: "confirm",
|
|
52542
|
+
message: "Are you sure you want to completely wipe ADHDev settings, uninstall the daemon service, and remove all downloaded data? This cannot be undone.",
|
|
52543
|
+
default: false
|
|
52544
|
+
}
|
|
52545
|
+
]);
|
|
52546
|
+
if (!confirm) return;
|
|
52547
|
+
}
|
|
52548
|
+
console.log(import_chalk4.default.bold("\n\u{1F5D1}\uFE0F Uninstalling ADHDev\n"));
|
|
52549
|
+
try {
|
|
52550
|
+
const { isDaemonRunning: isDaemonRunning2, stopDaemon: stopDaemon2 } = await Promise.resolve().then(() => (init_adhdev_daemon(), adhdev_daemon_exports));
|
|
52551
|
+
if (isDaemonRunning2()) {
|
|
52552
|
+
console.log(import_chalk4.default.gray(" Stopping daemon..."));
|
|
52553
|
+
stopDaemon2();
|
|
52554
|
+
console.log(import_chalk4.default.green(" \u2713 Daemon stopped."));
|
|
52555
|
+
}
|
|
52556
|
+
} catch {
|
|
52557
|
+
}
|
|
52558
|
+
console.log(import_chalk4.default.gray(" Removing OS background service..."));
|
|
52559
|
+
spawnSync2(process.execPath, [process.argv[1], "service", "uninstall"], { stdio: "inherit" });
|
|
52560
|
+
const adhdevDir = path29.join(os26.homedir(), ".adhdev");
|
|
52561
|
+
if (fs20.existsSync(adhdevDir)) {
|
|
52562
|
+
console.log(import_chalk4.default.gray(` Deleting ${adhdevDir}...`));
|
|
52563
|
+
try {
|
|
52564
|
+
fs20.rmSync(adhdevDir, { recursive: true, force: true });
|
|
52565
|
+
console.log(import_chalk4.default.green(" \u2713 Data wiped."));
|
|
52566
|
+
} catch (e) {
|
|
52567
|
+
console.log(import_chalk4.default.red(` \u2717 Failed to delete ~/.adhdev: ${e.message}`));
|
|
52568
|
+
}
|
|
52569
|
+
} else {
|
|
52570
|
+
console.log(import_chalk4.default.green(" \u2713 ~/.adhdev not found or already deleted."));
|
|
52571
|
+
}
|
|
52572
|
+
console.log(import_chalk4.default.green("\n\u2713 Uninstall complete."));
|
|
52573
|
+
console.log(import_chalk4.default.whiteBright(" To finish uninstalling the CLI tool, please run:"));
|
|
52574
|
+
console.log(import_chalk4.default.cyan(" npm uninstall -g adhdev\n"));
|
|
52575
|
+
});
|
|
51620
52576
|
}
|
|
51621
52577
|
|
|
51622
52578
|
// src/cli/daemon-commands.ts
|
|
@@ -51703,17 +52659,50 @@ function registerDaemonCommands(program2, pkgVersion3) {
|
|
|
51703
52659
|
\u2717 Failed to start standalone server: ${err.message}`));
|
|
51704
52660
|
});
|
|
51705
52661
|
});
|
|
52662
|
+
hideCommand(program2.command("daemon:api [mode]").description("Manage server API relay access (disabled by default)").action(async (modeArg) => {
|
|
52663
|
+
const mode = typeof modeArg === "string" && modeArg.trim() ? modeArg.trim().toLowerCase() : "status";
|
|
52664
|
+
const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
52665
|
+
const config2 = loadConfig2();
|
|
52666
|
+
if (mode === "status") {
|
|
52667
|
+
const enabled2 = config2.allowServerApiProxy === true;
|
|
52668
|
+
console.log();
|
|
52669
|
+
console.log(import_chalk5.default.bold(" Server API Relay\n"));
|
|
52670
|
+
console.log(` ${import_chalk5.default.bold("Status:")} ${enabled2 ? import_chalk5.default.green("enabled") : import_chalk5.default.yellow("disabled")}`);
|
|
52671
|
+
console.log(import_chalk5.default.gray(" Applies only to server REST/API proxy routes."));
|
|
52672
|
+
console.log(import_chalk5.default.gray(" Dashboard traffic remains P2P/local IPC based.\n"));
|
|
52673
|
+
return;
|
|
52674
|
+
}
|
|
52675
|
+
if (mode !== "enable" && mode !== "disable") {
|
|
52676
|
+
console.log(import_chalk5.default.red(`
|
|
52677
|
+
\u2717 Unknown mode: ${mode}
|
|
52678
|
+
`));
|
|
52679
|
+
console.log(import_chalk5.default.gray(" Use: adhdev daemon:api [status|enable|disable]\n"));
|
|
52680
|
+
process.exitCode = 1;
|
|
52681
|
+
return;
|
|
52682
|
+
}
|
|
52683
|
+
const enabled = mode === "enable";
|
|
52684
|
+
config2.allowServerApiProxy = enabled;
|
|
52685
|
+
saveConfig3(config2);
|
|
52686
|
+
console.log();
|
|
52687
|
+
console.log(import_chalk5.default.bold(" Server API Relay\n"));
|
|
52688
|
+
console.log(` ${import_chalk5.default.bold("Status:")} ${enabled ? import_chalk5.default.green("enabled") : import_chalk5.default.yellow("disabled")}`);
|
|
52689
|
+
console.log(import_chalk5.default.gray(` Set with: adhdev daemon:api ${enabled ? "disable" : "enable"}
|
|
52690
|
+
`));
|
|
52691
|
+
}));
|
|
51706
52692
|
hideCommand(program2.command("daemon:status").description("Check ADHDev Daemon status").option("-p, --port <port>", "Local WS server port", "19222").action(async (options) => {
|
|
51707
52693
|
const { isDaemonRunning: isDaemonRunning2, getDaemonPid: getDaemonPid2 } = await Promise.resolve().then(() => (init_adhdev_daemon(), adhdev_daemon_exports));
|
|
51708
52694
|
const { getCurrentDaemonLogPath: getCurrentDaemonLogPath2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
51709
52695
|
const { probeSessionHostStatus: probeSessionHostStatus2 } = await Promise.resolve().then(() => (init_session_host(), session_host_exports));
|
|
51710
52696
|
const port = parseInt(options.port, 10) || 19222;
|
|
52697
|
+
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
52698
|
+
const config2 = loadConfig2();
|
|
51711
52699
|
if (isDaemonRunning2()) {
|
|
51712
52700
|
console.log(import_chalk5.default.green(`
|
|
51713
52701
|
\u2713 ADHDev Daemon is running.
|
|
51714
52702
|
`));
|
|
51715
52703
|
console.log(import_chalk5.default.gray(` PID: ${getDaemonPid2() ?? "unknown"}`));
|
|
51716
52704
|
console.log(import_chalk5.default.gray(` Logs: ${getCurrentDaemonLogPath2()}`));
|
|
52705
|
+
console.log(import_chalk5.default.gray(` API Relay: ${config2.allowServerApiProxy ? "enabled" : "disabled"}`));
|
|
51717
52706
|
const health = await fetchLocalDaemonHealth(port);
|
|
51718
52707
|
if (health) {
|
|
51719
52708
|
console.log(import_chalk5.default.gray(` Local IPC: reachable (ws://127.0.0.1:${health.port}${health.wsPath})`));
|
|
@@ -52159,6 +53148,36 @@ function probeNodeDatachannel(packageRoot) {
|
|
|
52159
53148
|
};
|
|
52160
53149
|
}
|
|
52161
53150
|
}
|
|
53151
|
+
function probeSharpRuntime(packageRoot, nativeSharpPackage) {
|
|
53152
|
+
const resolved = resolveModuleFromPackage("sharp", packageRoot);
|
|
53153
|
+
if (!resolved) {
|
|
53154
|
+
return {
|
|
53155
|
+
label: "sharp",
|
|
53156
|
+
ok: false,
|
|
53157
|
+
detail: "module not found",
|
|
53158
|
+
fatal: false
|
|
53159
|
+
};
|
|
53160
|
+
}
|
|
53161
|
+
try {
|
|
53162
|
+
const sharp = require(resolved);
|
|
53163
|
+
const nativeResolved = resolveModuleFromPackage(nativeSharpPackage, packageRoot);
|
|
53164
|
+
const runtimeVersion = sharp?.versions?.sharp || sharp?.version || "unknown";
|
|
53165
|
+
const nativeDetail = nativeResolved ? `${nativeSharpPackage} resolved` : `${nativeSharpPackage} not separately resolvable`;
|
|
53166
|
+
return {
|
|
53167
|
+
label: "sharp",
|
|
53168
|
+
ok: typeof sharp === "function" || typeof sharp?.default === "function",
|
|
53169
|
+
detail: `${resolved} (runtime=${runtimeVersion}; ${nativeDetail})`,
|
|
53170
|
+
fatal: false
|
|
53171
|
+
};
|
|
53172
|
+
} catch (error48) {
|
|
53173
|
+
return {
|
|
53174
|
+
label: "sharp",
|
|
53175
|
+
ok: false,
|
|
53176
|
+
detail: `${resolved} (${error48?.message || "load failed"})`,
|
|
53177
|
+
fatal: false
|
|
53178
|
+
};
|
|
53179
|
+
}
|
|
53180
|
+
}
|
|
52162
53181
|
function probeConfigAccess() {
|
|
52163
53182
|
const configDir = path27.join(os24.homedir(), ".adhdev");
|
|
52164
53183
|
const configPath = path27.join(configDir, "config.json");
|
|
@@ -52307,18 +53326,7 @@ function registerDoctorCommands(program2, pkgVersion3) {
|
|
|
52307
53326
|
fatal: true
|
|
52308
53327
|
},
|
|
52309
53328
|
probeNodeDatachannel(packageRoot),
|
|
52310
|
-
|
|
52311
|
-
label: "sharp",
|
|
52312
|
-
ok: Boolean(resolveModuleFromPackage("sharp", packageRoot)),
|
|
52313
|
-
detail: resolveModuleFromPackage("sharp", packageRoot) || "module not found",
|
|
52314
|
-
fatal: false
|
|
52315
|
-
},
|
|
52316
|
-
{
|
|
52317
|
-
label: nativeSharpPackage,
|
|
52318
|
-
ok: Boolean(resolveModuleFromPackage(nativeSharpPackage, packageRoot)),
|
|
52319
|
-
detail: resolveModuleFromPackage(nativeSharpPackage, packageRoot) || "module not found",
|
|
52320
|
-
fatal: false
|
|
52321
|
-
},
|
|
53329
|
+
probeSharpRuntime(packageRoot, nativeSharpPackage),
|
|
52322
53330
|
...probeConfigAccess(),
|
|
52323
53331
|
...buildBrowseProbeChecks()
|
|
52324
53332
|
];
|
|
@@ -52333,7 +53341,7 @@ function registerDoctorCommands(program2, pkgVersion3) {
|
|
|
52333
53341
|
checks.push({
|
|
52334
53342
|
label: "Session host IPC",
|
|
52335
53343
|
ok: probe.reachable,
|
|
52336
|
-
detail: probe.reachable ? `reachable (${probe.runtimeCount} runtime(s), ${probe.endpoint.kind}:${probe.endpoint.path})` :
|
|
53344
|
+
detail: probe.reachable ? `reachable (${probe.runtimeCount} runtime(s), ${probe.endpoint.kind}:${probe.endpoint.path})` : `${sessionHostPid ? "unreachable (stale PID or lazy host)" : "unreachable (host not running)"} (${probe.endpoint.kind}:${probe.endpoint.path})`
|
|
52337
53345
|
});
|
|
52338
53346
|
} catch (e) {
|
|
52339
53347
|
checks.push({
|