adhdev 0.9.33 → 0.9.34
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 +394 -155
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +394 -155
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -12369,13 +12369,14 @@ function sliceFromOffset(text, start) {
|
|
|
12369
12369
|
function hydrateCliParsedMessages(parsedMessages, options) {
|
|
12370
12370
|
const { committedMessages, scope, lastOutputAt } = options;
|
|
12371
12371
|
const referenceMessages = [...committedMessages];
|
|
12372
|
+
const referenceComparables = referenceMessages.map((message) => normalizeComparableMessageContent(message?.content || ""));
|
|
12372
12373
|
const usedReferenceIndexes = /* @__PURE__ */ new Set();
|
|
12373
12374
|
const now = options.now ?? Date.now();
|
|
12374
12375
|
const findReferenceTimestamp = (role, content, parsedIndex) => {
|
|
12375
12376
|
const normalizedContent = normalizeComparableMessageContent(content);
|
|
12376
12377
|
if (!normalizedContent) return void 0;
|
|
12377
12378
|
const sameIndex = referenceMessages[parsedIndex];
|
|
12378
|
-
if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role &&
|
|
12379
|
+
if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && referenceComparables[parsedIndex] === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
|
|
12379
12380
|
usedReferenceIndexes.add(parsedIndex);
|
|
12380
12381
|
return sameIndex.timestamp;
|
|
12381
12382
|
}
|
|
@@ -12383,7 +12384,7 @@ function hydrateCliParsedMessages(parsedMessages, options) {
|
|
|
12383
12384
|
if (usedReferenceIndexes.has(i)) continue;
|
|
12384
12385
|
const candidate = referenceMessages[i];
|
|
12385
12386
|
if (!candidate || candidate.role !== role) continue;
|
|
12386
|
-
const candidateContent =
|
|
12387
|
+
const candidateContent = referenceComparables[i];
|
|
12387
12388
|
if (!candidateContent) continue;
|
|
12388
12389
|
const exactMatch = candidateContent === normalizedContent;
|
|
12389
12390
|
const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
|
|
@@ -13475,7 +13476,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
13475
13476
|
return;
|
|
13476
13477
|
}
|
|
13477
13478
|
if (this.currentTurnScope && !lastParsedAssistant) {
|
|
13478
|
-
LOG.
|
|
13479
|
+
LOG.debug(
|
|
13479
13480
|
"CLI",
|
|
13480
13481
|
`[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
|
|
13481
13482
|
);
|
|
@@ -14291,9 +14292,43 @@ var init_provider_cli_adapter = __esm({
|
|
|
14291
14292
|
}
|
|
14292
14293
|
armResponseTimeout() {
|
|
14293
14294
|
if (this.responseTimeout) clearTimeout(this.responseTimeout);
|
|
14295
|
+
const timeoutMs = this.timeouts.maxResponse;
|
|
14296
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
14297
|
+
this.responseTimeout = null;
|
|
14298
|
+
return;
|
|
14299
|
+
}
|
|
14294
14300
|
this.responseTimeout = setTimeout(() => {
|
|
14295
|
-
|
|
14296
|
-
|
|
14301
|
+
this.responseTimeout = null;
|
|
14302
|
+
if (!this.isWaitingForResponse) return;
|
|
14303
|
+
const detectedStatusBeforeEval = this.runDetectStatus(this.recentOutputBuffer);
|
|
14304
|
+
this.recordTrace("response_timeout_check", {
|
|
14305
|
+
timeoutMs,
|
|
14306
|
+
detectedStatus: detectedStatusBeforeEval,
|
|
14307
|
+
currentStatus: this.currentStatus,
|
|
14308
|
+
isWaitingForResponse: this.isWaitingForResponse,
|
|
14309
|
+
hasActionableApproval: this.hasActionableApproval(),
|
|
14310
|
+
...buildCliTraceParseSnapshot({
|
|
14311
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
14312
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
14313
|
+
responseBuffer: this.responseBuffer,
|
|
14314
|
+
partialResponse: this.responseBuffer,
|
|
14315
|
+
scope: this.currentTurnScope
|
|
14316
|
+
})
|
|
14317
|
+
});
|
|
14318
|
+
this.settledBuffer = this.recentOutputBuffer;
|
|
14319
|
+
this.evaluateSettled();
|
|
14320
|
+
if (this.isWaitingForResponse && !this.hasActionableApproval()) {
|
|
14321
|
+
const detectedStatusAfterEval = this.runDetectStatus(this.recentOutputBuffer);
|
|
14322
|
+
this.recordTrace("response_timeout_kept_open", {
|
|
14323
|
+
timeoutMs,
|
|
14324
|
+
detectedStatusBeforeEval,
|
|
14325
|
+
detectedStatusAfterEval,
|
|
14326
|
+
currentStatus: this.currentStatus,
|
|
14327
|
+
isWaitingForResponse: this.isWaitingForResponse
|
|
14328
|
+
});
|
|
14329
|
+
this.armResponseTimeout();
|
|
14330
|
+
}
|
|
14331
|
+
}, timeoutMs);
|
|
14297
14332
|
}
|
|
14298
14333
|
writeSubmitKeyForRetry(mode) {
|
|
14299
14334
|
void this.writeToPty(this.sendKey).catch((error48) => {
|
|
@@ -15184,6 +15219,20 @@ var init_cli_provider_instance = __esm({
|
|
|
15184
15219
|
getPresentationMode() {
|
|
15185
15220
|
return this.presentationMode;
|
|
15186
15221
|
}
|
|
15222
|
+
getHotChatSessionState() {
|
|
15223
|
+
const adapterStatus = this.adapter.getStatus();
|
|
15224
|
+
const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
|
|
15225
|
+
const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
|
|
15226
|
+
const runtime = this.adapter.getRuntimeMetadata();
|
|
15227
|
+
return {
|
|
15228
|
+
id: this.instanceId,
|
|
15229
|
+
status: visibleStatus,
|
|
15230
|
+
runtimeLifecycle: runtime?.lifecycle ?? null,
|
|
15231
|
+
runtimeSurfaceKind: runtime?.surfaceKind,
|
|
15232
|
+
runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
|
|
15233
|
+
runtimeRecoveryState: runtime?.recoveryState ?? null
|
|
15234
|
+
};
|
|
15235
|
+
}
|
|
15187
15236
|
updateSettings(newSettings) {
|
|
15188
15237
|
this.settings = { ...newSettings };
|
|
15189
15238
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
@@ -15339,6 +15388,15 @@ var init_cli_provider_instance = __esm({
|
|
|
15339
15388
|
this.completedDebouncePending = { chatTitle, duration: duration3, timestamp: now };
|
|
15340
15389
|
this.completedDebounceTimer = setTimeout(() => {
|
|
15341
15390
|
if (this.completedDebouncePending) {
|
|
15391
|
+
const latestStatus = this.adapter.getStatus();
|
|
15392
|
+
const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
|
|
15393
|
+
const latestVisibleStatus = latestAutoApproveActive ? "generating" : latestStatus.status;
|
|
15394
|
+
if (latestVisibleStatus !== "idle") {
|
|
15395
|
+
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
|
|
15396
|
+
this.completedDebouncePending = null;
|
|
15397
|
+
this.completedDebounceTimer = null;
|
|
15398
|
+
return;
|
|
15399
|
+
}
|
|
15342
15400
|
LOG.info("CLI", `[${this.type}] completed in ${this.completedDebouncePending.duration}s`);
|
|
15343
15401
|
this.pushEvent({ event: "agent:generating_completed", ...this.completedDebouncePending });
|
|
15344
15402
|
this.completedDebouncePending = null;
|
|
@@ -38458,6 +38516,51 @@ function killPid(pid) {
|
|
|
38458
38516
|
return false;
|
|
38459
38517
|
}
|
|
38460
38518
|
}
|
|
38519
|
+
function getWindowsProcessCommandLine(pid) {
|
|
38520
|
+
const pidFilter = `ProcessId=${pid}`;
|
|
38521
|
+
try {
|
|
38522
|
+
const psOut = (0, import_child_process8.execFileSync)("powershell.exe", [
|
|
38523
|
+
"-NoProfile",
|
|
38524
|
+
"-NonInteractive",
|
|
38525
|
+
"-ExecutionPolicy",
|
|
38526
|
+
"Bypass",
|
|
38527
|
+
"-Command",
|
|
38528
|
+
`(Get-CimInstance Win32_Process -Filter "${pidFilter}").CommandLine`
|
|
38529
|
+
], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
38530
|
+
if (psOut) return psOut;
|
|
38531
|
+
} catch {
|
|
38532
|
+
}
|
|
38533
|
+
try {
|
|
38534
|
+
const wmicOut = (0, import_child_process8.execFileSync)("wmic", [
|
|
38535
|
+
"process",
|
|
38536
|
+
"where",
|
|
38537
|
+
pidFilter,
|
|
38538
|
+
"get",
|
|
38539
|
+
"CommandLine"
|
|
38540
|
+
], { encoding: "utf8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
38541
|
+
if (wmicOut) return wmicOut;
|
|
38542
|
+
} catch {
|
|
38543
|
+
}
|
|
38544
|
+
return null;
|
|
38545
|
+
}
|
|
38546
|
+
function getProcessCommandLine(pid) {
|
|
38547
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
38548
|
+
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
38549
|
+
try {
|
|
38550
|
+
const text = (0, import_child_process8.execFileSync)("ps", ["-o", "command=", "-p", String(pid)], {
|
|
38551
|
+
encoding: "utf8",
|
|
38552
|
+
timeout: 3e3,
|
|
38553
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
38554
|
+
}).trim();
|
|
38555
|
+
return text || null;
|
|
38556
|
+
} catch {
|
|
38557
|
+
return null;
|
|
38558
|
+
}
|
|
38559
|
+
}
|
|
38560
|
+
function isManagedSessionHostPid(pid) {
|
|
38561
|
+
const commandLine = getProcessCommandLine(pid);
|
|
38562
|
+
return !!commandLine && /session-host-daemon/i.test(commandLine);
|
|
38563
|
+
}
|
|
38461
38564
|
async function waitForPidExit(pid, timeoutMs) {
|
|
38462
38565
|
const start = Date.now();
|
|
38463
38566
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -38474,7 +38577,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
38474
38577
|
try {
|
|
38475
38578
|
if (fs8.existsSync(pidFile)) {
|
|
38476
38579
|
const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
|
|
38477
|
-
if (Number.isFinite(pid)) {
|
|
38580
|
+
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
|
|
38478
38581
|
killPid(pid);
|
|
38479
38582
|
}
|
|
38480
38583
|
}
|
|
@@ -38485,18 +38588,6 @@ function stopSessionHostProcesses(appName) {
|
|
|
38485
38588
|
} catch {
|
|
38486
38589
|
}
|
|
38487
38590
|
}
|
|
38488
|
-
if (process.platform !== "win32") {
|
|
38489
|
-
try {
|
|
38490
|
-
const raw = (0, import_child_process8.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
38491
|
-
for (const line of raw.split("\n")) {
|
|
38492
|
-
const pid = Number.parseInt(line.trim(), 10);
|
|
38493
|
-
if (Number.isFinite(pid)) {
|
|
38494
|
-
killPid(pid);
|
|
38495
|
-
}
|
|
38496
|
-
}
|
|
38497
|
-
} catch {
|
|
38498
|
-
}
|
|
38499
|
-
}
|
|
38500
38591
|
}
|
|
38501
38592
|
function removeDaemonPidFile() {
|
|
38502
38593
|
const pidFile = path17.join(os20.homedir(), ".adhdev", "daemon.pid");
|
|
@@ -40838,6 +40929,20 @@ var init_forward = __esm({
|
|
|
40838
40929
|
});
|
|
40839
40930
|
|
|
40840
40931
|
// ../../oss/packages/daemon-core/src/providers/provider-instance-manager.ts
|
|
40932
|
+
function projectHotChatSessionStatesFromProviderState(state) {
|
|
40933
|
+
const project = (item) => ({
|
|
40934
|
+
id: item.instanceId,
|
|
40935
|
+
status: item.activeChat?.status || item.status,
|
|
40936
|
+
runtimeLifecycle: item.runtime?.lifecycle ?? null,
|
|
40937
|
+
runtimeSurfaceKind: item.runtime?.surfaceKind,
|
|
40938
|
+
runtimeRestoredFromStorage: item.runtime?.restoredFromStorage === true,
|
|
40939
|
+
runtimeRecoveryState: item.runtime?.recoveryState ?? null
|
|
40940
|
+
});
|
|
40941
|
+
if (state.category === "ide") {
|
|
40942
|
+
return [project(state), ...state.extensions.map(project)];
|
|
40943
|
+
}
|
|
40944
|
+
return [project(state)];
|
|
40945
|
+
}
|
|
40841
40946
|
var ProviderInstanceManager;
|
|
40842
40947
|
var init_provider_instance_manager = __esm({
|
|
40843
40948
|
"../../oss/packages/daemon-core/src/providers/provider-instance-manager.ts"() {
|
|
@@ -40938,6 +41043,27 @@ var init_provider_instance_manager = __esm({
|
|
|
40938
41043
|
}
|
|
40939
41044
|
return states;
|
|
40940
41045
|
}
|
|
41046
|
+
collectHotChatSessionStates() {
|
|
41047
|
+
const sessions = [];
|
|
41048
|
+
for (const [id, instance] of this.instances) {
|
|
41049
|
+
try {
|
|
41050
|
+
const projected = instance.getHotChatSessionState?.();
|
|
41051
|
+
if (Array.isArray(projected)) {
|
|
41052
|
+
sessions.push(...projected.filter((session) => !!session?.id));
|
|
41053
|
+
continue;
|
|
41054
|
+
}
|
|
41055
|
+
if (projected?.id) {
|
|
41056
|
+
sessions.push(projected);
|
|
41057
|
+
continue;
|
|
41058
|
+
}
|
|
41059
|
+
const state = instance.getState();
|
|
41060
|
+
sessions.push(...projectHotChatSessionStatesFromProviderState(state));
|
|
41061
|
+
} catch (e) {
|
|
41062
|
+
LOG.warn("InstanceMgr", `[InstanceManager] Failed to collect hot chat metadata from ${id}: ${e.message}`);
|
|
41063
|
+
}
|
|
41064
|
+
}
|
|
41065
|
+
return sessions;
|
|
41066
|
+
}
|
|
40941
41067
|
/**
|
|
40942
41068
|
* Per-category status collect
|
|
40943
41069
|
*/
|
|
@@ -79678,19 +79804,20 @@ var init_screenshot_sender = __esm({
|
|
|
79678
79804
|
}
|
|
79679
79805
|
return sentAny;
|
|
79680
79806
|
}
|
|
79681
|
-
sendScreenshot(peers, base64Data) {
|
|
79807
|
+
sendScreenshot(peers, base64Data, targetSessionId) {
|
|
79682
79808
|
const buffer = Buffer.from(base64Data, "base64");
|
|
79683
|
-
return this.sendScreenshotBuffer(peers, buffer);
|
|
79809
|
+
return this.sendScreenshotBuffer(peers, buffer, targetSessionId);
|
|
79684
79810
|
}
|
|
79685
79811
|
/** Send screenshot as raw Buffer (no base64 conversion overhead) */
|
|
79686
|
-
sendScreenshotBuffer(peers, buffer) {
|
|
79812
|
+
sendScreenshotBuffer(peers, buffer, targetSessionId) {
|
|
79687
79813
|
let sentAny = false;
|
|
79688
79814
|
let debugOnce = !this._ssDebugDone;
|
|
79689
79815
|
for (const [pid, peer] of peers.entries()) {
|
|
79690
79816
|
if (debugOnce) {
|
|
79691
|
-
logDebug(`sendScreenshot peer=${pid}: state=${peer.state}, hasCh=${!!peer.dataChannel}, ssActive=${peer.screenshotActive}, chOpen=${peer.dataChannel?.isOpen?.() ?? "N/A"}, bufSize=${buffer.length}`);
|
|
79817
|
+
logDebug(`sendScreenshot peer=${pid}: state=${peer.state}, hasCh=${!!peer.dataChannel}, ssActive=${peer.screenshotActive}, target=${peer.screenshotTargetSessionId || "none"}, chOpen=${peer.dataChannel?.isOpen?.() ?? "N/A"}, bufSize=${buffer.length}`);
|
|
79692
79818
|
}
|
|
79693
79819
|
if (peer.state !== "connected" || !peer.dataChannel || !peer.screenshotActive) continue;
|
|
79820
|
+
if (targetSessionId && peer.screenshotTargetSessionId !== targetSessionId) continue;
|
|
79694
79821
|
try {
|
|
79695
79822
|
if (!peer.dataChannel.isOpen()) continue;
|
|
79696
79823
|
const header = Buffer.alloc(4);
|
|
@@ -79722,18 +79849,32 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
79722
79849
|
log("Cannot initiate \u2014 node-datachannel not available");
|
|
79723
79850
|
return;
|
|
79724
79851
|
}
|
|
79852
|
+
const pid = peerId || `legacy_${Date.now()}`;
|
|
79853
|
+
const existing = deps.peers.get(pid);
|
|
79854
|
+
if (existing?.state === "connected") {
|
|
79855
|
+
log(`initiateconnection() ignored for peer ${pid} \u2014 already connected`);
|
|
79856
|
+
return;
|
|
79857
|
+
}
|
|
79858
|
+
if (existing?.state === "connecting") {
|
|
79859
|
+
log(`initiateconnection() ignored for peer ${pid} \u2014 connection already in progress`);
|
|
79860
|
+
return;
|
|
79861
|
+
}
|
|
79725
79862
|
const limits = deps.serverConn.getPlanLimits();
|
|
79726
79863
|
if (limits && limits.maxP2PConnections !== -1) {
|
|
79727
79864
|
let connectedCount = 0;
|
|
79865
|
+
let reservedCount = 0;
|
|
79728
79866
|
for (const peer of deps.peers.values()) {
|
|
79729
79867
|
if (peer.state === "connected") connectedCount++;
|
|
79868
|
+
if (peer.state === "connected" || peer.state === "connecting") reservedCount++;
|
|
79730
79869
|
}
|
|
79731
|
-
if (
|
|
79870
|
+
if (reservedCount >= limits.maxP2PConnections) {
|
|
79732
79871
|
let oldestPeer = null;
|
|
79733
|
-
|
|
79734
|
-
|
|
79735
|
-
if (
|
|
79736
|
-
oldestPeer
|
|
79872
|
+
if (connectedCount >= limits.maxP2PConnections) {
|
|
79873
|
+
for (const [peerKey, peer] of deps.peers) {
|
|
79874
|
+
if (peer.state === "connected") {
|
|
79875
|
+
if (!oldestPeer || peer.connectedAt < oldestPeer.at) {
|
|
79876
|
+
oldestPeer = { id: peerKey, at: peer.connectedAt };
|
|
79877
|
+
}
|
|
79737
79878
|
}
|
|
79738
79879
|
}
|
|
79739
79880
|
}
|
|
@@ -79751,19 +79892,12 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
79751
79892
|
}
|
|
79752
79893
|
}
|
|
79753
79894
|
disconnectPeer(deps.peers, oldestPeer.id, deps.notifyStateChange);
|
|
79895
|
+
} else {
|
|
79896
|
+
log(`P2P limit reached (${reservedCount}/${limits.maxP2PConnections}) with reserved connecting slot(s). Rejecting peer ${pid.slice(0, 12)}\u2026`);
|
|
79897
|
+
return;
|
|
79754
79898
|
}
|
|
79755
79899
|
}
|
|
79756
79900
|
}
|
|
79757
|
-
const pid = peerId || `legacy_${Date.now()}`;
|
|
79758
|
-
const existing = deps.peers.get(pid);
|
|
79759
|
-
if (existing?.state === "connected") {
|
|
79760
|
-
log(`initiateconnection() ignored for peer ${pid} \u2014 already connected`);
|
|
79761
|
-
return;
|
|
79762
|
-
}
|
|
79763
|
-
if (existing?.state === "connecting") {
|
|
79764
|
-
log(`initiateconnection() ignored for peer ${pid} \u2014 connection already in progress`);
|
|
79765
|
-
return;
|
|
79766
|
-
}
|
|
79767
79901
|
log(`initiateconnection() for peer ${pid}...`);
|
|
79768
79902
|
const mod = deps.nodeDatachannel;
|
|
79769
79903
|
const PeerConnectionCtor = mod.PeerConnection || mod.default?.PeerConnection || mod.default || mod;
|
|
@@ -80122,14 +80256,19 @@ var init_daemon_p2p = __esm({
|
|
|
80122
80256
|
}
|
|
80123
80257
|
return false;
|
|
80124
80258
|
}
|
|
80125
|
-
/** Get
|
|
80126
|
-
get
|
|
80259
|
+
/** Get all target sessions for active screenshot requests */
|
|
80260
|
+
get screenshotTargetSessionIds() {
|
|
80261
|
+
const targets = /* @__PURE__ */ new Set();
|
|
80127
80262
|
for (const peer of this.peers.values()) {
|
|
80128
80263
|
if (peer.screenshotActive && peer.state === "connected" && peer.screenshotTargetSessionId) {
|
|
80129
|
-
|
|
80264
|
+
targets.add(peer.screenshotTargetSessionId);
|
|
80130
80265
|
}
|
|
80131
80266
|
}
|
|
80132
|
-
return
|
|
80267
|
+
return Array.from(targets);
|
|
80268
|
+
}
|
|
80269
|
+
/** Get the target session for the currently active screenshot request */
|
|
80270
|
+
get screenshotTargetSessionId() {
|
|
80271
|
+
return this.screenshotTargetSessionIds[0];
|
|
80133
80272
|
}
|
|
80134
80273
|
constructor(serverConn) {
|
|
80135
80274
|
this.serverConn = serverConn;
|
|
@@ -80238,6 +80377,14 @@ ${e?.stack || ""}`);
|
|
|
80238
80377
|
}
|
|
80239
80378
|
return false;
|
|
80240
80379
|
}
|
|
80380
|
+
hasAnyNeedingFirstFrameForTarget(targetSessionId) {
|
|
80381
|
+
for (const peer of this.peers.values()) {
|
|
80382
|
+
if (peer.needsFirstFrame && peer.screenshotActive && peer.state === "connected" && peer.screenshotTargetSessionId === targetSessionId) {
|
|
80383
|
+
return true;
|
|
80384
|
+
}
|
|
80385
|
+
}
|
|
80386
|
+
return false;
|
|
80387
|
+
}
|
|
80241
80388
|
onStateChange(listener) {
|
|
80242
80389
|
this.stateListeners.push(listener);
|
|
80243
80390
|
}
|
|
@@ -80301,11 +80448,14 @@ ${e?.stack || ""}`);
|
|
|
80301
80448
|
if (targetPeers.size === 0) return false;
|
|
80302
80449
|
return this.screenshotSender.broadcastSessionOutput(targetPeers, sessionId, data);
|
|
80303
80450
|
}
|
|
80304
|
-
sendScreenshot(base64Data) {
|
|
80305
|
-
return this.screenshotSender.sendScreenshot(this.peers, base64Data);
|
|
80451
|
+
sendScreenshot(base64Data, targetSessionId) {
|
|
80452
|
+
return this.screenshotSender.sendScreenshot(this.peers, base64Data, targetSessionId);
|
|
80453
|
+
}
|
|
80454
|
+
sendScreenshotBuffer(buffer, targetSessionId) {
|
|
80455
|
+
return this.screenshotSender.sendScreenshotBuffer(this.peers, buffer, targetSessionId);
|
|
80306
80456
|
}
|
|
80307
|
-
|
|
80308
|
-
return this.
|
|
80457
|
+
sendScreenshotBufferForTarget(targetSessionId, buffer) {
|
|
80458
|
+
return this.sendScreenshotBuffer(buffer, targetSessionId);
|
|
80309
80459
|
}
|
|
80310
80460
|
// ─── Handler registration (unchanged API) ───────
|
|
80311
80461
|
onFileRequest(handler) {
|
|
@@ -87029,6 +87179,7 @@ var init_screenshot_controller = __esm({
|
|
|
87029
87179
|
lastSize = 0;
|
|
87030
87180
|
lastHash = 0;
|
|
87031
87181
|
staticFrameCount = 0;
|
|
87182
|
+
targetFrameState = /* @__PURE__ */ new Map();
|
|
87032
87183
|
currentInterval;
|
|
87033
87184
|
// Quality profiles
|
|
87034
87185
|
profileDirect;
|
|
@@ -87092,14 +87243,13 @@ var init_screenshot_controller = __esm({
|
|
|
87092
87243
|
async tick() {
|
|
87093
87244
|
if (!this.deps.isRunning()) return;
|
|
87094
87245
|
const active = this.deps.isScreenshotActive();
|
|
87095
|
-
const
|
|
87096
|
-
|
|
87246
|
+
const targetSessionIds = this.getActiveTargetSessionIds();
|
|
87247
|
+
const isRelay = this.deps.isUsingRelay();
|
|
87248
|
+
const profile = isRelay ? this.profileRelay : this.profileDirect;
|
|
87249
|
+
if (active && targetSessionIds.length === 0) {
|
|
87097
87250
|
this.timer = setTimeout(() => this.tick(), 500);
|
|
87098
87251
|
return;
|
|
87099
87252
|
}
|
|
87100
|
-
const cdp = targetSessionId ? this.deps.getCdp(targetSessionId) : null;
|
|
87101
|
-
const isRelay = this.deps.isUsingRelay();
|
|
87102
|
-
const profile = isRelay ? this.profileRelay : this.profileDirect;
|
|
87103
87253
|
this.checkBudgetReset();
|
|
87104
87254
|
if (this.dailyBudgetMs > 0) {
|
|
87105
87255
|
const now = Date.now();
|
|
@@ -87114,49 +87264,84 @@ var init_screenshot_controller = __esm({
|
|
|
87114
87264
|
}
|
|
87115
87265
|
}
|
|
87116
87266
|
const budgetBlocked = this.budgetExhausted && isRelay;
|
|
87117
|
-
if (!active ||
|
|
87267
|
+
if (!active || budgetBlocked) {
|
|
87118
87268
|
this.staticFrameCount = 0;
|
|
87269
|
+
this.targetFrameState.clear();
|
|
87119
87270
|
this.currentInterval = profile.maxInterval;
|
|
87120
87271
|
if (!active) this.lastActiveTimestamp = 0;
|
|
87121
87272
|
this.timer = setTimeout(() => this.tick(), budgetBlocked ? 3e4 : this.currentInterval);
|
|
87122
87273
|
return;
|
|
87123
87274
|
}
|
|
87124
87275
|
this.debugCount++;
|
|
87125
|
-
|
|
87126
|
-
|
|
87127
|
-
|
|
87276
|
+
let capturedAny = false;
|
|
87277
|
+
let sentAnyFrame = false;
|
|
87278
|
+
let anyFirstFrameAcrossTargets = false;
|
|
87279
|
+
for (const targetSessionId of targetSessionIds) {
|
|
87280
|
+
const cdp = this.deps.getCdp(targetSessionId);
|
|
87281
|
+
if (!cdp) continue;
|
|
87282
|
+
try {
|
|
87283
|
+
const buf = await cdp.captureScreenshot({ quality: profile.quality });
|
|
87284
|
+
if (!buf) {
|
|
87285
|
+
if (this.debugCount <= 5) LOG.debug("Screenshot", `captureScreenshot returned null for target=${targetSessionId}`);
|
|
87286
|
+
continue;
|
|
87287
|
+
}
|
|
87288
|
+
capturedAny = true;
|
|
87289
|
+
const state = this.getTargetFrameState(targetSessionId);
|
|
87128
87290
|
const hash2 = _ScreenshotController.fnvHash(buf);
|
|
87129
|
-
const sizeMatch = buf.length ===
|
|
87130
|
-
const hashMatch = hash2 ===
|
|
87131
|
-
const anyNeedsFirstFrame = this.deps.hasAnyNeedingFirstFrame();
|
|
87291
|
+
const sizeMatch = buf.length === state.lastSize;
|
|
87292
|
+
const hashMatch = hash2 === state.lastHash;
|
|
87293
|
+
const anyNeedsFirstFrame = this.deps.hasAnyNeedingFirstFrameForTarget?.(targetSessionId) ?? this.deps.hasAnyNeedingFirstFrame();
|
|
87132
87294
|
const resizeTarget = anyNeedsFirstFrame ? profile.firstFrameLongEdge : profile.maxLongEdge;
|
|
87295
|
+
anyFirstFrameAcrossTargets = anyFirstFrameAcrossTargets || anyNeedsFirstFrame;
|
|
87133
87296
|
if (sizeMatch && hashMatch && !anyNeedsFirstFrame) {
|
|
87134
|
-
|
|
87135
|
-
if (
|
|
87297
|
+
state.staticFrameCount++;
|
|
87298
|
+
if (state.staticFrameCount >= this.STATIC_THRESHOLD) {
|
|
87136
87299
|
this.currentInterval = Math.min(this.currentInterval + 200, profile.maxInterval);
|
|
87137
87300
|
}
|
|
87138
87301
|
if (this.debugCount <= 5 || this.debugCount % 50 === 0) {
|
|
87139
|
-
LOG.debug("Screenshot", `skip (unchanged, static=${
|
|
87140
|
-
}
|
|
87141
|
-
} else {
|
|
87142
|
-
const normalizedBuf = await this.normalizeBuffer(buf, resizeTarget, profile.quality);
|
|
87143
|
-
this.lastSize = buf.length;
|
|
87144
|
-
this.lastHash = hash2;
|
|
87145
|
-
this.staticFrameCount = 0;
|
|
87146
|
-
this.currentInterval = profile.minInterval;
|
|
87147
|
-
const sent = this.deps.sendScreenshotBuffer(normalizedBuf);
|
|
87148
|
-
if (this.debugCount <= 3 || anyNeedsFirstFrame) {
|
|
87149
|
-
LOG.debug("Screenshot", `sent: ${normalizedBuf.length} bytes, delivered=${sent}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
|
|
87302
|
+
LOG.debug("Screenshot", `skip target=${targetSessionId} (unchanged, static=${state.staticFrameCount}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"})`);
|
|
87150
87303
|
}
|
|
87304
|
+
continue;
|
|
87151
87305
|
}
|
|
87152
|
-
|
|
87153
|
-
|
|
87306
|
+
const normalizedBuf = await this.normalizeBuffer(buf, resizeTarget, profile.quality);
|
|
87307
|
+
state.lastSize = buf.length;
|
|
87308
|
+
state.lastHash = hash2;
|
|
87309
|
+
state.staticFrameCount = 0;
|
|
87310
|
+
this.lastSize = buf.length;
|
|
87311
|
+
this.lastHash = hash2;
|
|
87312
|
+
this.staticFrameCount = 0;
|
|
87313
|
+
this.currentInterval = profile.minInterval;
|
|
87314
|
+
const sent = this.deps.sendScreenshotBufferForTarget ? this.deps.sendScreenshotBufferForTarget(targetSessionId, normalizedBuf) : this.deps.sendScreenshotBuffer(normalizedBuf);
|
|
87315
|
+
sentAnyFrame = sentAnyFrame || sent;
|
|
87316
|
+
if (this.debugCount <= 3 || anyNeedsFirstFrame) {
|
|
87317
|
+
LOG.debug("Screenshot", `sent target=${targetSessionId}: ${normalizedBuf.length} bytes, delivered=${sent}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
|
|
87318
|
+
}
|
|
87319
|
+
} catch (e) {
|
|
87320
|
+
if (this.debugCount <= 5) LOG.warn("Screenshot", `error target=${targetSessionId}: ${e?.message}`);
|
|
87154
87321
|
}
|
|
87155
|
-
}
|
|
87156
|
-
|
|
87322
|
+
}
|
|
87323
|
+
if (!capturedAny) {
|
|
87324
|
+
this.currentInterval = profile.maxInterval;
|
|
87325
|
+
} else if (!sentAnyFrame && !anyFirstFrameAcrossTargets) {
|
|
87326
|
+
this.currentInterval = Math.min(this.currentInterval + 200, profile.maxInterval);
|
|
87157
87327
|
}
|
|
87158
87328
|
this.timer = setTimeout(() => this.tick(), this.currentInterval);
|
|
87159
87329
|
}
|
|
87330
|
+
getActiveTargetSessionIds() {
|
|
87331
|
+
const explicitTargets = this.deps.getScreenshotTargetSessionIds?.() || [];
|
|
87332
|
+
const normalized = explicitTargets.map((target) => typeof target === "string" ? target.trim() : "").filter((target) => target.length > 0);
|
|
87333
|
+
if (normalized.length > 0) return Array.from(new Set(normalized));
|
|
87334
|
+
const legacyTarget = this.deps.getScreenshotTargetSessionId();
|
|
87335
|
+
return legacyTarget ? [legacyTarget] : [];
|
|
87336
|
+
}
|
|
87337
|
+
getTargetFrameState(targetSessionId) {
|
|
87338
|
+
let state = this.targetFrameState.get(targetSessionId);
|
|
87339
|
+
if (!state) {
|
|
87340
|
+
state = { lastSize: 0, lastHash: 0, staticFrameCount: 0 };
|
|
87341
|
+
this.targetFrameState.set(targetSessionId, state);
|
|
87342
|
+
}
|
|
87343
|
+
return state;
|
|
87344
|
+
}
|
|
87160
87345
|
// ─── Budget ───────────────────────────────────
|
|
87161
87346
|
checkBudgetReset() {
|
|
87162
87347
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -87373,7 +87558,7 @@ function killPid2(pid) {
|
|
|
87373
87558
|
return false;
|
|
87374
87559
|
}
|
|
87375
87560
|
}
|
|
87376
|
-
function
|
|
87561
|
+
function getWindowsProcessCommandLine2(pid) {
|
|
87377
87562
|
const pidFilter = `ProcessId=${pid}`;
|
|
87378
87563
|
try {
|
|
87379
87564
|
const psOut = (0, import_child_process13.execFileSync)("powershell.exe", [
|
|
@@ -87402,13 +87587,32 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
87402
87587
|
}
|
|
87403
87588
|
return null;
|
|
87404
87589
|
}
|
|
87590
|
+
function getProcessCommandLine2(pid) {
|
|
87591
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
87592
|
+
if (process.platform === "win32") return getWindowsProcessCommandLine2(pid);
|
|
87593
|
+
try {
|
|
87594
|
+
const text = (0, import_child_process13.execFileSync)("ps", ["-o", "command=", "-p", String(pid)], {
|
|
87595
|
+
encoding: "utf8",
|
|
87596
|
+
timeout: 3e3,
|
|
87597
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
87598
|
+
}).trim();
|
|
87599
|
+
return text || null;
|
|
87600
|
+
} catch {
|
|
87601
|
+
return null;
|
|
87602
|
+
}
|
|
87603
|
+
}
|
|
87604
|
+
function isManagedSessionHostPid2(pid) {
|
|
87605
|
+
const commandLine = getProcessCommandLine2(pid);
|
|
87606
|
+
if (!commandLine) return false;
|
|
87607
|
+
return /session-host-daemon/i.test(commandLine);
|
|
87608
|
+
}
|
|
87405
87609
|
function stopManagedSessionHostProcess() {
|
|
87406
87610
|
let stopped = false;
|
|
87407
87611
|
const pidFile = getSessionHostPidFile();
|
|
87408
87612
|
try {
|
|
87409
87613
|
if (fs22.existsSync(pidFile)) {
|
|
87410
87614
|
const pid = Number.parseInt(fs22.readFileSync(pidFile, "utf8").trim(), 10);
|
|
87411
|
-
if (Number.isFinite(pid) && pid !== process.pid) {
|
|
87615
|
+
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid2(pid)) {
|
|
87412
87616
|
stopped = killPid2(pid) || stopped;
|
|
87413
87617
|
}
|
|
87414
87618
|
}
|
|
@@ -87422,40 +87626,7 @@ function stopManagedSessionHostProcess() {
|
|
|
87422
87626
|
return stopped;
|
|
87423
87627
|
}
|
|
87424
87628
|
function stopSessionHost() {
|
|
87425
|
-
|
|
87426
|
-
if (process.platform === "win32") {
|
|
87427
|
-
try {
|
|
87428
|
-
const raw = (0, import_child_process13.execFileSync)("tasklist", ["/FO", "CSV", "/NH", "/FI", "IMAGENAME eq node.exe"], {
|
|
87429
|
-
encoding: "utf8",
|
|
87430
|
-
timeout: 5e3,
|
|
87431
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
87432
|
-
windowsHide: true
|
|
87433
|
-
}).trim();
|
|
87434
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
87435
|
-
const match = line.match(/^"node\.exe","(\d+)"/i);
|
|
87436
|
-
if (!match) continue;
|
|
87437
|
-
const candidatePid = Number.parseInt(match[1], 10);
|
|
87438
|
-
if (!Number.isFinite(candidatePid) || candidatePid === process.pid) continue;
|
|
87439
|
-
const commandLine = getWindowsProcessCommandLine(candidatePid);
|
|
87440
|
-
if (commandLine?.includes("session-host-daemon")) {
|
|
87441
|
-
stopped = killPid2(candidatePid) || stopped;
|
|
87442
|
-
}
|
|
87443
|
-
}
|
|
87444
|
-
} catch {
|
|
87445
|
-
}
|
|
87446
|
-
} else {
|
|
87447
|
-
try {
|
|
87448
|
-
const raw = (0, import_child_process13.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
87449
|
-
for (const line of raw.split("\n")) {
|
|
87450
|
-
const pid = Number.parseInt(line.trim(), 10);
|
|
87451
|
-
if (Number.isFinite(pid) && pid !== process.pid && pid !== process.ppid) {
|
|
87452
|
-
stopped = killPid2(pid) || stopped;
|
|
87453
|
-
}
|
|
87454
|
-
}
|
|
87455
|
-
} catch {
|
|
87456
|
-
}
|
|
87457
|
-
}
|
|
87458
|
-
return stopped;
|
|
87629
|
+
return stopManagedSessionHostProcess();
|
|
87459
87630
|
}
|
|
87460
87631
|
async function ensureSessionHostReady2() {
|
|
87461
87632
|
const quarantine = quarantineLegacyStandaloneSessions({
|
|
@@ -87712,10 +87883,65 @@ var init_session_host_controller = __esm({
|
|
|
87712
87883
|
var adhdev_daemon_exports = {};
|
|
87713
87884
|
__export(adhdev_daemon_exports, {
|
|
87714
87885
|
AdhdevDaemon: () => AdhdevDaemon,
|
|
87886
|
+
buildMandatoryUpdateInfoFromServerPayload: () => buildMandatoryUpdateInfoFromServerPayload,
|
|
87887
|
+
buildMandatoryUpdateRequiredPayload: () => buildMandatoryUpdateRequiredPayload,
|
|
87715
87888
|
getDaemonPid: () => getDaemonPid,
|
|
87716
87889
|
isDaemonRunning: () => isDaemonRunning,
|
|
87717
|
-
stopDaemon: () => stopDaemon
|
|
87718
|
-
|
|
87890
|
+
stopDaemon: () => stopDaemon,
|
|
87891
|
+
validateMandatoryUpdateTarget: () => validateMandatoryUpdateTarget,
|
|
87892
|
+
verifyPublishedMandatoryUpdateTarget: () => verifyPublishedMandatoryUpdateTarget
|
|
87893
|
+
});
|
|
87894
|
+
function validateMandatoryUpdateTarget(targetVersion) {
|
|
87895
|
+
if (typeof targetVersion !== "string") return { valid: false, error: "target version is required" };
|
|
87896
|
+
if (targetVersion !== targetVersion.trim()) return { valid: false, error: "target version must not contain whitespace" };
|
|
87897
|
+
const version2 = targetVersion;
|
|
87898
|
+
if (!version2) return { valid: false, error: "target version is required" };
|
|
87899
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z]+(?:\.[0-9A-Za-z]+)*)?(?:\+[0-9A-Za-z]+(?:\.[0-9A-Za-z]+)*)?$/.test(version2)) {
|
|
87900
|
+
return { valid: false, error: `invalid semver target: ${version2}` };
|
|
87901
|
+
}
|
|
87902
|
+
return { valid: true };
|
|
87903
|
+
}
|
|
87904
|
+
function verifyPublishedMandatoryUpdateTarget(packageName, targetVersion, deps = {}) {
|
|
87905
|
+
if (!/^(?:adhdev|@adhdev\/daemon-standalone)$/.test(packageName)) {
|
|
87906
|
+
throw new Error(`invalid mandatory update package: ${packageName}`);
|
|
87907
|
+
}
|
|
87908
|
+
const validation = validateMandatoryUpdateTarget(targetVersion);
|
|
87909
|
+
if (!validation.valid) throw new Error(validation.error || "invalid mandatory update target");
|
|
87910
|
+
const run = deps.execFileSync || import_child_process14.execFileSync;
|
|
87911
|
+
const npmExecutable = deps.npmExecutable || resolveCurrentGlobalInstallSurface({ packageName }).npmExecutable;
|
|
87912
|
+
const published = String(run(npmExecutable, ["view", `${packageName}@${targetVersion}`, "version"], {
|
|
87913
|
+
encoding: "utf-8",
|
|
87914
|
+
timeout: 1e4,
|
|
87915
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
87916
|
+
...process.platform === "win32" ? { shell: true, windowsHide: true } : {}
|
|
87917
|
+
})).trim();
|
|
87918
|
+
if (published !== targetVersion) {
|
|
87919
|
+
throw new Error(`Published version mismatch: expected ${targetVersion}, got ${published || "unknown"}`);
|
|
87920
|
+
}
|
|
87921
|
+
return published;
|
|
87922
|
+
}
|
|
87923
|
+
function buildMandatoryUpdateInfoFromServerPayload(payload, fallbackVersion) {
|
|
87924
|
+
const targetVersion = typeof payload?.latest === "string" && payload.latest ? payload.latest : fallbackVersion;
|
|
87925
|
+
const validation = validateMandatoryUpdateTarget(targetVersion);
|
|
87926
|
+
if (!validation.valid) return { info: null, error: validation.error || targetVersion };
|
|
87927
|
+
return {
|
|
87928
|
+
info: {
|
|
87929
|
+
targetVersion,
|
|
87930
|
+
reason: typeof payload?.reason === "string" && payload.reason.trim() ? payload.reason.trim() : "major_minor_mismatch",
|
|
87931
|
+
minVersion: typeof payload?.minVersion === "string" && payload.minVersion.trim() ? payload.minVersion.trim() : void 0
|
|
87932
|
+
}
|
|
87933
|
+
};
|
|
87934
|
+
}
|
|
87935
|
+
function buildMandatoryUpdateRequiredPayload(pending, interactionId) {
|
|
87936
|
+
return {
|
|
87937
|
+
error: "A mandatory daemon update is pending. Finish current work and let the daemon update before starting a new session.",
|
|
87938
|
+
code: "DAEMON_UPDATE_REQUIRED",
|
|
87939
|
+
required: true,
|
|
87940
|
+
latest: pending.targetVersion,
|
|
87941
|
+
reason: pending.reason,
|
|
87942
|
+
interactionId
|
|
87943
|
+
};
|
|
87944
|
+
}
|
|
87719
87945
|
function resolveDaemonPort(ref = {}) {
|
|
87720
87946
|
return Number.isFinite(ref.port) && Number(ref.port) > 0 ? Number(ref.port) : DEFAULT_DAEMON_PORT;
|
|
87721
87947
|
}
|
|
@@ -87742,7 +87968,7 @@ function removeDaemonPid(ref = {}) {
|
|
|
87742
87968
|
function isDaemonRunning(ref = {}) {
|
|
87743
87969
|
const port = resolveDaemonPort(ref);
|
|
87744
87970
|
try {
|
|
87745
|
-
const { execFileSync:
|
|
87971
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
87746
87972
|
const probe = `
|
|
87747
87973
|
const http = require('http');
|
|
87748
87974
|
const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
|
|
@@ -87752,7 +87978,7 @@ function isDaemonRunning(ref = {}) {
|
|
|
87752
87978
|
req.on('error', () => process.stdout.write('0'));
|
|
87753
87979
|
req.on('timeout', () => { req.destroy(); process.stdout.write('0'); });
|
|
87754
87980
|
`;
|
|
87755
|
-
const result =
|
|
87981
|
+
const result = execFileSync7(process.execPath, ["-e", probe], {
|
|
87756
87982
|
encoding: "utf-8",
|
|
87757
87983
|
timeout: 3e3,
|
|
87758
87984
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -87778,9 +88004,9 @@ function isDaemonRunning(ref = {}) {
|
|
|
87778
88004
|
function isAdhdevProcess(pid) {
|
|
87779
88005
|
try {
|
|
87780
88006
|
if (process.platform === "win32") {
|
|
87781
|
-
const { execFileSync:
|
|
88007
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
87782
88008
|
try {
|
|
87783
|
-
const psOut =
|
|
88009
|
+
const psOut = execFileSync7("powershell.exe", [
|
|
87784
88010
|
"-NoProfile",
|
|
87785
88011
|
"-NonInteractive",
|
|
87786
88012
|
"-ExecutionPolicy",
|
|
@@ -87793,8 +88019,8 @@ function isAdhdevProcess(pid) {
|
|
|
87793
88019
|
return true;
|
|
87794
88020
|
}
|
|
87795
88021
|
} else {
|
|
87796
|
-
const { execFileSync:
|
|
87797
|
-
const cmdline =
|
|
88022
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
88023
|
+
const cmdline = execFileSync7("ps", ["-o", "command=", "-p", String(pid)], {
|
|
87798
88024
|
encoding: "utf-8",
|
|
87799
88025
|
timeout: 2e3,
|
|
87800
88026
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -87808,7 +88034,7 @@ function isAdhdevProcess(pid) {
|
|
|
87808
88034
|
function getDaemonHealthPid(ref = {}) {
|
|
87809
88035
|
const port = resolveDaemonPort(ref);
|
|
87810
88036
|
try {
|
|
87811
|
-
const { execFileSync:
|
|
88037
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
87812
88038
|
const probe = `
|
|
87813
88039
|
const http = require('http');
|
|
87814
88040
|
const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
|
|
@@ -87826,7 +88052,7 @@ function getDaemonHealthPid(ref = {}) {
|
|
|
87826
88052
|
req.on('error', () => {});
|
|
87827
88053
|
req.on('timeout', () => { req.destroy(); });
|
|
87828
88054
|
`;
|
|
87829
|
-
const result =
|
|
88055
|
+
const result = execFileSync7(process.execPath, ["-e", probe], {
|
|
87830
88056
|
encoding: "utf-8",
|
|
87831
88057
|
timeout: 3e3,
|
|
87832
88058
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -87872,7 +88098,7 @@ function stopDaemon(ref = {}) {
|
|
|
87872
88098
|
return false;
|
|
87873
88099
|
}
|
|
87874
88100
|
}
|
|
87875
|
-
var os28, fs23, path29, import_http, import_ws3, pkgVersion, AdhdevDaemon;
|
|
88101
|
+
var os28, fs23, path29, import_http, import_child_process14, import_ws3, pkgVersion, AdhdevDaemon;
|
|
87876
88102
|
var init_adhdev_daemon = __esm({
|
|
87877
88103
|
"src/adhdev-daemon.ts"() {
|
|
87878
88104
|
"use strict";
|
|
@@ -87888,12 +88114,13 @@ var init_adhdev_daemon = __esm({
|
|
|
87888
88114
|
fs23 = __toESM(require("fs"));
|
|
87889
88115
|
path29 = __toESM(require("path"));
|
|
87890
88116
|
import_http = require("http");
|
|
88117
|
+
import_child_process14 = require("child_process");
|
|
87891
88118
|
import_ws3 = require("ws");
|
|
87892
88119
|
init_source();
|
|
87893
88120
|
init_version();
|
|
87894
88121
|
init_src();
|
|
87895
88122
|
init_runtime_defaults();
|
|
87896
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
88123
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.34" });
|
|
87897
88124
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
87898
88125
|
localHttpServer = null;
|
|
87899
88126
|
localWss = null;
|
|
@@ -87986,6 +88213,10 @@ var init_adhdev_daemon = __esm({
|
|
|
87986
88213
|
getUpgradePackageName() {
|
|
87987
88214
|
return process.argv[1]?.includes("daemon-standalone") ? "@adhdev/daemon-standalone" : "adhdev";
|
|
87988
88215
|
}
|
|
88216
|
+
getMandatoryUpdateBlockPayload(cmd, interactionId) {
|
|
88217
|
+
if (!this.pendingMandatoryUpdate || !_AdhdevDaemon.MANDATORY_UPDATE_BLOCKED_COMMANDS.has(cmd)) return null;
|
|
88218
|
+
return buildMandatoryUpdateRequiredPayload(this.pendingMandatoryUpdate, interactionId);
|
|
88219
|
+
}
|
|
87989
88220
|
hasBlockingSessionsForMandatoryUpdate() {
|
|
87990
88221
|
if (!this.components) return false;
|
|
87991
88222
|
const blocking = /* @__PURE__ */ new Set(["generating", "waiting_approval", "starting"]);
|
|
@@ -88011,15 +88242,7 @@ var init_adhdev_daemon = __esm({
|
|
|
88011
88242
|
const pkgName = this.getUpgradePackageName();
|
|
88012
88243
|
this.mandatoryUpgradeInFlight = true;
|
|
88013
88244
|
try {
|
|
88014
|
-
|
|
88015
|
-
const published = execSync8(`npm view ${pkgName}@${pending.targetVersion} version`, {
|
|
88016
|
-
encoding: "utf-8",
|
|
88017
|
-
timeout: 1e4,
|
|
88018
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
88019
|
-
}).trim();
|
|
88020
|
-
if (published !== pending.targetVersion) {
|
|
88021
|
-
throw new Error(`Published version mismatch: expected ${pending.targetVersion}, got ${published || "unknown"}`);
|
|
88022
|
-
}
|
|
88245
|
+
verifyPublishedMandatoryUpdateTarget(pkgName, pending.targetVersion);
|
|
88023
88246
|
LOG.warn("Upgrade", `Applying mandatory daemon update (${pending.reason}) \u2192 v${pending.targetVersion}`);
|
|
88024
88247
|
spawnDetachedDaemonUpgradeHelper({
|
|
88025
88248
|
packageName: pkgName,
|
|
@@ -88121,7 +88344,7 @@ var init_adhdev_daemon = __esm({
|
|
|
88121
88344
|
const now = Date.now();
|
|
88122
88345
|
const cached2 = this.hotChatSnapshotCache;
|
|
88123
88346
|
const sessions = cached2 && now - cached2.builtAt < _AdhdevDaemon.HOT_CHAT_SNAPSHOT_CACHE_TTL_MS ? cached2.sessions : (() => {
|
|
88124
|
-
const built = this.
|
|
88347
|
+
const built = this.components.instanceManager.collectHotChatSessionStates();
|
|
88125
88348
|
this.hotChatSnapshotCache = { sessions: built, builtAt: now };
|
|
88126
88349
|
return built;
|
|
88127
88350
|
})();
|
|
@@ -88506,14 +88729,17 @@ ${err?.stack || ""}`);
|
|
|
88506
88729
|
isRunning: () => this.running,
|
|
88507
88730
|
isScreenshotActive: () => this.p2p?.screenshotActive ?? false,
|
|
88508
88731
|
getScreenshotTargetSessionId: () => this.p2p?.screenshotTargetSessionId,
|
|
88732
|
+
getScreenshotTargetSessionIds: () => this.p2p?.screenshotTargetSessionIds ?? [],
|
|
88509
88733
|
isUsingRelay: () => this.p2p?.isUsingRelay ?? false,
|
|
88510
88734
|
hasAnyNeedingFirstFrame: () => this.p2p?.hasAnyNeedingFirstFrame() ?? false,
|
|
88735
|
+
hasAnyNeedingFirstFrameForTarget: (targetSessionId) => this.p2p?.hasAnyNeedingFirstFrameForTarget(targetSessionId) ?? false,
|
|
88511
88736
|
getCdp: (targetSessionId) => {
|
|
88512
88737
|
if (targetSessionId) return this.getCdpFor(targetSessionId);
|
|
88513
88738
|
LOG.warn("P2P", "Screenshot requested without targetSessionId \u2014 cannot determine target session. Skipping frame.");
|
|
88514
88739
|
return null;
|
|
88515
88740
|
},
|
|
88516
|
-
sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf)
|
|
88741
|
+
sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf),
|
|
88742
|
+
sendScreenshotBufferForTarget: (targetSessionId, buf) => this.p2p.sendScreenshotBufferForTarget(targetSessionId, buf)
|
|
88517
88743
|
}, planLimits ?? void 0);
|
|
88518
88744
|
this.screenshotController.start();
|
|
88519
88745
|
this.p2p.onScreenshotStart(() => this.screenshotController?.triggerImmediate());
|
|
@@ -88542,11 +88768,12 @@ ${err?.stack || ""}`);
|
|
|
88542
88768
|
});
|
|
88543
88769
|
this.serverConn.on("force_update_required", (msg) => {
|
|
88544
88770
|
const payload = msg.payload;
|
|
88545
|
-
|
|
88546
|
-
|
|
88547
|
-
|
|
88548
|
-
|
|
88549
|
-
}
|
|
88771
|
+
const parsedUpdate = buildMandatoryUpdateInfoFromServerPayload(payload, pkgVersion);
|
|
88772
|
+
if (!parsedUpdate.info) {
|
|
88773
|
+
LOG.error("Upgrade", `Ignoring invalid mandatory daemon update target from server: ${parsedUpdate.error || "unknown"}`);
|
|
88774
|
+
return;
|
|
88775
|
+
}
|
|
88776
|
+
this.pendingMandatoryUpdate = parsedUpdate.info;
|
|
88550
88777
|
LOG.warn("Upgrade", `Mandatory daemon update required (${this.pendingMandatoryUpdate.reason})`);
|
|
88551
88778
|
void this.maybeApplyMandatoryUpdate("server-force-update");
|
|
88552
88779
|
});
|
|
@@ -88657,15 +88884,9 @@ ${err?.stack || ""}`);
|
|
|
88657
88884
|
const cmdStart = Date.now();
|
|
88658
88885
|
const source = msg.ipcWs ? "ext" : typeof msg.source === "string" && msg.source.trim() ? msg.source : "ws";
|
|
88659
88886
|
try {
|
|
88660
|
-
|
|
88661
|
-
|
|
88662
|
-
|
|
88663
|
-
code: "DAEMON_UPDATE_REQUIRED",
|
|
88664
|
-
required: true,
|
|
88665
|
-
latest: this.pendingMandatoryUpdate.targetVersion,
|
|
88666
|
-
reason: this.pendingMandatoryUpdate.reason,
|
|
88667
|
-
interactionId
|
|
88668
|
-
});
|
|
88887
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(cmd, interactionId);
|
|
88888
|
+
if (mandatoryUpdateBlock) {
|
|
88889
|
+
this.sendResult(msg, false, mandatoryUpdateBlock);
|
|
88669
88890
|
return;
|
|
88670
88891
|
}
|
|
88671
88892
|
if (source === "api" && !loadConfig().allowServerApiProxy) {
|
|
@@ -88710,6 +88931,10 @@ ${err?.stack || ""}`);
|
|
|
88710
88931
|
const interactionId = String(normalizedData._interactionId);
|
|
88711
88932
|
const cmdStart = Date.now();
|
|
88712
88933
|
try {
|
|
88934
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(cmdType, interactionId);
|
|
88935
|
+
if (mandatoryUpdateBlock) {
|
|
88936
|
+
return { success: false, ...mandatoryUpdateBlock };
|
|
88937
|
+
}
|
|
88713
88938
|
switch (cmdType) {
|
|
88714
88939
|
case "get_runtime_snapshot": {
|
|
88715
88940
|
const sessionId = typeof normalizedData.sessionId === "string" ? normalizedData.sessionId : "";
|
|
@@ -88888,8 +89113,22 @@ ${err?.stack || ""}`);
|
|
|
88888
89113
|
}));
|
|
88889
89114
|
return;
|
|
88890
89115
|
}
|
|
89116
|
+
const normalizedArgs = this.ensureInteractionContext(args);
|
|
89117
|
+
const interactionId = String(normalizedArgs._interactionId);
|
|
89118
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(command, interactionId);
|
|
89119
|
+
if (mandatoryUpdateBlock) {
|
|
89120
|
+
ws.send(JSON.stringify({
|
|
89121
|
+
type: "ext:command_result",
|
|
89122
|
+
payload: {
|
|
89123
|
+
requestId,
|
|
89124
|
+
success: false,
|
|
89125
|
+
...mandatoryUpdateBlock
|
|
89126
|
+
}
|
|
89127
|
+
}));
|
|
89128
|
+
return;
|
|
89129
|
+
}
|
|
88891
89130
|
try {
|
|
88892
|
-
const result = await this.components.router.execute(command,
|
|
89131
|
+
const result = await this.components.router.execute(command, normalizedArgs, "ipc");
|
|
88893
89132
|
ws.send(JSON.stringify({
|
|
88894
89133
|
type: "ext:command_result",
|
|
88895
89134
|
payload: {
|
|
@@ -89059,9 +89298,9 @@ async function runWizard(options = {}) {
|
|
|
89059
89298
|
}
|
|
89060
89299
|
async function checkForUpdate() {
|
|
89061
89300
|
try {
|
|
89062
|
-
const { execFileSync:
|
|
89301
|
+
const { execFileSync: execFileSync7 } = await import("child_process");
|
|
89063
89302
|
const currentVersion = resolvePackageVersion();
|
|
89064
|
-
const latestVersion = readLatestPublishedCliVersion(
|
|
89303
|
+
const latestVersion = readLatestPublishedCliVersion(execFileSync7);
|
|
89065
89304
|
if (!latestVersion) return;
|
|
89066
89305
|
if (!currentVersion || !latestVersion || currentVersion === latestVersion) return;
|
|
89067
89306
|
console.log(source_default.yellow(` Update available: ${currentVersion} \u2192 ${latestVersion}`));
|
|
@@ -89078,7 +89317,7 @@ async function checkForUpdate() {
|
|
|
89078
89317
|
const spinner = (await Promise.resolve().then(() => (init_ora(), ora_exports))).default("Updating adhdev CLI...").start();
|
|
89079
89318
|
try {
|
|
89080
89319
|
const installCommand = buildPinnedGlobalInstallCommand({ packageName: "adhdev", targetVersion: "latest" });
|
|
89081
|
-
|
|
89320
|
+
execFileSync7(installCommand.command, installCommand.args, {
|
|
89082
89321
|
encoding: "utf-8",
|
|
89083
89322
|
timeout: 6e4,
|
|
89084
89323
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -92373,7 +92612,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
|
|
|
92373
92612
|
|
|
92374
92613
|
// src/cli/doctor-commands.ts
|
|
92375
92614
|
init_source();
|
|
92376
|
-
var
|
|
92615
|
+
var import_child_process15 = require("child_process");
|
|
92377
92616
|
var fs26 = __toESM(require("fs"));
|
|
92378
92617
|
var os30 = __toESM(require("os"));
|
|
92379
92618
|
var path33 = __toESM(require("path"));
|
|
@@ -93015,7 +93254,7 @@ function findCommandPaths(command) {
|
|
|
93015
93254
|
try {
|
|
93016
93255
|
const bin = process.platform === "win32" ? "where.exe" : "which";
|
|
93017
93256
|
const args = process.platform === "win32" ? [command] : ["-a", command];
|
|
93018
|
-
const output = (0,
|
|
93257
|
+
const output = (0, import_child_process15.execFileSync)(bin, args, {
|
|
93019
93258
|
encoding: "utf-8",
|
|
93020
93259
|
stdio: ["ignore", "pipe", "ignore"]
|
|
93021
93260
|
});
|
|
@@ -93030,7 +93269,7 @@ function probeCliBinary(commandPath, currentVersion) {
|
|
|
93030
93269
|
currentVersion
|
|
93031
93270
|
};
|
|
93032
93271
|
try {
|
|
93033
|
-
probe.version = (0,
|
|
93272
|
+
probe.version = (0, import_child_process15.execFileSync)(commandPath, ["--version"], {
|
|
93034
93273
|
encoding: "utf-8",
|
|
93035
93274
|
stdio: ["ignore", "pipe", "pipe"]
|
|
93036
93275
|
}).trim();
|
|
@@ -93038,7 +93277,7 @@ function probeCliBinary(commandPath, currentVersion) {
|
|
|
93038
93277
|
probe.versionError = error48?.stderr?.toString?.().trim() || error48?.message || "version probe failed";
|
|
93039
93278
|
}
|
|
93040
93279
|
try {
|
|
93041
|
-
probe.helpText = (0,
|
|
93280
|
+
probe.helpText = (0, import_child_process15.execFileSync)(commandPath, ["--help"], {
|
|
93042
93281
|
encoding: "utf-8",
|
|
93043
93282
|
stdio: ["ignore", "pipe", "pipe"]
|
|
93044
93283
|
});
|