adhdev 0.9.32 → 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 +450 -157
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +450 -157
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -7981,6 +7981,26 @@ function toHistoryPersistedMessages(messages) {
|
|
|
7981
7981
|
historyDedupKey: deriveHistoryDedupKey(message)
|
|
7982
7982
|
}));
|
|
7983
7983
|
}
|
|
7984
|
+
function findLastMessageIndexBySignature(messages, signature) {
|
|
7985
|
+
if (!signature) return -1;
|
|
7986
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
7987
|
+
if (getChatMessageSignature(messages[index]) === signature) {
|
|
7988
|
+
return index;
|
|
7989
|
+
}
|
|
7990
|
+
}
|
|
7991
|
+
return -1;
|
|
7992
|
+
}
|
|
7993
|
+
function buildBoundedTailSync(messages, cursor) {
|
|
7994
|
+
const totalMessages = messages.length;
|
|
7995
|
+
const tailMessages = cursor.tailLimit > 0 && totalMessages > cursor.tailLimit ? messages.slice(-cursor.tailLimit) : messages;
|
|
7996
|
+
return {
|
|
7997
|
+
syncMode: "full",
|
|
7998
|
+
replaceFrom: 0,
|
|
7999
|
+
messages: tailMessages,
|
|
8000
|
+
totalMessages,
|
|
8001
|
+
lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
|
|
8002
|
+
};
|
|
8003
|
+
}
|
|
7984
8004
|
function computeReadChatSync(messages, cursor) {
|
|
7985
8005
|
const totalMessages = messages.length;
|
|
7986
8006
|
const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
|
|
@@ -8012,6 +8032,15 @@ function computeReadChatSync(messages, cursor) {
|
|
|
8012
8032
|
lastMessageSignature
|
|
8013
8033
|
};
|
|
8014
8034
|
}
|
|
8035
|
+
if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
|
|
8036
|
+
return {
|
|
8037
|
+
syncMode: "noop",
|
|
8038
|
+
replaceFrom: totalMessages,
|
|
8039
|
+
messages: [],
|
|
8040
|
+
totalMessages,
|
|
8041
|
+
lastMessageSignature
|
|
8042
|
+
};
|
|
8043
|
+
}
|
|
8015
8044
|
if (knownMessageCount < totalMessages) {
|
|
8016
8045
|
const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
|
|
8017
8046
|
if (anchorSignature === knownSignature) {
|
|
@@ -8023,6 +8052,19 @@ function computeReadChatSync(messages, cursor) {
|
|
|
8023
8052
|
lastMessageSignature
|
|
8024
8053
|
};
|
|
8025
8054
|
}
|
|
8055
|
+
if (cursor.tailLimit > 0) {
|
|
8056
|
+
const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
|
|
8057
|
+
if (signatureIndex >= 0) {
|
|
8058
|
+
return {
|
|
8059
|
+
syncMode: "append",
|
|
8060
|
+
replaceFrom: knownMessageCount,
|
|
8061
|
+
messages: messages.slice(signatureIndex + 1),
|
|
8062
|
+
totalMessages,
|
|
8063
|
+
lastMessageSignature
|
|
8064
|
+
};
|
|
8065
|
+
}
|
|
8066
|
+
return buildBoundedTailSync(messages, cursor);
|
|
8067
|
+
}
|
|
8026
8068
|
}
|
|
8027
8069
|
const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
|
|
8028
8070
|
return {
|
|
@@ -12327,13 +12369,14 @@ function sliceFromOffset(text, start) {
|
|
|
12327
12369
|
function hydrateCliParsedMessages(parsedMessages, options) {
|
|
12328
12370
|
const { committedMessages, scope, lastOutputAt } = options;
|
|
12329
12371
|
const referenceMessages = [...committedMessages];
|
|
12372
|
+
const referenceComparables = referenceMessages.map((message) => normalizeComparableMessageContent(message?.content || ""));
|
|
12330
12373
|
const usedReferenceIndexes = /* @__PURE__ */ new Set();
|
|
12331
12374
|
const now = options.now ?? Date.now();
|
|
12332
12375
|
const findReferenceTimestamp = (role, content, parsedIndex) => {
|
|
12333
12376
|
const normalizedContent = normalizeComparableMessageContent(content);
|
|
12334
12377
|
if (!normalizedContent) return void 0;
|
|
12335
12378
|
const sameIndex = referenceMessages[parsedIndex];
|
|
12336
|
-
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)) {
|
|
12337
12380
|
usedReferenceIndexes.add(parsedIndex);
|
|
12338
12381
|
return sameIndex.timestamp;
|
|
12339
12382
|
}
|
|
@@ -12341,7 +12384,7 @@ function hydrateCliParsedMessages(parsedMessages, options) {
|
|
|
12341
12384
|
if (usedReferenceIndexes.has(i)) continue;
|
|
12342
12385
|
const candidate = referenceMessages[i];
|
|
12343
12386
|
if (!candidate || candidate.role !== role) continue;
|
|
12344
|
-
const candidateContent =
|
|
12387
|
+
const candidateContent = referenceComparables[i];
|
|
12345
12388
|
if (!candidateContent) continue;
|
|
12346
12389
|
const exactMatch = candidateContent === normalizedContent;
|
|
12347
12390
|
const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
|
|
@@ -13433,7 +13476,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
13433
13476
|
return;
|
|
13434
13477
|
}
|
|
13435
13478
|
if (this.currentTurnScope && !lastParsedAssistant) {
|
|
13436
|
-
LOG.
|
|
13479
|
+
LOG.debug(
|
|
13437
13480
|
"CLI",
|
|
13438
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 || "-"}`
|
|
13439
13482
|
);
|
|
@@ -14249,9 +14292,43 @@ var init_provider_cli_adapter = __esm({
|
|
|
14249
14292
|
}
|
|
14250
14293
|
armResponseTimeout() {
|
|
14251
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
|
+
}
|
|
14252
14300
|
this.responseTimeout = setTimeout(() => {
|
|
14253
|
-
|
|
14254
|
-
|
|
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);
|
|
14255
14332
|
}
|
|
14256
14333
|
writeSubmitKeyForRetry(mode) {
|
|
14257
14334
|
void this.writeToPty(this.sendKey).catch((error48) => {
|
|
@@ -15142,6 +15219,20 @@ var init_cli_provider_instance = __esm({
|
|
|
15142
15219
|
getPresentationMode() {
|
|
15143
15220
|
return this.presentationMode;
|
|
15144
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
|
+
}
|
|
15145
15236
|
updateSettings(newSettings) {
|
|
15146
15237
|
this.settings = { ...newSettings };
|
|
15147
15238
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
@@ -15297,6 +15388,15 @@ var init_cli_provider_instance = __esm({
|
|
|
15297
15388
|
this.completedDebouncePending = { chatTitle, duration: duration3, timestamp: now };
|
|
15298
15389
|
this.completedDebounceTimer = setTimeout(() => {
|
|
15299
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
|
+
}
|
|
15300
15400
|
LOG.info("CLI", `[${this.type}] completed in ${this.completedDebouncePending.duration}s`);
|
|
15301
15401
|
this.pushEvent({ event: "agent:generating_completed", ...this.completedDebouncePending });
|
|
15302
15402
|
this.completedDebouncePending = null;
|
|
@@ -36425,10 +36525,22 @@ var init_provider_loader = __esm({
|
|
|
36425
36525
|
setMachineProviderEnabled(type, enabled) {
|
|
36426
36526
|
return this.setMachineProviderConfig(type, { enabled });
|
|
36427
36527
|
}
|
|
36528
|
+
getEffectiveProviderAvailability(type) {
|
|
36529
|
+
const providerType = this.resolveAlias(type);
|
|
36530
|
+
const availability = this.providerAvailability.get(providerType);
|
|
36531
|
+
if (availability) return availability;
|
|
36532
|
+
const machineConfig = this.getMachineProviderConfig(providerType);
|
|
36533
|
+
const lastDetection = machineConfig.lastDetection;
|
|
36534
|
+
if (!lastDetection) return void 0;
|
|
36535
|
+
return {
|
|
36536
|
+
installed: lastDetection.ok === true,
|
|
36537
|
+
detectedPath: typeof lastDetection.path === "string" && lastDetection.path.trim() ? lastDetection.path.trim() : null
|
|
36538
|
+
};
|
|
36539
|
+
}
|
|
36428
36540
|
getMachineProviderStatus(type) {
|
|
36429
36541
|
const providerType = this.resolveAlias(type);
|
|
36430
36542
|
if (!this.isMachineProviderEnabled(providerType)) return "disabled";
|
|
36431
|
-
const availability = this.
|
|
36543
|
+
const availability = this.getEffectiveProviderAvailability(providerType);
|
|
36432
36544
|
if (!availability) return "enabled_unchecked";
|
|
36433
36545
|
return availability.installed ? "detected" : "not_detected";
|
|
36434
36546
|
}
|
|
@@ -36556,7 +36668,7 @@ var init_provider_loader = __esm({
|
|
|
36556
36668
|
}
|
|
36557
36669
|
getAvailableProviderInfos() {
|
|
36558
36670
|
return this.getAll().map((provider) => {
|
|
36559
|
-
const availability = this.
|
|
36671
|
+
const availability = this.getEffectiveProviderAvailability(provider.type);
|
|
36560
36672
|
const enabled = this.isMachineProviderEnabled(provider.type);
|
|
36561
36673
|
const machineConfig = this.getMachineProviderConfig(provider.type);
|
|
36562
36674
|
return {
|
|
@@ -38404,6 +38516,51 @@ function killPid(pid) {
|
|
|
38404
38516
|
return false;
|
|
38405
38517
|
}
|
|
38406
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
|
+
}
|
|
38407
38564
|
async function waitForPidExit(pid, timeoutMs) {
|
|
38408
38565
|
const start = Date.now();
|
|
38409
38566
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -38420,7 +38577,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
38420
38577
|
try {
|
|
38421
38578
|
if (fs8.existsSync(pidFile)) {
|
|
38422
38579
|
const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
|
|
38423
|
-
if (Number.isFinite(pid)) {
|
|
38580
|
+
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
|
|
38424
38581
|
killPid(pid);
|
|
38425
38582
|
}
|
|
38426
38583
|
}
|
|
@@ -38431,18 +38588,6 @@ function stopSessionHostProcesses(appName) {
|
|
|
38431
38588
|
} catch {
|
|
38432
38589
|
}
|
|
38433
38590
|
}
|
|
38434
|
-
if (process.platform !== "win32") {
|
|
38435
|
-
try {
|
|
38436
|
-
const raw = (0, import_child_process8.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
38437
|
-
for (const line of raw.split("\n")) {
|
|
38438
|
-
const pid = Number.parseInt(line.trim(), 10);
|
|
38439
|
-
if (Number.isFinite(pid)) {
|
|
38440
|
-
killPid(pid);
|
|
38441
|
-
}
|
|
38442
|
-
}
|
|
38443
|
-
} catch {
|
|
38444
|
-
}
|
|
38445
|
-
}
|
|
38446
38591
|
}
|
|
38447
38592
|
function removeDaemonPidFile() {
|
|
38448
38593
|
const pidFile = path17.join(os20.homedir(), ".adhdev", "daemon.pid");
|
|
@@ -40784,6 +40929,20 @@ var init_forward = __esm({
|
|
|
40784
40929
|
});
|
|
40785
40930
|
|
|
40786
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
|
+
}
|
|
40787
40946
|
var ProviderInstanceManager;
|
|
40788
40947
|
var init_provider_instance_manager = __esm({
|
|
40789
40948
|
"../../oss/packages/daemon-core/src/providers/provider-instance-manager.ts"() {
|
|
@@ -40884,6 +41043,27 @@ var init_provider_instance_manager = __esm({
|
|
|
40884
41043
|
}
|
|
40885
41044
|
return states;
|
|
40886
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
|
+
}
|
|
40887
41067
|
/**
|
|
40888
41068
|
* Per-category status collect
|
|
40889
41069
|
*/
|
|
@@ -79624,19 +79804,20 @@ var init_screenshot_sender = __esm({
|
|
|
79624
79804
|
}
|
|
79625
79805
|
return sentAny;
|
|
79626
79806
|
}
|
|
79627
|
-
sendScreenshot(peers, base64Data) {
|
|
79807
|
+
sendScreenshot(peers, base64Data, targetSessionId) {
|
|
79628
79808
|
const buffer = Buffer.from(base64Data, "base64");
|
|
79629
|
-
return this.sendScreenshotBuffer(peers, buffer);
|
|
79809
|
+
return this.sendScreenshotBuffer(peers, buffer, targetSessionId);
|
|
79630
79810
|
}
|
|
79631
79811
|
/** Send screenshot as raw Buffer (no base64 conversion overhead) */
|
|
79632
|
-
sendScreenshotBuffer(peers, buffer) {
|
|
79812
|
+
sendScreenshotBuffer(peers, buffer, targetSessionId) {
|
|
79633
79813
|
let sentAny = false;
|
|
79634
79814
|
let debugOnce = !this._ssDebugDone;
|
|
79635
79815
|
for (const [pid, peer] of peers.entries()) {
|
|
79636
79816
|
if (debugOnce) {
|
|
79637
|
-
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}`);
|
|
79638
79818
|
}
|
|
79639
79819
|
if (peer.state !== "connected" || !peer.dataChannel || !peer.screenshotActive) continue;
|
|
79820
|
+
if (targetSessionId && peer.screenshotTargetSessionId !== targetSessionId) continue;
|
|
79640
79821
|
try {
|
|
79641
79822
|
if (!peer.dataChannel.isOpen()) continue;
|
|
79642
79823
|
const header = Buffer.alloc(4);
|
|
@@ -79668,18 +79849,32 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
79668
79849
|
log("Cannot initiate \u2014 node-datachannel not available");
|
|
79669
79850
|
return;
|
|
79670
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
|
+
}
|
|
79671
79862
|
const limits = deps.serverConn.getPlanLimits();
|
|
79672
79863
|
if (limits && limits.maxP2PConnections !== -1) {
|
|
79673
79864
|
let connectedCount = 0;
|
|
79865
|
+
let reservedCount = 0;
|
|
79674
79866
|
for (const peer of deps.peers.values()) {
|
|
79675
79867
|
if (peer.state === "connected") connectedCount++;
|
|
79868
|
+
if (peer.state === "connected" || peer.state === "connecting") reservedCount++;
|
|
79676
79869
|
}
|
|
79677
|
-
if (
|
|
79870
|
+
if (reservedCount >= limits.maxP2PConnections) {
|
|
79678
79871
|
let oldestPeer = null;
|
|
79679
|
-
|
|
79680
|
-
|
|
79681
|
-
if (
|
|
79682
|
-
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
|
+
}
|
|
79683
79878
|
}
|
|
79684
79879
|
}
|
|
79685
79880
|
}
|
|
@@ -79697,19 +79892,12 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
79697
79892
|
}
|
|
79698
79893
|
}
|
|
79699
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;
|
|
79700
79898
|
}
|
|
79701
79899
|
}
|
|
79702
79900
|
}
|
|
79703
|
-
const pid = peerId || `legacy_${Date.now()}`;
|
|
79704
|
-
const existing = deps.peers.get(pid);
|
|
79705
|
-
if (existing?.state === "connected") {
|
|
79706
|
-
log(`initiateconnection() ignored for peer ${pid} \u2014 already connected`);
|
|
79707
|
-
return;
|
|
79708
|
-
}
|
|
79709
|
-
if (existing?.state === "connecting") {
|
|
79710
|
-
log(`initiateconnection() ignored for peer ${pid} \u2014 connection already in progress`);
|
|
79711
|
-
return;
|
|
79712
|
-
}
|
|
79713
79901
|
log(`initiateconnection() for peer ${pid}...`);
|
|
79714
79902
|
const mod = deps.nodeDatachannel;
|
|
79715
79903
|
const PeerConnectionCtor = mod.PeerConnection || mod.default?.PeerConnection || mod.default || mod;
|
|
@@ -80068,14 +80256,19 @@ var init_daemon_p2p = __esm({
|
|
|
80068
80256
|
}
|
|
80069
80257
|
return false;
|
|
80070
80258
|
}
|
|
80071
|
-
/** Get
|
|
80072
|
-
get
|
|
80259
|
+
/** Get all target sessions for active screenshot requests */
|
|
80260
|
+
get screenshotTargetSessionIds() {
|
|
80261
|
+
const targets = /* @__PURE__ */ new Set();
|
|
80073
80262
|
for (const peer of this.peers.values()) {
|
|
80074
80263
|
if (peer.screenshotActive && peer.state === "connected" && peer.screenshotTargetSessionId) {
|
|
80075
|
-
|
|
80264
|
+
targets.add(peer.screenshotTargetSessionId);
|
|
80076
80265
|
}
|
|
80077
80266
|
}
|
|
80078
|
-
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];
|
|
80079
80272
|
}
|
|
80080
80273
|
constructor(serverConn) {
|
|
80081
80274
|
this.serverConn = serverConn;
|
|
@@ -80184,6 +80377,14 @@ ${e?.stack || ""}`);
|
|
|
80184
80377
|
}
|
|
80185
80378
|
return false;
|
|
80186
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
|
+
}
|
|
80187
80388
|
onStateChange(listener) {
|
|
80188
80389
|
this.stateListeners.push(listener);
|
|
80189
80390
|
}
|
|
@@ -80247,11 +80448,14 @@ ${e?.stack || ""}`);
|
|
|
80247
80448
|
if (targetPeers.size === 0) return false;
|
|
80248
80449
|
return this.screenshotSender.broadcastSessionOutput(targetPeers, sessionId, data);
|
|
80249
80450
|
}
|
|
80250
|
-
sendScreenshot(base64Data) {
|
|
80251
|
-
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);
|
|
80252
80456
|
}
|
|
80253
|
-
|
|
80254
|
-
return this.
|
|
80457
|
+
sendScreenshotBufferForTarget(targetSessionId, buffer) {
|
|
80458
|
+
return this.sendScreenshotBuffer(buffer, targetSessionId);
|
|
80255
80459
|
}
|
|
80256
80460
|
// ─── Handler registration (unchanged API) ───────
|
|
80257
80461
|
onFileRequest(handler) {
|
|
@@ -86975,6 +87179,7 @@ var init_screenshot_controller = __esm({
|
|
|
86975
87179
|
lastSize = 0;
|
|
86976
87180
|
lastHash = 0;
|
|
86977
87181
|
staticFrameCount = 0;
|
|
87182
|
+
targetFrameState = /* @__PURE__ */ new Map();
|
|
86978
87183
|
currentInterval;
|
|
86979
87184
|
// Quality profiles
|
|
86980
87185
|
profileDirect;
|
|
@@ -87038,14 +87243,13 @@ var init_screenshot_controller = __esm({
|
|
|
87038
87243
|
async tick() {
|
|
87039
87244
|
if (!this.deps.isRunning()) return;
|
|
87040
87245
|
const active = this.deps.isScreenshotActive();
|
|
87041
|
-
const
|
|
87042
|
-
|
|
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) {
|
|
87043
87250
|
this.timer = setTimeout(() => this.tick(), 500);
|
|
87044
87251
|
return;
|
|
87045
87252
|
}
|
|
87046
|
-
const cdp = targetSessionId ? this.deps.getCdp(targetSessionId) : null;
|
|
87047
|
-
const isRelay = this.deps.isUsingRelay();
|
|
87048
|
-
const profile = isRelay ? this.profileRelay : this.profileDirect;
|
|
87049
87253
|
this.checkBudgetReset();
|
|
87050
87254
|
if (this.dailyBudgetMs > 0) {
|
|
87051
87255
|
const now = Date.now();
|
|
@@ -87060,49 +87264,84 @@ var init_screenshot_controller = __esm({
|
|
|
87060
87264
|
}
|
|
87061
87265
|
}
|
|
87062
87266
|
const budgetBlocked = this.budgetExhausted && isRelay;
|
|
87063
|
-
if (!active ||
|
|
87267
|
+
if (!active || budgetBlocked) {
|
|
87064
87268
|
this.staticFrameCount = 0;
|
|
87269
|
+
this.targetFrameState.clear();
|
|
87065
87270
|
this.currentInterval = profile.maxInterval;
|
|
87066
87271
|
if (!active) this.lastActiveTimestamp = 0;
|
|
87067
87272
|
this.timer = setTimeout(() => this.tick(), budgetBlocked ? 3e4 : this.currentInterval);
|
|
87068
87273
|
return;
|
|
87069
87274
|
}
|
|
87070
87275
|
this.debugCount++;
|
|
87071
|
-
|
|
87072
|
-
|
|
87073
|
-
|
|
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);
|
|
87074
87290
|
const hash2 = _ScreenshotController.fnvHash(buf);
|
|
87075
|
-
const sizeMatch = buf.length ===
|
|
87076
|
-
const hashMatch = hash2 ===
|
|
87077
|
-
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();
|
|
87078
87294
|
const resizeTarget = anyNeedsFirstFrame ? profile.firstFrameLongEdge : profile.maxLongEdge;
|
|
87295
|
+
anyFirstFrameAcrossTargets = anyFirstFrameAcrossTargets || anyNeedsFirstFrame;
|
|
87079
87296
|
if (sizeMatch && hashMatch && !anyNeedsFirstFrame) {
|
|
87080
|
-
|
|
87081
|
-
if (
|
|
87297
|
+
state.staticFrameCount++;
|
|
87298
|
+
if (state.staticFrameCount >= this.STATIC_THRESHOLD) {
|
|
87082
87299
|
this.currentInterval = Math.min(this.currentInterval + 200, profile.maxInterval);
|
|
87083
87300
|
}
|
|
87084
87301
|
if (this.debugCount <= 5 || this.debugCount % 50 === 0) {
|
|
87085
|
-
LOG.debug("Screenshot", `skip (unchanged, static=${
|
|
87086
|
-
}
|
|
87087
|
-
} else {
|
|
87088
|
-
const normalizedBuf = await this.normalizeBuffer(buf, resizeTarget, profile.quality);
|
|
87089
|
-
this.lastSize = buf.length;
|
|
87090
|
-
this.lastHash = hash2;
|
|
87091
|
-
this.staticFrameCount = 0;
|
|
87092
|
-
this.currentInterval = profile.minInterval;
|
|
87093
|
-
const sent = this.deps.sendScreenshotBuffer(normalizedBuf);
|
|
87094
|
-
if (this.debugCount <= 3 || anyNeedsFirstFrame) {
|
|
87095
|
-
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"})`);
|
|
87096
87303
|
}
|
|
87304
|
+
continue;
|
|
87097
87305
|
}
|
|
87098
|
-
|
|
87099
|
-
|
|
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}`);
|
|
87100
87321
|
}
|
|
87101
|
-
}
|
|
87102
|
-
|
|
87322
|
+
}
|
|
87323
|
+
if (!capturedAny) {
|
|
87324
|
+
this.currentInterval = profile.maxInterval;
|
|
87325
|
+
} else if (!sentAnyFrame && !anyFirstFrameAcrossTargets) {
|
|
87326
|
+
this.currentInterval = Math.min(this.currentInterval + 200, profile.maxInterval);
|
|
87103
87327
|
}
|
|
87104
87328
|
this.timer = setTimeout(() => this.tick(), this.currentInterval);
|
|
87105
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
|
+
}
|
|
87106
87345
|
// ─── Budget ───────────────────────────────────
|
|
87107
87346
|
checkBudgetReset() {
|
|
87108
87347
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -87319,7 +87558,7 @@ function killPid2(pid) {
|
|
|
87319
87558
|
return false;
|
|
87320
87559
|
}
|
|
87321
87560
|
}
|
|
87322
|
-
function
|
|
87561
|
+
function getWindowsProcessCommandLine2(pid) {
|
|
87323
87562
|
const pidFilter = `ProcessId=${pid}`;
|
|
87324
87563
|
try {
|
|
87325
87564
|
const psOut = (0, import_child_process13.execFileSync)("powershell.exe", [
|
|
@@ -87348,13 +87587,32 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
87348
87587
|
}
|
|
87349
87588
|
return null;
|
|
87350
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
|
+
}
|
|
87351
87609
|
function stopManagedSessionHostProcess() {
|
|
87352
87610
|
let stopped = false;
|
|
87353
87611
|
const pidFile = getSessionHostPidFile();
|
|
87354
87612
|
try {
|
|
87355
87613
|
if (fs22.existsSync(pidFile)) {
|
|
87356
87614
|
const pid = Number.parseInt(fs22.readFileSync(pidFile, "utf8").trim(), 10);
|
|
87357
|
-
if (Number.isFinite(pid) && pid !== process.pid) {
|
|
87615
|
+
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid2(pid)) {
|
|
87358
87616
|
stopped = killPid2(pid) || stopped;
|
|
87359
87617
|
}
|
|
87360
87618
|
}
|
|
@@ -87368,40 +87626,7 @@ function stopManagedSessionHostProcess() {
|
|
|
87368
87626
|
return stopped;
|
|
87369
87627
|
}
|
|
87370
87628
|
function stopSessionHost() {
|
|
87371
|
-
|
|
87372
|
-
if (process.platform === "win32") {
|
|
87373
|
-
try {
|
|
87374
|
-
const raw = (0, import_child_process13.execFileSync)("tasklist", ["/FO", "CSV", "/NH", "/FI", "IMAGENAME eq node.exe"], {
|
|
87375
|
-
encoding: "utf8",
|
|
87376
|
-
timeout: 5e3,
|
|
87377
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
87378
|
-
windowsHide: true
|
|
87379
|
-
}).trim();
|
|
87380
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
87381
|
-
const match = line.match(/^"node\.exe","(\d+)"/i);
|
|
87382
|
-
if (!match) continue;
|
|
87383
|
-
const candidatePid = Number.parseInt(match[1], 10);
|
|
87384
|
-
if (!Number.isFinite(candidatePid) || candidatePid === process.pid) continue;
|
|
87385
|
-
const commandLine = getWindowsProcessCommandLine(candidatePid);
|
|
87386
|
-
if (commandLine?.includes("session-host-daemon")) {
|
|
87387
|
-
stopped = killPid2(candidatePid) || stopped;
|
|
87388
|
-
}
|
|
87389
|
-
}
|
|
87390
|
-
} catch {
|
|
87391
|
-
}
|
|
87392
|
-
} else {
|
|
87393
|
-
try {
|
|
87394
|
-
const raw = (0, import_child_process13.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
87395
|
-
for (const line of raw.split("\n")) {
|
|
87396
|
-
const pid = Number.parseInt(line.trim(), 10);
|
|
87397
|
-
if (Number.isFinite(pid) && pid !== process.pid && pid !== process.ppid) {
|
|
87398
|
-
stopped = killPid2(pid) || stopped;
|
|
87399
|
-
}
|
|
87400
|
-
}
|
|
87401
|
-
} catch {
|
|
87402
|
-
}
|
|
87403
|
-
}
|
|
87404
|
-
return stopped;
|
|
87629
|
+
return stopManagedSessionHostProcess();
|
|
87405
87630
|
}
|
|
87406
87631
|
async function ensureSessionHostReady2() {
|
|
87407
87632
|
const quarantine = quarantineLegacyStandaloneSessions({
|
|
@@ -87658,10 +87883,65 @@ var init_session_host_controller = __esm({
|
|
|
87658
87883
|
var adhdev_daemon_exports = {};
|
|
87659
87884
|
__export(adhdev_daemon_exports, {
|
|
87660
87885
|
AdhdevDaemon: () => AdhdevDaemon,
|
|
87886
|
+
buildMandatoryUpdateInfoFromServerPayload: () => buildMandatoryUpdateInfoFromServerPayload,
|
|
87887
|
+
buildMandatoryUpdateRequiredPayload: () => buildMandatoryUpdateRequiredPayload,
|
|
87661
87888
|
getDaemonPid: () => getDaemonPid,
|
|
87662
87889
|
isDaemonRunning: () => isDaemonRunning,
|
|
87663
|
-
stopDaemon: () => stopDaemon
|
|
87664
|
-
|
|
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
|
+
}
|
|
87665
87945
|
function resolveDaemonPort(ref = {}) {
|
|
87666
87946
|
return Number.isFinite(ref.port) && Number(ref.port) > 0 ? Number(ref.port) : DEFAULT_DAEMON_PORT;
|
|
87667
87947
|
}
|
|
@@ -87688,7 +87968,7 @@ function removeDaemonPid(ref = {}) {
|
|
|
87688
87968
|
function isDaemonRunning(ref = {}) {
|
|
87689
87969
|
const port = resolveDaemonPort(ref);
|
|
87690
87970
|
try {
|
|
87691
|
-
const { execFileSync:
|
|
87971
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
87692
87972
|
const probe = `
|
|
87693
87973
|
const http = require('http');
|
|
87694
87974
|
const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
|
|
@@ -87698,7 +87978,7 @@ function isDaemonRunning(ref = {}) {
|
|
|
87698
87978
|
req.on('error', () => process.stdout.write('0'));
|
|
87699
87979
|
req.on('timeout', () => { req.destroy(); process.stdout.write('0'); });
|
|
87700
87980
|
`;
|
|
87701
|
-
const result =
|
|
87981
|
+
const result = execFileSync7(process.execPath, ["-e", probe], {
|
|
87702
87982
|
encoding: "utf-8",
|
|
87703
87983
|
timeout: 3e3,
|
|
87704
87984
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -87724,9 +88004,9 @@ function isDaemonRunning(ref = {}) {
|
|
|
87724
88004
|
function isAdhdevProcess(pid) {
|
|
87725
88005
|
try {
|
|
87726
88006
|
if (process.platform === "win32") {
|
|
87727
|
-
const { execFileSync:
|
|
88007
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
87728
88008
|
try {
|
|
87729
|
-
const psOut =
|
|
88009
|
+
const psOut = execFileSync7("powershell.exe", [
|
|
87730
88010
|
"-NoProfile",
|
|
87731
88011
|
"-NonInteractive",
|
|
87732
88012
|
"-ExecutionPolicy",
|
|
@@ -87739,8 +88019,8 @@ function isAdhdevProcess(pid) {
|
|
|
87739
88019
|
return true;
|
|
87740
88020
|
}
|
|
87741
88021
|
} else {
|
|
87742
|
-
const { execFileSync:
|
|
87743
|
-
const cmdline =
|
|
88022
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
88023
|
+
const cmdline = execFileSync7("ps", ["-o", "command=", "-p", String(pid)], {
|
|
87744
88024
|
encoding: "utf-8",
|
|
87745
88025
|
timeout: 2e3,
|
|
87746
88026
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -87754,7 +88034,7 @@ function isAdhdevProcess(pid) {
|
|
|
87754
88034
|
function getDaemonHealthPid(ref = {}) {
|
|
87755
88035
|
const port = resolveDaemonPort(ref);
|
|
87756
88036
|
try {
|
|
87757
|
-
const { execFileSync:
|
|
88037
|
+
const { execFileSync: execFileSync7 } = require("child_process");
|
|
87758
88038
|
const probe = `
|
|
87759
88039
|
const http = require('http');
|
|
87760
88040
|
const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
|
|
@@ -87772,7 +88052,7 @@ function getDaemonHealthPid(ref = {}) {
|
|
|
87772
88052
|
req.on('error', () => {});
|
|
87773
88053
|
req.on('timeout', () => { req.destroy(); });
|
|
87774
88054
|
`;
|
|
87775
|
-
const result =
|
|
88055
|
+
const result = execFileSync7(process.execPath, ["-e", probe], {
|
|
87776
88056
|
encoding: "utf-8",
|
|
87777
88057
|
timeout: 3e3,
|
|
87778
88058
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -87818,7 +88098,7 @@ function stopDaemon(ref = {}) {
|
|
|
87818
88098
|
return false;
|
|
87819
88099
|
}
|
|
87820
88100
|
}
|
|
87821
|
-
var os28, fs23, path29, import_http, import_ws3, pkgVersion, AdhdevDaemon;
|
|
88101
|
+
var os28, fs23, path29, import_http, import_child_process14, import_ws3, pkgVersion, AdhdevDaemon;
|
|
87822
88102
|
var init_adhdev_daemon = __esm({
|
|
87823
88103
|
"src/adhdev-daemon.ts"() {
|
|
87824
88104
|
"use strict";
|
|
@@ -87834,12 +88114,13 @@ var init_adhdev_daemon = __esm({
|
|
|
87834
88114
|
fs23 = __toESM(require("fs"));
|
|
87835
88115
|
path29 = __toESM(require("path"));
|
|
87836
88116
|
import_http = require("http");
|
|
88117
|
+
import_child_process14 = require("child_process");
|
|
87837
88118
|
import_ws3 = require("ws");
|
|
87838
88119
|
init_source();
|
|
87839
88120
|
init_version();
|
|
87840
88121
|
init_src();
|
|
87841
88122
|
init_runtime_defaults();
|
|
87842
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
88123
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.34" });
|
|
87843
88124
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
87844
88125
|
localHttpServer = null;
|
|
87845
88126
|
localWss = null;
|
|
@@ -87932,6 +88213,10 @@ var init_adhdev_daemon = __esm({
|
|
|
87932
88213
|
getUpgradePackageName() {
|
|
87933
88214
|
return process.argv[1]?.includes("daemon-standalone") ? "@adhdev/daemon-standalone" : "adhdev";
|
|
87934
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
|
+
}
|
|
87935
88220
|
hasBlockingSessionsForMandatoryUpdate() {
|
|
87936
88221
|
if (!this.components) return false;
|
|
87937
88222
|
const blocking = /* @__PURE__ */ new Set(["generating", "waiting_approval", "starting"]);
|
|
@@ -87957,15 +88242,7 @@ var init_adhdev_daemon = __esm({
|
|
|
87957
88242
|
const pkgName = this.getUpgradePackageName();
|
|
87958
88243
|
this.mandatoryUpgradeInFlight = true;
|
|
87959
88244
|
try {
|
|
87960
|
-
|
|
87961
|
-
const published = execSync8(`npm view ${pkgName}@${pending.targetVersion} version`, {
|
|
87962
|
-
encoding: "utf-8",
|
|
87963
|
-
timeout: 1e4,
|
|
87964
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
87965
|
-
}).trim();
|
|
87966
|
-
if (published !== pending.targetVersion) {
|
|
87967
|
-
throw new Error(`Published version mismatch: expected ${pending.targetVersion}, got ${published || "unknown"}`);
|
|
87968
|
-
}
|
|
88245
|
+
verifyPublishedMandatoryUpdateTarget(pkgName, pending.targetVersion);
|
|
87969
88246
|
LOG.warn("Upgrade", `Applying mandatory daemon update (${pending.reason}) \u2192 v${pending.targetVersion}`);
|
|
87970
88247
|
spawnDetachedDaemonUpgradeHelper({
|
|
87971
88248
|
packageName: pkgName,
|
|
@@ -88067,7 +88344,7 @@ var init_adhdev_daemon = __esm({
|
|
|
88067
88344
|
const now = Date.now();
|
|
88068
88345
|
const cached2 = this.hotChatSnapshotCache;
|
|
88069
88346
|
const sessions = cached2 && now - cached2.builtAt < _AdhdevDaemon.HOT_CHAT_SNAPSHOT_CACHE_TTL_MS ? cached2.sessions : (() => {
|
|
88070
|
-
const built = this.
|
|
88347
|
+
const built = this.components.instanceManager.collectHotChatSessionStates();
|
|
88071
88348
|
this.hotChatSnapshotCache = { sessions: built, builtAt: now };
|
|
88072
88349
|
return built;
|
|
88073
88350
|
})();
|
|
@@ -88452,14 +88729,17 @@ ${err?.stack || ""}`);
|
|
|
88452
88729
|
isRunning: () => this.running,
|
|
88453
88730
|
isScreenshotActive: () => this.p2p?.screenshotActive ?? false,
|
|
88454
88731
|
getScreenshotTargetSessionId: () => this.p2p?.screenshotTargetSessionId,
|
|
88732
|
+
getScreenshotTargetSessionIds: () => this.p2p?.screenshotTargetSessionIds ?? [],
|
|
88455
88733
|
isUsingRelay: () => this.p2p?.isUsingRelay ?? false,
|
|
88456
88734
|
hasAnyNeedingFirstFrame: () => this.p2p?.hasAnyNeedingFirstFrame() ?? false,
|
|
88735
|
+
hasAnyNeedingFirstFrameForTarget: (targetSessionId) => this.p2p?.hasAnyNeedingFirstFrameForTarget(targetSessionId) ?? false,
|
|
88457
88736
|
getCdp: (targetSessionId) => {
|
|
88458
88737
|
if (targetSessionId) return this.getCdpFor(targetSessionId);
|
|
88459
88738
|
LOG.warn("P2P", "Screenshot requested without targetSessionId \u2014 cannot determine target session. Skipping frame.");
|
|
88460
88739
|
return null;
|
|
88461
88740
|
},
|
|
88462
|
-
sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf)
|
|
88741
|
+
sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf),
|
|
88742
|
+
sendScreenshotBufferForTarget: (targetSessionId, buf) => this.p2p.sendScreenshotBufferForTarget(targetSessionId, buf)
|
|
88463
88743
|
}, planLimits ?? void 0);
|
|
88464
88744
|
this.screenshotController.start();
|
|
88465
88745
|
this.p2p.onScreenshotStart(() => this.screenshotController?.triggerImmediate());
|
|
@@ -88488,11 +88768,12 @@ ${err?.stack || ""}`);
|
|
|
88488
88768
|
});
|
|
88489
88769
|
this.serverConn.on("force_update_required", (msg) => {
|
|
88490
88770
|
const payload = msg.payload;
|
|
88491
|
-
|
|
88492
|
-
|
|
88493
|
-
|
|
88494
|
-
|
|
88495
|
-
}
|
|
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;
|
|
88496
88777
|
LOG.warn("Upgrade", `Mandatory daemon update required (${this.pendingMandatoryUpdate.reason})`);
|
|
88497
88778
|
void this.maybeApplyMandatoryUpdate("server-force-update");
|
|
88498
88779
|
});
|
|
@@ -88603,15 +88884,9 @@ ${err?.stack || ""}`);
|
|
|
88603
88884
|
const cmdStart = Date.now();
|
|
88604
88885
|
const source = msg.ipcWs ? "ext" : typeof msg.source === "string" && msg.source.trim() ? msg.source : "ws";
|
|
88605
88886
|
try {
|
|
88606
|
-
|
|
88607
|
-
|
|
88608
|
-
|
|
88609
|
-
code: "DAEMON_UPDATE_REQUIRED",
|
|
88610
|
-
required: true,
|
|
88611
|
-
latest: this.pendingMandatoryUpdate.targetVersion,
|
|
88612
|
-
reason: this.pendingMandatoryUpdate.reason,
|
|
88613
|
-
interactionId
|
|
88614
|
-
});
|
|
88887
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(cmd, interactionId);
|
|
88888
|
+
if (mandatoryUpdateBlock) {
|
|
88889
|
+
this.sendResult(msg, false, mandatoryUpdateBlock);
|
|
88615
88890
|
return;
|
|
88616
88891
|
}
|
|
88617
88892
|
if (source === "api" && !loadConfig().allowServerApiProxy) {
|
|
@@ -88656,6 +88931,10 @@ ${err?.stack || ""}`);
|
|
|
88656
88931
|
const interactionId = String(normalizedData._interactionId);
|
|
88657
88932
|
const cmdStart = Date.now();
|
|
88658
88933
|
try {
|
|
88934
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(cmdType, interactionId);
|
|
88935
|
+
if (mandatoryUpdateBlock) {
|
|
88936
|
+
return { success: false, ...mandatoryUpdateBlock };
|
|
88937
|
+
}
|
|
88659
88938
|
switch (cmdType) {
|
|
88660
88939
|
case "get_runtime_snapshot": {
|
|
88661
88940
|
const sessionId = typeof normalizedData.sessionId === "string" ? normalizedData.sessionId : "";
|
|
@@ -88834,8 +89113,22 @@ ${err?.stack || ""}`);
|
|
|
88834
89113
|
}));
|
|
88835
89114
|
return;
|
|
88836
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
|
+
}
|
|
88837
89130
|
try {
|
|
88838
|
-
const result = await this.components.router.execute(command,
|
|
89131
|
+
const result = await this.components.router.execute(command, normalizedArgs, "ipc");
|
|
88839
89132
|
ws.send(JSON.stringify({
|
|
88840
89133
|
type: "ext:command_result",
|
|
88841
89134
|
payload: {
|
|
@@ -89005,9 +89298,9 @@ async function runWizard(options = {}) {
|
|
|
89005
89298
|
}
|
|
89006
89299
|
async function checkForUpdate() {
|
|
89007
89300
|
try {
|
|
89008
|
-
const { execFileSync:
|
|
89301
|
+
const { execFileSync: execFileSync7 } = await import("child_process");
|
|
89009
89302
|
const currentVersion = resolvePackageVersion();
|
|
89010
|
-
const latestVersion = readLatestPublishedCliVersion(
|
|
89303
|
+
const latestVersion = readLatestPublishedCliVersion(execFileSync7);
|
|
89011
89304
|
if (!latestVersion) return;
|
|
89012
89305
|
if (!currentVersion || !latestVersion || currentVersion === latestVersion) return;
|
|
89013
89306
|
console.log(source_default.yellow(` Update available: ${currentVersion} \u2192 ${latestVersion}`));
|
|
@@ -89024,7 +89317,7 @@ async function checkForUpdate() {
|
|
|
89024
89317
|
const spinner = (await Promise.resolve().then(() => (init_ora(), ora_exports))).default("Updating adhdev CLI...").start();
|
|
89025
89318
|
try {
|
|
89026
89319
|
const installCommand = buildPinnedGlobalInstallCommand({ packageName: "adhdev", targetVersion: "latest" });
|
|
89027
|
-
|
|
89320
|
+
execFileSync7(installCommand.command, installCommand.args, {
|
|
89028
89321
|
encoding: "utf-8",
|
|
89029
89322
|
timeout: 6e4,
|
|
89030
89323
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -92319,7 +92612,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
|
|
|
92319
92612
|
|
|
92320
92613
|
// src/cli/doctor-commands.ts
|
|
92321
92614
|
init_source();
|
|
92322
|
-
var
|
|
92615
|
+
var import_child_process15 = require("child_process");
|
|
92323
92616
|
var fs26 = __toESM(require("fs"));
|
|
92324
92617
|
var os30 = __toESM(require("os"));
|
|
92325
92618
|
var path33 = __toESM(require("path"));
|
|
@@ -92961,7 +93254,7 @@ function findCommandPaths(command) {
|
|
|
92961
93254
|
try {
|
|
92962
93255
|
const bin = process.platform === "win32" ? "where.exe" : "which";
|
|
92963
93256
|
const args = process.platform === "win32" ? [command] : ["-a", command];
|
|
92964
|
-
const output = (0,
|
|
93257
|
+
const output = (0, import_child_process15.execFileSync)(bin, args, {
|
|
92965
93258
|
encoding: "utf-8",
|
|
92966
93259
|
stdio: ["ignore", "pipe", "ignore"]
|
|
92967
93260
|
});
|
|
@@ -92976,7 +93269,7 @@ function probeCliBinary(commandPath, currentVersion) {
|
|
|
92976
93269
|
currentVersion
|
|
92977
93270
|
};
|
|
92978
93271
|
try {
|
|
92979
|
-
probe.version = (0,
|
|
93272
|
+
probe.version = (0, import_child_process15.execFileSync)(commandPath, ["--version"], {
|
|
92980
93273
|
encoding: "utf-8",
|
|
92981
93274
|
stdio: ["ignore", "pipe", "pipe"]
|
|
92982
93275
|
}).trim();
|
|
@@ -92984,7 +93277,7 @@ function probeCliBinary(commandPath, currentVersion) {
|
|
|
92984
93277
|
probe.versionError = error48?.stderr?.toString?.().trim() || error48?.message || "version probe failed";
|
|
92985
93278
|
}
|
|
92986
93279
|
try {
|
|
92987
|
-
probe.helpText = (0,
|
|
93280
|
+
probe.helpText = (0, import_child_process15.execFileSync)(commandPath, ["--help"], {
|
|
92988
93281
|
encoding: "utf-8",
|
|
92989
93282
|
stdio: ["ignore", "pipe", "pipe"]
|
|
92990
93283
|
});
|