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/index.js
CHANGED
|
@@ -7461,6 +7461,26 @@ function toHistoryPersistedMessages(messages) {
|
|
|
7461
7461
|
historyDedupKey: deriveHistoryDedupKey(message)
|
|
7462
7462
|
}));
|
|
7463
7463
|
}
|
|
7464
|
+
function findLastMessageIndexBySignature(messages, signature) {
|
|
7465
|
+
if (!signature) return -1;
|
|
7466
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
7467
|
+
if (getChatMessageSignature(messages[index]) === signature) {
|
|
7468
|
+
return index;
|
|
7469
|
+
}
|
|
7470
|
+
}
|
|
7471
|
+
return -1;
|
|
7472
|
+
}
|
|
7473
|
+
function buildBoundedTailSync(messages, cursor) {
|
|
7474
|
+
const totalMessages = messages.length;
|
|
7475
|
+
const tailMessages = cursor.tailLimit > 0 && totalMessages > cursor.tailLimit ? messages.slice(-cursor.tailLimit) : messages;
|
|
7476
|
+
return {
|
|
7477
|
+
syncMode: "full",
|
|
7478
|
+
replaceFrom: 0,
|
|
7479
|
+
messages: tailMessages,
|
|
7480
|
+
totalMessages,
|
|
7481
|
+
lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
|
|
7482
|
+
};
|
|
7483
|
+
}
|
|
7464
7484
|
function computeReadChatSync(messages, cursor) {
|
|
7465
7485
|
const totalMessages = messages.length;
|
|
7466
7486
|
const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
|
|
@@ -7492,6 +7512,15 @@ function computeReadChatSync(messages, cursor) {
|
|
|
7492
7512
|
lastMessageSignature
|
|
7493
7513
|
};
|
|
7494
7514
|
}
|
|
7515
|
+
if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
|
|
7516
|
+
return {
|
|
7517
|
+
syncMode: "noop",
|
|
7518
|
+
replaceFrom: totalMessages,
|
|
7519
|
+
messages: [],
|
|
7520
|
+
totalMessages,
|
|
7521
|
+
lastMessageSignature
|
|
7522
|
+
};
|
|
7523
|
+
}
|
|
7495
7524
|
if (knownMessageCount < totalMessages) {
|
|
7496
7525
|
const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
|
|
7497
7526
|
if (anchorSignature === knownSignature) {
|
|
@@ -7503,6 +7532,19 @@ function computeReadChatSync(messages, cursor) {
|
|
|
7503
7532
|
lastMessageSignature
|
|
7504
7533
|
};
|
|
7505
7534
|
}
|
|
7535
|
+
if (cursor.tailLimit > 0) {
|
|
7536
|
+
const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
|
|
7537
|
+
if (signatureIndex >= 0) {
|
|
7538
|
+
return {
|
|
7539
|
+
syncMode: "append",
|
|
7540
|
+
replaceFrom: knownMessageCount,
|
|
7541
|
+
messages: messages.slice(signatureIndex + 1),
|
|
7542
|
+
totalMessages,
|
|
7543
|
+
lastMessageSignature
|
|
7544
|
+
};
|
|
7545
|
+
}
|
|
7546
|
+
return buildBoundedTailSync(messages, cursor);
|
|
7547
|
+
}
|
|
7506
7548
|
}
|
|
7507
7549
|
const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
|
|
7508
7550
|
return {
|
|
@@ -11371,13 +11413,14 @@ function sliceFromOffset(text, start) {
|
|
|
11371
11413
|
function hydrateCliParsedMessages(parsedMessages, options) {
|
|
11372
11414
|
const { committedMessages, scope, lastOutputAt } = options;
|
|
11373
11415
|
const referenceMessages = [...committedMessages];
|
|
11416
|
+
const referenceComparables = referenceMessages.map((message) => normalizeComparableMessageContent(message?.content || ""));
|
|
11374
11417
|
const usedReferenceIndexes = /* @__PURE__ */ new Set();
|
|
11375
11418
|
const now = options.now ?? Date.now();
|
|
11376
11419
|
const findReferenceTimestamp = (role, content, parsedIndex) => {
|
|
11377
11420
|
const normalizedContent = normalizeComparableMessageContent(content);
|
|
11378
11421
|
if (!normalizedContent) return void 0;
|
|
11379
11422
|
const sameIndex = referenceMessages[parsedIndex];
|
|
11380
|
-
if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role &&
|
|
11423
|
+
if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && referenceComparables[parsedIndex] === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
|
|
11381
11424
|
usedReferenceIndexes.add(parsedIndex);
|
|
11382
11425
|
return sameIndex.timestamp;
|
|
11383
11426
|
}
|
|
@@ -11385,7 +11428,7 @@ function hydrateCliParsedMessages(parsedMessages, options) {
|
|
|
11385
11428
|
if (usedReferenceIndexes.has(i)) continue;
|
|
11386
11429
|
const candidate = referenceMessages[i];
|
|
11387
11430
|
if (!candidate || candidate.role !== role) continue;
|
|
11388
|
-
const candidateContent =
|
|
11431
|
+
const candidateContent = referenceComparables[i];
|
|
11389
11432
|
if (!candidateContent) continue;
|
|
11390
11433
|
const exactMatch = candidateContent === normalizedContent;
|
|
11391
11434
|
const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
|
|
@@ -12477,7 +12520,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
12477
12520
|
return;
|
|
12478
12521
|
}
|
|
12479
12522
|
if (this.currentTurnScope && !lastParsedAssistant) {
|
|
12480
|
-
LOG.
|
|
12523
|
+
LOG.debug(
|
|
12481
12524
|
"CLI",
|
|
12482
12525
|
`[${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 || "-"}`
|
|
12483
12526
|
);
|
|
@@ -13293,9 +13336,43 @@ var init_provider_cli_adapter = __esm({
|
|
|
13293
13336
|
}
|
|
13294
13337
|
armResponseTimeout() {
|
|
13295
13338
|
if (this.responseTimeout) clearTimeout(this.responseTimeout);
|
|
13339
|
+
const timeoutMs = this.timeouts.maxResponse;
|
|
13340
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
13341
|
+
this.responseTimeout = null;
|
|
13342
|
+
return;
|
|
13343
|
+
}
|
|
13296
13344
|
this.responseTimeout = setTimeout(() => {
|
|
13297
|
-
|
|
13298
|
-
|
|
13345
|
+
this.responseTimeout = null;
|
|
13346
|
+
if (!this.isWaitingForResponse) return;
|
|
13347
|
+
const detectedStatusBeforeEval = this.runDetectStatus(this.recentOutputBuffer);
|
|
13348
|
+
this.recordTrace("response_timeout_check", {
|
|
13349
|
+
timeoutMs,
|
|
13350
|
+
detectedStatus: detectedStatusBeforeEval,
|
|
13351
|
+
currentStatus: this.currentStatus,
|
|
13352
|
+
isWaitingForResponse: this.isWaitingForResponse,
|
|
13353
|
+
hasActionableApproval: this.hasActionableApproval(),
|
|
13354
|
+
...buildCliTraceParseSnapshot({
|
|
13355
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
13356
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
13357
|
+
responseBuffer: this.responseBuffer,
|
|
13358
|
+
partialResponse: this.responseBuffer,
|
|
13359
|
+
scope: this.currentTurnScope
|
|
13360
|
+
})
|
|
13361
|
+
});
|
|
13362
|
+
this.settledBuffer = this.recentOutputBuffer;
|
|
13363
|
+
this.evaluateSettled();
|
|
13364
|
+
if (this.isWaitingForResponse && !this.hasActionableApproval()) {
|
|
13365
|
+
const detectedStatusAfterEval = this.runDetectStatus(this.recentOutputBuffer);
|
|
13366
|
+
this.recordTrace("response_timeout_kept_open", {
|
|
13367
|
+
timeoutMs,
|
|
13368
|
+
detectedStatusBeforeEval,
|
|
13369
|
+
detectedStatusAfterEval,
|
|
13370
|
+
currentStatus: this.currentStatus,
|
|
13371
|
+
isWaitingForResponse: this.isWaitingForResponse
|
|
13372
|
+
});
|
|
13373
|
+
this.armResponseTimeout();
|
|
13374
|
+
}
|
|
13375
|
+
}, timeoutMs);
|
|
13299
13376
|
}
|
|
13300
13377
|
writeSubmitKeyForRetry(mode) {
|
|
13301
13378
|
void this.writeToPty(this.sendKey).catch((error48) => {
|
|
@@ -14186,6 +14263,20 @@ var init_cli_provider_instance = __esm({
|
|
|
14186
14263
|
getPresentationMode() {
|
|
14187
14264
|
return this.presentationMode;
|
|
14188
14265
|
}
|
|
14266
|
+
getHotChatSessionState() {
|
|
14267
|
+
const adapterStatus = this.adapter.getStatus();
|
|
14268
|
+
const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
|
|
14269
|
+
const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
|
|
14270
|
+
const runtime = this.adapter.getRuntimeMetadata();
|
|
14271
|
+
return {
|
|
14272
|
+
id: this.instanceId,
|
|
14273
|
+
status: visibleStatus,
|
|
14274
|
+
runtimeLifecycle: runtime?.lifecycle ?? null,
|
|
14275
|
+
runtimeSurfaceKind: runtime?.surfaceKind,
|
|
14276
|
+
runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
|
|
14277
|
+
runtimeRecoveryState: runtime?.recoveryState ?? null
|
|
14278
|
+
};
|
|
14279
|
+
}
|
|
14189
14280
|
updateSettings(newSettings) {
|
|
14190
14281
|
this.settings = { ...newSettings };
|
|
14191
14282
|
this.adapter.updateRuntimeSettings?.(this.settings);
|
|
@@ -14341,6 +14432,15 @@ var init_cli_provider_instance = __esm({
|
|
|
14341
14432
|
this.completedDebouncePending = { chatTitle, duration: duration3, timestamp: now };
|
|
14342
14433
|
this.completedDebounceTimer = setTimeout(() => {
|
|
14343
14434
|
if (this.completedDebouncePending) {
|
|
14435
|
+
const latestStatus = this.adapter.getStatus();
|
|
14436
|
+
const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
|
|
14437
|
+
const latestVisibleStatus = latestAutoApproveActive ? "generating" : latestStatus.status;
|
|
14438
|
+
if (latestVisibleStatus !== "idle") {
|
|
14439
|
+
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
|
|
14440
|
+
this.completedDebouncePending = null;
|
|
14441
|
+
this.completedDebounceTimer = null;
|
|
14442
|
+
return;
|
|
14443
|
+
}
|
|
14344
14444
|
LOG.info("CLI", `[${this.type}] completed in ${this.completedDebouncePending.duration}s`);
|
|
14345
14445
|
this.pushEvent({ event: "agent:generating_completed", ...this.completedDebouncePending });
|
|
14346
14446
|
this.completedDebouncePending = null;
|
|
@@ -35469,10 +35569,22 @@ var init_provider_loader = __esm({
|
|
|
35469
35569
|
setMachineProviderEnabled(type, enabled) {
|
|
35470
35570
|
return this.setMachineProviderConfig(type, { enabled });
|
|
35471
35571
|
}
|
|
35572
|
+
getEffectiveProviderAvailability(type) {
|
|
35573
|
+
const providerType = this.resolveAlias(type);
|
|
35574
|
+
const availability = this.providerAvailability.get(providerType);
|
|
35575
|
+
if (availability) return availability;
|
|
35576
|
+
const machineConfig = this.getMachineProviderConfig(providerType);
|
|
35577
|
+
const lastDetection = machineConfig.lastDetection;
|
|
35578
|
+
if (!lastDetection) return void 0;
|
|
35579
|
+
return {
|
|
35580
|
+
installed: lastDetection.ok === true,
|
|
35581
|
+
detectedPath: typeof lastDetection.path === "string" && lastDetection.path.trim() ? lastDetection.path.trim() : null
|
|
35582
|
+
};
|
|
35583
|
+
}
|
|
35472
35584
|
getMachineProviderStatus(type) {
|
|
35473
35585
|
const providerType = this.resolveAlias(type);
|
|
35474
35586
|
if (!this.isMachineProviderEnabled(providerType)) return "disabled";
|
|
35475
|
-
const availability = this.
|
|
35587
|
+
const availability = this.getEffectiveProviderAvailability(providerType);
|
|
35476
35588
|
if (!availability) return "enabled_unchecked";
|
|
35477
35589
|
return availability.installed ? "detected" : "not_detected";
|
|
35478
35590
|
}
|
|
@@ -35600,7 +35712,7 @@ var init_provider_loader = __esm({
|
|
|
35600
35712
|
}
|
|
35601
35713
|
getAvailableProviderInfos() {
|
|
35602
35714
|
return this.getAll().map((provider) => {
|
|
35603
|
-
const availability = this.
|
|
35715
|
+
const availability = this.getEffectiveProviderAvailability(provider.type);
|
|
35604
35716
|
const enabled = this.isMachineProviderEnabled(provider.type);
|
|
35605
35717
|
const machineConfig = this.getMachineProviderConfig(provider.type);
|
|
35606
35718
|
return {
|
|
@@ -37448,6 +37560,51 @@ function killPid(pid) {
|
|
|
37448
37560
|
return false;
|
|
37449
37561
|
}
|
|
37450
37562
|
}
|
|
37563
|
+
function getWindowsProcessCommandLine(pid) {
|
|
37564
|
+
const pidFilter = `ProcessId=${pid}`;
|
|
37565
|
+
try {
|
|
37566
|
+
const psOut = (0, import_child_process8.execFileSync)("powershell.exe", [
|
|
37567
|
+
"-NoProfile",
|
|
37568
|
+
"-NonInteractive",
|
|
37569
|
+
"-ExecutionPolicy",
|
|
37570
|
+
"Bypass",
|
|
37571
|
+
"-Command",
|
|
37572
|
+
`(Get-CimInstance Win32_Process -Filter "${pidFilter}").CommandLine`
|
|
37573
|
+
], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
37574
|
+
if (psOut) return psOut;
|
|
37575
|
+
} catch {
|
|
37576
|
+
}
|
|
37577
|
+
try {
|
|
37578
|
+
const wmicOut = (0, import_child_process8.execFileSync)("wmic", [
|
|
37579
|
+
"process",
|
|
37580
|
+
"where",
|
|
37581
|
+
pidFilter,
|
|
37582
|
+
"get",
|
|
37583
|
+
"CommandLine"
|
|
37584
|
+
], { encoding: "utf8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
37585
|
+
if (wmicOut) return wmicOut;
|
|
37586
|
+
} catch {
|
|
37587
|
+
}
|
|
37588
|
+
return null;
|
|
37589
|
+
}
|
|
37590
|
+
function getProcessCommandLine(pid) {
|
|
37591
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
37592
|
+
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
37593
|
+
try {
|
|
37594
|
+
const text = (0, import_child_process8.execFileSync)("ps", ["-o", "command=", "-p", String(pid)], {
|
|
37595
|
+
encoding: "utf8",
|
|
37596
|
+
timeout: 3e3,
|
|
37597
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
37598
|
+
}).trim();
|
|
37599
|
+
return text || null;
|
|
37600
|
+
} catch {
|
|
37601
|
+
return null;
|
|
37602
|
+
}
|
|
37603
|
+
}
|
|
37604
|
+
function isManagedSessionHostPid(pid) {
|
|
37605
|
+
const commandLine = getProcessCommandLine(pid);
|
|
37606
|
+
return !!commandLine && /session-host-daemon/i.test(commandLine);
|
|
37607
|
+
}
|
|
37451
37608
|
async function waitForPidExit(pid, timeoutMs) {
|
|
37452
37609
|
const start = Date.now();
|
|
37453
37610
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -37464,7 +37621,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
37464
37621
|
try {
|
|
37465
37622
|
if (fs8.existsSync(pidFile)) {
|
|
37466
37623
|
const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
|
|
37467
|
-
if (Number.isFinite(pid)) {
|
|
37624
|
+
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
|
|
37468
37625
|
killPid(pid);
|
|
37469
37626
|
}
|
|
37470
37627
|
}
|
|
@@ -37475,18 +37632,6 @@ function stopSessionHostProcesses(appName) {
|
|
|
37475
37632
|
} catch {
|
|
37476
37633
|
}
|
|
37477
37634
|
}
|
|
37478
|
-
if (process.platform !== "win32") {
|
|
37479
|
-
try {
|
|
37480
|
-
const raw = (0, import_child_process8.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
37481
|
-
for (const line of raw.split("\n")) {
|
|
37482
|
-
const pid = Number.parseInt(line.trim(), 10);
|
|
37483
|
-
if (Number.isFinite(pid)) {
|
|
37484
|
-
killPid(pid);
|
|
37485
|
-
}
|
|
37486
|
-
}
|
|
37487
|
-
} catch {
|
|
37488
|
-
}
|
|
37489
|
-
}
|
|
37490
37635
|
}
|
|
37491
37636
|
function removeDaemonPidFile() {
|
|
37492
37637
|
const pidFile = path16.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
@@ -39828,6 +39973,20 @@ var init_forward = __esm({
|
|
|
39828
39973
|
});
|
|
39829
39974
|
|
|
39830
39975
|
// ../../oss/packages/daemon-core/src/providers/provider-instance-manager.ts
|
|
39976
|
+
function projectHotChatSessionStatesFromProviderState(state) {
|
|
39977
|
+
const project = (item) => ({
|
|
39978
|
+
id: item.instanceId,
|
|
39979
|
+
status: item.activeChat?.status || item.status,
|
|
39980
|
+
runtimeLifecycle: item.runtime?.lifecycle ?? null,
|
|
39981
|
+
runtimeSurfaceKind: item.runtime?.surfaceKind,
|
|
39982
|
+
runtimeRestoredFromStorage: item.runtime?.restoredFromStorage === true,
|
|
39983
|
+
runtimeRecoveryState: item.runtime?.recoveryState ?? null
|
|
39984
|
+
});
|
|
39985
|
+
if (state.category === "ide") {
|
|
39986
|
+
return [project(state), ...state.extensions.map(project)];
|
|
39987
|
+
}
|
|
39988
|
+
return [project(state)];
|
|
39989
|
+
}
|
|
39831
39990
|
var ProviderInstanceManager;
|
|
39832
39991
|
var init_provider_instance_manager = __esm({
|
|
39833
39992
|
"../../oss/packages/daemon-core/src/providers/provider-instance-manager.ts"() {
|
|
@@ -39928,6 +40087,27 @@ var init_provider_instance_manager = __esm({
|
|
|
39928
40087
|
}
|
|
39929
40088
|
return states;
|
|
39930
40089
|
}
|
|
40090
|
+
collectHotChatSessionStates() {
|
|
40091
|
+
const sessions = [];
|
|
40092
|
+
for (const [id, instance] of this.instances) {
|
|
40093
|
+
try {
|
|
40094
|
+
const projected = instance.getHotChatSessionState?.();
|
|
40095
|
+
if (Array.isArray(projected)) {
|
|
40096
|
+
sessions.push(...projected.filter((session) => !!session?.id));
|
|
40097
|
+
continue;
|
|
40098
|
+
}
|
|
40099
|
+
if (projected?.id) {
|
|
40100
|
+
sessions.push(projected);
|
|
40101
|
+
continue;
|
|
40102
|
+
}
|
|
40103
|
+
const state = instance.getState();
|
|
40104
|
+
sessions.push(...projectHotChatSessionStatesFromProviderState(state));
|
|
40105
|
+
} catch (e) {
|
|
40106
|
+
LOG.warn("InstanceMgr", `[InstanceManager] Failed to collect hot chat metadata from ${id}: ${e.message}`);
|
|
40107
|
+
}
|
|
40108
|
+
}
|
|
40109
|
+
return sessions;
|
|
40110
|
+
}
|
|
39931
40111
|
/**
|
|
39932
40112
|
* Per-category status collect
|
|
39933
40113
|
*/
|
|
@@ -47410,19 +47590,20 @@ var init_screenshot_sender = __esm({
|
|
|
47410
47590
|
}
|
|
47411
47591
|
return sentAny;
|
|
47412
47592
|
}
|
|
47413
|
-
sendScreenshot(peers, base64Data) {
|
|
47593
|
+
sendScreenshot(peers, base64Data, targetSessionId) {
|
|
47414
47594
|
const buffer = Buffer.from(base64Data, "base64");
|
|
47415
|
-
return this.sendScreenshotBuffer(peers, buffer);
|
|
47595
|
+
return this.sendScreenshotBuffer(peers, buffer, targetSessionId);
|
|
47416
47596
|
}
|
|
47417
47597
|
/** Send screenshot as raw Buffer (no base64 conversion overhead) */
|
|
47418
|
-
sendScreenshotBuffer(peers, buffer) {
|
|
47598
|
+
sendScreenshotBuffer(peers, buffer, targetSessionId) {
|
|
47419
47599
|
let sentAny = false;
|
|
47420
47600
|
let debugOnce = !this._ssDebugDone;
|
|
47421
47601
|
for (const [pid, peer] of peers.entries()) {
|
|
47422
47602
|
if (debugOnce) {
|
|
47423
|
-
logDebug(`sendScreenshot peer=${pid}: state=${peer.state}, hasCh=${!!peer.dataChannel}, ssActive=${peer.screenshotActive}, chOpen=${peer.dataChannel?.isOpen?.() ?? "N/A"}, bufSize=${buffer.length}`);
|
|
47603
|
+
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}`);
|
|
47424
47604
|
}
|
|
47425
47605
|
if (peer.state !== "connected" || !peer.dataChannel || !peer.screenshotActive) continue;
|
|
47606
|
+
if (targetSessionId && peer.screenshotTargetSessionId !== targetSessionId) continue;
|
|
47426
47607
|
try {
|
|
47427
47608
|
if (!peer.dataChannel.isOpen()) continue;
|
|
47428
47609
|
const header = Buffer.alloc(4);
|
|
@@ -47454,18 +47635,32 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
47454
47635
|
log("Cannot initiate \u2014 node-datachannel not available");
|
|
47455
47636
|
return;
|
|
47456
47637
|
}
|
|
47638
|
+
const pid = peerId || `legacy_${Date.now()}`;
|
|
47639
|
+
const existing = deps.peers.get(pid);
|
|
47640
|
+
if (existing?.state === "connected") {
|
|
47641
|
+
log(`initiateconnection() ignored for peer ${pid} \u2014 already connected`);
|
|
47642
|
+
return;
|
|
47643
|
+
}
|
|
47644
|
+
if (existing?.state === "connecting") {
|
|
47645
|
+
log(`initiateconnection() ignored for peer ${pid} \u2014 connection already in progress`);
|
|
47646
|
+
return;
|
|
47647
|
+
}
|
|
47457
47648
|
const limits = deps.serverConn.getPlanLimits();
|
|
47458
47649
|
if (limits && limits.maxP2PConnections !== -1) {
|
|
47459
47650
|
let connectedCount = 0;
|
|
47651
|
+
let reservedCount = 0;
|
|
47460
47652
|
for (const peer of deps.peers.values()) {
|
|
47461
47653
|
if (peer.state === "connected") connectedCount++;
|
|
47654
|
+
if (peer.state === "connected" || peer.state === "connecting") reservedCount++;
|
|
47462
47655
|
}
|
|
47463
|
-
if (
|
|
47656
|
+
if (reservedCount >= limits.maxP2PConnections) {
|
|
47464
47657
|
let oldestPeer = null;
|
|
47465
|
-
|
|
47466
|
-
|
|
47467
|
-
if (
|
|
47468
|
-
oldestPeer
|
|
47658
|
+
if (connectedCount >= limits.maxP2PConnections) {
|
|
47659
|
+
for (const [peerKey, peer] of deps.peers) {
|
|
47660
|
+
if (peer.state === "connected") {
|
|
47661
|
+
if (!oldestPeer || peer.connectedAt < oldestPeer.at) {
|
|
47662
|
+
oldestPeer = { id: peerKey, at: peer.connectedAt };
|
|
47663
|
+
}
|
|
47469
47664
|
}
|
|
47470
47665
|
}
|
|
47471
47666
|
}
|
|
@@ -47483,19 +47678,12 @@ async function initiateConnection(deps, peerId, sharePermission) {
|
|
|
47483
47678
|
}
|
|
47484
47679
|
}
|
|
47485
47680
|
disconnectPeer(deps.peers, oldestPeer.id, deps.notifyStateChange);
|
|
47681
|
+
} else {
|
|
47682
|
+
log(`P2P limit reached (${reservedCount}/${limits.maxP2PConnections}) with reserved connecting slot(s). Rejecting peer ${pid.slice(0, 12)}\u2026`);
|
|
47683
|
+
return;
|
|
47486
47684
|
}
|
|
47487
47685
|
}
|
|
47488
47686
|
}
|
|
47489
|
-
const pid = peerId || `legacy_${Date.now()}`;
|
|
47490
|
-
const existing = deps.peers.get(pid);
|
|
47491
|
-
if (existing?.state === "connected") {
|
|
47492
|
-
log(`initiateconnection() ignored for peer ${pid} \u2014 already connected`);
|
|
47493
|
-
return;
|
|
47494
|
-
}
|
|
47495
|
-
if (existing?.state === "connecting") {
|
|
47496
|
-
log(`initiateconnection() ignored for peer ${pid} \u2014 connection already in progress`);
|
|
47497
|
-
return;
|
|
47498
|
-
}
|
|
47499
47687
|
log(`initiateconnection() for peer ${pid}...`);
|
|
47500
47688
|
const mod = deps.nodeDatachannel;
|
|
47501
47689
|
const PeerConnectionCtor = mod.PeerConnection || mod.default?.PeerConnection || mod.default || mod;
|
|
@@ -47854,14 +48042,19 @@ var init_daemon_p2p = __esm({
|
|
|
47854
48042
|
}
|
|
47855
48043
|
return false;
|
|
47856
48044
|
}
|
|
47857
|
-
/** Get
|
|
47858
|
-
get
|
|
48045
|
+
/** Get all target sessions for active screenshot requests */
|
|
48046
|
+
get screenshotTargetSessionIds() {
|
|
48047
|
+
const targets = /* @__PURE__ */ new Set();
|
|
47859
48048
|
for (const peer of this.peers.values()) {
|
|
47860
48049
|
if (peer.screenshotActive && peer.state === "connected" && peer.screenshotTargetSessionId) {
|
|
47861
|
-
|
|
48050
|
+
targets.add(peer.screenshotTargetSessionId);
|
|
47862
48051
|
}
|
|
47863
48052
|
}
|
|
47864
|
-
return
|
|
48053
|
+
return Array.from(targets);
|
|
48054
|
+
}
|
|
48055
|
+
/** Get the target session for the currently active screenshot request */
|
|
48056
|
+
get screenshotTargetSessionId() {
|
|
48057
|
+
return this.screenshotTargetSessionIds[0];
|
|
47865
48058
|
}
|
|
47866
48059
|
constructor(serverConn) {
|
|
47867
48060
|
this.serverConn = serverConn;
|
|
@@ -47970,6 +48163,14 @@ ${e?.stack || ""}`);
|
|
|
47970
48163
|
}
|
|
47971
48164
|
return false;
|
|
47972
48165
|
}
|
|
48166
|
+
hasAnyNeedingFirstFrameForTarget(targetSessionId) {
|
|
48167
|
+
for (const peer of this.peers.values()) {
|
|
48168
|
+
if (peer.needsFirstFrame && peer.screenshotActive && peer.state === "connected" && peer.screenshotTargetSessionId === targetSessionId) {
|
|
48169
|
+
return true;
|
|
48170
|
+
}
|
|
48171
|
+
}
|
|
48172
|
+
return false;
|
|
48173
|
+
}
|
|
47973
48174
|
onStateChange(listener) {
|
|
47974
48175
|
this.stateListeners.push(listener);
|
|
47975
48176
|
}
|
|
@@ -48033,11 +48234,14 @@ ${e?.stack || ""}`);
|
|
|
48033
48234
|
if (targetPeers.size === 0) return false;
|
|
48034
48235
|
return this.screenshotSender.broadcastSessionOutput(targetPeers, sessionId, data);
|
|
48035
48236
|
}
|
|
48036
|
-
sendScreenshot(base64Data) {
|
|
48037
|
-
return this.screenshotSender.sendScreenshot(this.peers, base64Data);
|
|
48237
|
+
sendScreenshot(base64Data, targetSessionId) {
|
|
48238
|
+
return this.screenshotSender.sendScreenshot(this.peers, base64Data, targetSessionId);
|
|
48038
48239
|
}
|
|
48039
|
-
sendScreenshotBuffer(buffer) {
|
|
48040
|
-
return this.screenshotSender.sendScreenshotBuffer(this.peers, buffer);
|
|
48240
|
+
sendScreenshotBuffer(buffer, targetSessionId) {
|
|
48241
|
+
return this.screenshotSender.sendScreenshotBuffer(this.peers, buffer, targetSessionId);
|
|
48242
|
+
}
|
|
48243
|
+
sendScreenshotBufferForTarget(targetSessionId, buffer) {
|
|
48244
|
+
return this.sendScreenshotBuffer(buffer, targetSessionId);
|
|
48041
48245
|
}
|
|
48042
48246
|
// ─── Handler registration (unchanged API) ───────
|
|
48043
48247
|
onFileRequest(handler) {
|
|
@@ -54761,6 +54965,7 @@ var init_screenshot_controller = __esm({
|
|
|
54761
54965
|
lastSize = 0;
|
|
54762
54966
|
lastHash = 0;
|
|
54763
54967
|
staticFrameCount = 0;
|
|
54968
|
+
targetFrameState = /* @__PURE__ */ new Map();
|
|
54764
54969
|
currentInterval;
|
|
54765
54970
|
// Quality profiles
|
|
54766
54971
|
profileDirect;
|
|
@@ -54824,14 +55029,13 @@ var init_screenshot_controller = __esm({
|
|
|
54824
55029
|
async tick() {
|
|
54825
55030
|
if (!this.deps.isRunning()) return;
|
|
54826
55031
|
const active = this.deps.isScreenshotActive();
|
|
54827
|
-
const
|
|
54828
|
-
|
|
55032
|
+
const targetSessionIds = this.getActiveTargetSessionIds();
|
|
55033
|
+
const isRelay = this.deps.isUsingRelay();
|
|
55034
|
+
const profile = isRelay ? this.profileRelay : this.profileDirect;
|
|
55035
|
+
if (active && targetSessionIds.length === 0) {
|
|
54829
55036
|
this.timer = setTimeout(() => this.tick(), 500);
|
|
54830
55037
|
return;
|
|
54831
55038
|
}
|
|
54832
|
-
const cdp = targetSessionId ? this.deps.getCdp(targetSessionId) : null;
|
|
54833
|
-
const isRelay = this.deps.isUsingRelay();
|
|
54834
|
-
const profile = isRelay ? this.profileRelay : this.profileDirect;
|
|
54835
55039
|
this.checkBudgetReset();
|
|
54836
55040
|
if (this.dailyBudgetMs > 0) {
|
|
54837
55041
|
const now = Date.now();
|
|
@@ -54846,49 +55050,84 @@ var init_screenshot_controller = __esm({
|
|
|
54846
55050
|
}
|
|
54847
55051
|
}
|
|
54848
55052
|
const budgetBlocked = this.budgetExhausted && isRelay;
|
|
54849
|
-
if (!active ||
|
|
55053
|
+
if (!active || budgetBlocked) {
|
|
54850
55054
|
this.staticFrameCount = 0;
|
|
55055
|
+
this.targetFrameState.clear();
|
|
54851
55056
|
this.currentInterval = profile.maxInterval;
|
|
54852
55057
|
if (!active) this.lastActiveTimestamp = 0;
|
|
54853
55058
|
this.timer = setTimeout(() => this.tick(), budgetBlocked ? 3e4 : this.currentInterval);
|
|
54854
55059
|
return;
|
|
54855
55060
|
}
|
|
54856
55061
|
this.debugCount++;
|
|
54857
|
-
|
|
54858
|
-
|
|
54859
|
-
|
|
55062
|
+
let capturedAny = false;
|
|
55063
|
+
let sentAnyFrame = false;
|
|
55064
|
+
let anyFirstFrameAcrossTargets = false;
|
|
55065
|
+
for (const targetSessionId of targetSessionIds) {
|
|
55066
|
+
const cdp = this.deps.getCdp(targetSessionId);
|
|
55067
|
+
if (!cdp) continue;
|
|
55068
|
+
try {
|
|
55069
|
+
const buf = await cdp.captureScreenshot({ quality: profile.quality });
|
|
55070
|
+
if (!buf) {
|
|
55071
|
+
if (this.debugCount <= 5) LOG.debug("Screenshot", `captureScreenshot returned null for target=${targetSessionId}`);
|
|
55072
|
+
continue;
|
|
55073
|
+
}
|
|
55074
|
+
capturedAny = true;
|
|
55075
|
+
const state = this.getTargetFrameState(targetSessionId);
|
|
54860
55076
|
const hash2 = _ScreenshotController.fnvHash(buf);
|
|
54861
|
-
const sizeMatch = buf.length ===
|
|
54862
|
-
const hashMatch = hash2 ===
|
|
54863
|
-
const anyNeedsFirstFrame = this.deps.hasAnyNeedingFirstFrame();
|
|
55077
|
+
const sizeMatch = buf.length === state.lastSize;
|
|
55078
|
+
const hashMatch = hash2 === state.lastHash;
|
|
55079
|
+
const anyNeedsFirstFrame = this.deps.hasAnyNeedingFirstFrameForTarget?.(targetSessionId) ?? this.deps.hasAnyNeedingFirstFrame();
|
|
54864
55080
|
const resizeTarget = anyNeedsFirstFrame ? profile.firstFrameLongEdge : profile.maxLongEdge;
|
|
55081
|
+
anyFirstFrameAcrossTargets = anyFirstFrameAcrossTargets || anyNeedsFirstFrame;
|
|
54865
55082
|
if (sizeMatch && hashMatch && !anyNeedsFirstFrame) {
|
|
54866
|
-
|
|
54867
|
-
if (
|
|
55083
|
+
state.staticFrameCount++;
|
|
55084
|
+
if (state.staticFrameCount >= this.STATIC_THRESHOLD) {
|
|
54868
55085
|
this.currentInterval = Math.min(this.currentInterval + 200, profile.maxInterval);
|
|
54869
55086
|
}
|
|
54870
55087
|
if (this.debugCount <= 5 || this.debugCount % 50 === 0) {
|
|
54871
|
-
LOG.debug("Screenshot", `skip (unchanged, static=${
|
|
54872
|
-
}
|
|
54873
|
-
} else {
|
|
54874
|
-
const normalizedBuf = await this.normalizeBuffer(buf, resizeTarget, profile.quality);
|
|
54875
|
-
this.lastSize = buf.length;
|
|
54876
|
-
this.lastHash = hash2;
|
|
54877
|
-
this.staticFrameCount = 0;
|
|
54878
|
-
this.currentInterval = profile.minInterval;
|
|
54879
|
-
const sent = this.deps.sendScreenshotBuffer(normalizedBuf);
|
|
54880
|
-
if (this.debugCount <= 3 || anyNeedsFirstFrame) {
|
|
54881
|
-
LOG.debug("Screenshot", `sent: ${normalizedBuf.length} bytes, delivered=${sent}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
|
|
55088
|
+
LOG.debug("Screenshot", `skip target=${targetSessionId} (unchanged, static=${state.staticFrameCount}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"})`);
|
|
54882
55089
|
}
|
|
55090
|
+
continue;
|
|
54883
55091
|
}
|
|
54884
|
-
|
|
54885
|
-
|
|
55092
|
+
const normalizedBuf = await this.normalizeBuffer(buf, resizeTarget, profile.quality);
|
|
55093
|
+
state.lastSize = buf.length;
|
|
55094
|
+
state.lastHash = hash2;
|
|
55095
|
+
state.staticFrameCount = 0;
|
|
55096
|
+
this.lastSize = buf.length;
|
|
55097
|
+
this.lastHash = hash2;
|
|
55098
|
+
this.staticFrameCount = 0;
|
|
55099
|
+
this.currentInterval = profile.minInterval;
|
|
55100
|
+
const sent = this.deps.sendScreenshotBufferForTarget ? this.deps.sendScreenshotBufferForTarget(targetSessionId, normalizedBuf) : this.deps.sendScreenshotBuffer(normalizedBuf);
|
|
55101
|
+
sentAnyFrame = sentAnyFrame || sent;
|
|
55102
|
+
if (this.debugCount <= 3 || anyNeedsFirstFrame) {
|
|
55103
|
+
LOG.debug("Screenshot", `sent target=${targetSessionId}: ${normalizedBuf.length} bytes, delivered=${sent}, interval=${this.currentInterval}ms, ${isRelay ? "RELAY" : "DIRECT"}${anyNeedsFirstFrame ? " (first-frame)" : ""}`);
|
|
55104
|
+
}
|
|
55105
|
+
} catch (e) {
|
|
55106
|
+
if (this.debugCount <= 5) LOG.warn("Screenshot", `error target=${targetSessionId}: ${e?.message}`);
|
|
54886
55107
|
}
|
|
54887
|
-
}
|
|
54888
|
-
|
|
55108
|
+
}
|
|
55109
|
+
if (!capturedAny) {
|
|
55110
|
+
this.currentInterval = profile.maxInterval;
|
|
55111
|
+
} else if (!sentAnyFrame && !anyFirstFrameAcrossTargets) {
|
|
55112
|
+
this.currentInterval = Math.min(this.currentInterval + 200, profile.maxInterval);
|
|
54889
55113
|
}
|
|
54890
55114
|
this.timer = setTimeout(() => this.tick(), this.currentInterval);
|
|
54891
55115
|
}
|
|
55116
|
+
getActiveTargetSessionIds() {
|
|
55117
|
+
const explicitTargets = this.deps.getScreenshotTargetSessionIds?.() || [];
|
|
55118
|
+
const normalized = explicitTargets.map((target) => typeof target === "string" ? target.trim() : "").filter((target) => target.length > 0);
|
|
55119
|
+
if (normalized.length > 0) return Array.from(new Set(normalized));
|
|
55120
|
+
const legacyTarget = this.deps.getScreenshotTargetSessionId();
|
|
55121
|
+
return legacyTarget ? [legacyTarget] : [];
|
|
55122
|
+
}
|
|
55123
|
+
getTargetFrameState(targetSessionId) {
|
|
55124
|
+
let state = this.targetFrameState.get(targetSessionId);
|
|
55125
|
+
if (!state) {
|
|
55126
|
+
state = { lastSize: 0, lastHash: 0, staticFrameCount: 0 };
|
|
55127
|
+
this.targetFrameState.set(targetSessionId, state);
|
|
55128
|
+
}
|
|
55129
|
+
return state;
|
|
55130
|
+
}
|
|
54892
55131
|
// ─── Budget ───────────────────────────────────
|
|
54893
55132
|
checkBudgetReset() {
|
|
54894
55133
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -55079,7 +55318,7 @@ function killPid2(pid) {
|
|
|
55079
55318
|
return false;
|
|
55080
55319
|
}
|
|
55081
55320
|
}
|
|
55082
|
-
function
|
|
55321
|
+
function getWindowsProcessCommandLine2(pid) {
|
|
55083
55322
|
const pidFilter = `ProcessId=${pid}`;
|
|
55084
55323
|
try {
|
|
55085
55324
|
const psOut = (0, import_child_process12.execFileSync)("powershell.exe", [
|
|
@@ -55108,13 +55347,32 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
55108
55347
|
}
|
|
55109
55348
|
return null;
|
|
55110
55349
|
}
|
|
55350
|
+
function getProcessCommandLine2(pid) {
|
|
55351
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
55352
|
+
if (process.platform === "win32") return getWindowsProcessCommandLine2(pid);
|
|
55353
|
+
try {
|
|
55354
|
+
const text = (0, import_child_process12.execFileSync)("ps", ["-o", "command=", "-p", String(pid)], {
|
|
55355
|
+
encoding: "utf8",
|
|
55356
|
+
timeout: 3e3,
|
|
55357
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
55358
|
+
}).trim();
|
|
55359
|
+
return text || null;
|
|
55360
|
+
} catch {
|
|
55361
|
+
return null;
|
|
55362
|
+
}
|
|
55363
|
+
}
|
|
55364
|
+
function isManagedSessionHostPid2(pid) {
|
|
55365
|
+
const commandLine = getProcessCommandLine2(pid);
|
|
55366
|
+
if (!commandLine) return false;
|
|
55367
|
+
return /session-host-daemon/i.test(commandLine);
|
|
55368
|
+
}
|
|
55111
55369
|
function stopManagedSessionHostProcess() {
|
|
55112
55370
|
let stopped = false;
|
|
55113
55371
|
const pidFile = getSessionHostPidFile();
|
|
55114
55372
|
try {
|
|
55115
55373
|
if (fs17.existsSync(pidFile)) {
|
|
55116
55374
|
const pid = Number.parseInt(fs17.readFileSync(pidFile, "utf8").trim(), 10);
|
|
55117
|
-
if (Number.isFinite(pid) && pid !== process.pid) {
|
|
55375
|
+
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid2(pid)) {
|
|
55118
55376
|
stopped = killPid2(pid) || stopped;
|
|
55119
55377
|
}
|
|
55120
55378
|
}
|
|
@@ -55128,40 +55386,7 @@ function stopManagedSessionHostProcess() {
|
|
|
55128
55386
|
return stopped;
|
|
55129
55387
|
}
|
|
55130
55388
|
function stopSessionHost() {
|
|
55131
|
-
|
|
55132
|
-
if (process.platform === "win32") {
|
|
55133
|
-
try {
|
|
55134
|
-
const raw = (0, import_child_process12.execFileSync)("tasklist", ["/FO", "CSV", "/NH", "/FI", "IMAGENAME eq node.exe"], {
|
|
55135
|
-
encoding: "utf8",
|
|
55136
|
-
timeout: 5e3,
|
|
55137
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
55138
|
-
windowsHide: true
|
|
55139
|
-
}).trim();
|
|
55140
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
55141
|
-
const match = line.match(/^"node\.exe","(\d+)"/i);
|
|
55142
|
-
if (!match) continue;
|
|
55143
|
-
const candidatePid = Number.parseInt(match[1], 10);
|
|
55144
|
-
if (!Number.isFinite(candidatePid) || candidatePid === process.pid) continue;
|
|
55145
|
-
const commandLine = getWindowsProcessCommandLine(candidatePid);
|
|
55146
|
-
if (commandLine?.includes("session-host-daemon")) {
|
|
55147
|
-
stopped = killPid2(candidatePid) || stopped;
|
|
55148
|
-
}
|
|
55149
|
-
}
|
|
55150
|
-
} catch {
|
|
55151
|
-
}
|
|
55152
|
-
} else {
|
|
55153
|
-
try {
|
|
55154
|
-
const raw = (0, import_child_process12.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
55155
|
-
for (const line of raw.split("\n")) {
|
|
55156
|
-
const pid = Number.parseInt(line.trim(), 10);
|
|
55157
|
-
if (Number.isFinite(pid) && pid !== process.pid && pid !== process.ppid) {
|
|
55158
|
-
stopped = killPid2(pid) || stopped;
|
|
55159
|
-
}
|
|
55160
|
-
}
|
|
55161
|
-
} catch {
|
|
55162
|
-
}
|
|
55163
|
-
}
|
|
55164
|
-
return stopped;
|
|
55389
|
+
return stopManagedSessionHostProcess();
|
|
55165
55390
|
}
|
|
55166
55391
|
async function ensureSessionHostReady2() {
|
|
55167
55392
|
const quarantine = quarantineLegacyStandaloneSessions({
|
|
@@ -55938,10 +56163,65 @@ var init_version = __esm({
|
|
|
55938
56163
|
var adhdev_daemon_exports = {};
|
|
55939
56164
|
__export(adhdev_daemon_exports, {
|
|
55940
56165
|
AdhdevDaemon: () => AdhdevDaemon,
|
|
56166
|
+
buildMandatoryUpdateInfoFromServerPayload: () => buildMandatoryUpdateInfoFromServerPayload,
|
|
56167
|
+
buildMandatoryUpdateRequiredPayload: () => buildMandatoryUpdateRequiredPayload,
|
|
55941
56168
|
getDaemonPid: () => getDaemonPid,
|
|
55942
56169
|
isDaemonRunning: () => isDaemonRunning,
|
|
55943
|
-
stopDaemon: () => stopDaemon
|
|
55944
|
-
|
|
56170
|
+
stopDaemon: () => stopDaemon,
|
|
56171
|
+
validateMandatoryUpdateTarget: () => validateMandatoryUpdateTarget,
|
|
56172
|
+
verifyPublishedMandatoryUpdateTarget: () => verifyPublishedMandatoryUpdateTarget
|
|
56173
|
+
});
|
|
56174
|
+
function validateMandatoryUpdateTarget(targetVersion) {
|
|
56175
|
+
if (typeof targetVersion !== "string") return { valid: false, error: "target version is required" };
|
|
56176
|
+
if (targetVersion !== targetVersion.trim()) return { valid: false, error: "target version must not contain whitespace" };
|
|
56177
|
+
const version2 = targetVersion;
|
|
56178
|
+
if (!version2) return { valid: false, error: "target version is required" };
|
|
56179
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z]+(?:\.[0-9A-Za-z]+)*)?(?:\+[0-9A-Za-z]+(?:\.[0-9A-Za-z]+)*)?$/.test(version2)) {
|
|
56180
|
+
return { valid: false, error: `invalid semver target: ${version2}` };
|
|
56181
|
+
}
|
|
56182
|
+
return { valid: true };
|
|
56183
|
+
}
|
|
56184
|
+
function verifyPublishedMandatoryUpdateTarget(packageName, targetVersion, deps = {}) {
|
|
56185
|
+
if (!/^(?:adhdev|@adhdev\/daemon-standalone)$/.test(packageName)) {
|
|
56186
|
+
throw new Error(`invalid mandatory update package: ${packageName}`);
|
|
56187
|
+
}
|
|
56188
|
+
const validation = validateMandatoryUpdateTarget(targetVersion);
|
|
56189
|
+
if (!validation.valid) throw new Error(validation.error || "invalid mandatory update target");
|
|
56190
|
+
const run = deps.execFileSync || import_child_process13.execFileSync;
|
|
56191
|
+
const npmExecutable = deps.npmExecutable || resolveCurrentGlobalInstallSurface({ packageName }).npmExecutable;
|
|
56192
|
+
const published = String(run(npmExecutable, ["view", `${packageName}@${targetVersion}`, "version"], {
|
|
56193
|
+
encoding: "utf-8",
|
|
56194
|
+
timeout: 1e4,
|
|
56195
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
56196
|
+
...process.platform === "win32" ? { shell: true, windowsHide: true } : {}
|
|
56197
|
+
})).trim();
|
|
56198
|
+
if (published !== targetVersion) {
|
|
56199
|
+
throw new Error(`Published version mismatch: expected ${targetVersion}, got ${published || "unknown"}`);
|
|
56200
|
+
}
|
|
56201
|
+
return published;
|
|
56202
|
+
}
|
|
56203
|
+
function buildMandatoryUpdateInfoFromServerPayload(payload, fallbackVersion) {
|
|
56204
|
+
const targetVersion = typeof payload?.latest === "string" && payload.latest ? payload.latest : fallbackVersion;
|
|
56205
|
+
const validation = validateMandatoryUpdateTarget(targetVersion);
|
|
56206
|
+
if (!validation.valid) return { info: null, error: validation.error || targetVersion };
|
|
56207
|
+
return {
|
|
56208
|
+
info: {
|
|
56209
|
+
targetVersion,
|
|
56210
|
+
reason: typeof payload?.reason === "string" && payload.reason.trim() ? payload.reason.trim() : "major_minor_mismatch",
|
|
56211
|
+
minVersion: typeof payload?.minVersion === "string" && payload.minVersion.trim() ? payload.minVersion.trim() : void 0
|
|
56212
|
+
}
|
|
56213
|
+
};
|
|
56214
|
+
}
|
|
56215
|
+
function buildMandatoryUpdateRequiredPayload(pending, interactionId) {
|
|
56216
|
+
return {
|
|
56217
|
+
error: "A mandatory daemon update is pending. Finish current work and let the daemon update before starting a new session.",
|
|
56218
|
+
code: "DAEMON_UPDATE_REQUIRED",
|
|
56219
|
+
required: true,
|
|
56220
|
+
latest: pending.targetVersion,
|
|
56221
|
+
reason: pending.reason,
|
|
56222
|
+
interactionId
|
|
56223
|
+
};
|
|
56224
|
+
}
|
|
55945
56225
|
function resolveDaemonPort(ref = {}) {
|
|
55946
56226
|
return Number.isFinite(ref.port) && Number(ref.port) > 0 ? Number(ref.port) : DEFAULT_DAEMON_PORT;
|
|
55947
56227
|
}
|
|
@@ -55968,7 +56248,7 @@ function removeDaemonPid(ref = {}) {
|
|
|
55968
56248
|
function isDaemonRunning(ref = {}) {
|
|
55969
56249
|
const port = resolveDaemonPort(ref);
|
|
55970
56250
|
try {
|
|
55971
|
-
const { execFileSync:
|
|
56251
|
+
const { execFileSync: execFileSync6 } = require("child_process");
|
|
55972
56252
|
const probe = `
|
|
55973
56253
|
const http = require('http');
|
|
55974
56254
|
const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
|
|
@@ -55978,7 +56258,7 @@ function isDaemonRunning(ref = {}) {
|
|
|
55978
56258
|
req.on('error', () => process.stdout.write('0'));
|
|
55979
56259
|
req.on('timeout', () => { req.destroy(); process.stdout.write('0'); });
|
|
55980
56260
|
`;
|
|
55981
|
-
const result =
|
|
56261
|
+
const result = execFileSync6(process.execPath, ["-e", probe], {
|
|
55982
56262
|
encoding: "utf-8",
|
|
55983
56263
|
timeout: 3e3,
|
|
55984
56264
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -56004,9 +56284,9 @@ function isDaemonRunning(ref = {}) {
|
|
|
56004
56284
|
function isAdhdevProcess(pid) {
|
|
56005
56285
|
try {
|
|
56006
56286
|
if (process.platform === "win32") {
|
|
56007
|
-
const { execFileSync:
|
|
56287
|
+
const { execFileSync: execFileSync6 } = require("child_process");
|
|
56008
56288
|
try {
|
|
56009
|
-
const psOut =
|
|
56289
|
+
const psOut = execFileSync6("powershell.exe", [
|
|
56010
56290
|
"-NoProfile",
|
|
56011
56291
|
"-NonInteractive",
|
|
56012
56292
|
"-ExecutionPolicy",
|
|
@@ -56019,8 +56299,8 @@ function isAdhdevProcess(pid) {
|
|
|
56019
56299
|
return true;
|
|
56020
56300
|
}
|
|
56021
56301
|
} else {
|
|
56022
|
-
const { execFileSync:
|
|
56023
|
-
const cmdline =
|
|
56302
|
+
const { execFileSync: execFileSync6 } = require("child_process");
|
|
56303
|
+
const cmdline = execFileSync6("ps", ["-o", "command=", "-p", String(pid)], {
|
|
56024
56304
|
encoding: "utf-8",
|
|
56025
56305
|
timeout: 2e3,
|
|
56026
56306
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -56034,7 +56314,7 @@ function isAdhdevProcess(pid) {
|
|
|
56034
56314
|
function getDaemonHealthPid(ref = {}) {
|
|
56035
56315
|
const port = resolveDaemonPort(ref);
|
|
56036
56316
|
try {
|
|
56037
|
-
const { execFileSync:
|
|
56317
|
+
const { execFileSync: execFileSync6 } = require("child_process");
|
|
56038
56318
|
const probe = `
|
|
56039
56319
|
const http = require('http');
|
|
56040
56320
|
const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
|
|
@@ -56052,7 +56332,7 @@ function getDaemonHealthPid(ref = {}) {
|
|
|
56052
56332
|
req.on('error', () => {});
|
|
56053
56333
|
req.on('timeout', () => { req.destroy(); });
|
|
56054
56334
|
`;
|
|
56055
|
-
const result =
|
|
56335
|
+
const result = execFileSync6(process.execPath, ["-e", probe], {
|
|
56056
56336
|
encoding: "utf-8",
|
|
56057
56337
|
timeout: 3e3,
|
|
56058
56338
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -56098,7 +56378,7 @@ function stopDaemon(ref = {}) {
|
|
|
56098
56378
|
return false;
|
|
56099
56379
|
}
|
|
56100
56380
|
}
|
|
56101
|
-
var os26, fs18, path26, import_http, import_ws3, pkgVersion, AdhdevDaemon;
|
|
56381
|
+
var os26, fs18, path26, import_http, import_child_process13, import_ws3, pkgVersion, AdhdevDaemon;
|
|
56102
56382
|
var init_adhdev_daemon = __esm({
|
|
56103
56383
|
"src/adhdev-daemon.ts"() {
|
|
56104
56384
|
"use strict";
|
|
@@ -56114,12 +56394,13 @@ var init_adhdev_daemon = __esm({
|
|
|
56114
56394
|
fs18 = __toESM(require("fs"));
|
|
56115
56395
|
path26 = __toESM(require("path"));
|
|
56116
56396
|
import_http = require("http");
|
|
56397
|
+
import_child_process13 = require("child_process");
|
|
56117
56398
|
import_ws3 = require("ws");
|
|
56118
56399
|
init_source2();
|
|
56119
56400
|
init_version();
|
|
56120
56401
|
init_src();
|
|
56121
56402
|
init_runtime_defaults();
|
|
56122
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
56403
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.34" });
|
|
56123
56404
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
56124
56405
|
localHttpServer = null;
|
|
56125
56406
|
localWss = null;
|
|
@@ -56212,6 +56493,10 @@ var init_adhdev_daemon = __esm({
|
|
|
56212
56493
|
getUpgradePackageName() {
|
|
56213
56494
|
return process.argv[1]?.includes("daemon-standalone") ? "@adhdev/daemon-standalone" : "adhdev";
|
|
56214
56495
|
}
|
|
56496
|
+
getMandatoryUpdateBlockPayload(cmd, interactionId) {
|
|
56497
|
+
if (!this.pendingMandatoryUpdate || !_AdhdevDaemon.MANDATORY_UPDATE_BLOCKED_COMMANDS.has(cmd)) return null;
|
|
56498
|
+
return buildMandatoryUpdateRequiredPayload(this.pendingMandatoryUpdate, interactionId);
|
|
56499
|
+
}
|
|
56215
56500
|
hasBlockingSessionsForMandatoryUpdate() {
|
|
56216
56501
|
if (!this.components) return false;
|
|
56217
56502
|
const blocking = /* @__PURE__ */ new Set(["generating", "waiting_approval", "starting"]);
|
|
@@ -56237,15 +56522,7 @@ var init_adhdev_daemon = __esm({
|
|
|
56237
56522
|
const pkgName = this.getUpgradePackageName();
|
|
56238
56523
|
this.mandatoryUpgradeInFlight = true;
|
|
56239
56524
|
try {
|
|
56240
|
-
|
|
56241
|
-
const published = execSync7(`npm view ${pkgName}@${pending.targetVersion} version`, {
|
|
56242
|
-
encoding: "utf-8",
|
|
56243
|
-
timeout: 1e4,
|
|
56244
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
56245
|
-
}).trim();
|
|
56246
|
-
if (published !== pending.targetVersion) {
|
|
56247
|
-
throw new Error(`Published version mismatch: expected ${pending.targetVersion}, got ${published || "unknown"}`);
|
|
56248
|
-
}
|
|
56525
|
+
verifyPublishedMandatoryUpdateTarget(pkgName, pending.targetVersion);
|
|
56249
56526
|
LOG.warn("Upgrade", `Applying mandatory daemon update (${pending.reason}) \u2192 v${pending.targetVersion}`);
|
|
56250
56527
|
spawnDetachedDaemonUpgradeHelper({
|
|
56251
56528
|
packageName: pkgName,
|
|
@@ -56347,7 +56624,7 @@ var init_adhdev_daemon = __esm({
|
|
|
56347
56624
|
const now = Date.now();
|
|
56348
56625
|
const cached2 = this.hotChatSnapshotCache;
|
|
56349
56626
|
const sessions = cached2 && now - cached2.builtAt < _AdhdevDaemon.HOT_CHAT_SNAPSHOT_CACHE_TTL_MS ? cached2.sessions : (() => {
|
|
56350
|
-
const built = this.
|
|
56627
|
+
const built = this.components.instanceManager.collectHotChatSessionStates();
|
|
56351
56628
|
this.hotChatSnapshotCache = { sessions: built, builtAt: now };
|
|
56352
56629
|
return built;
|
|
56353
56630
|
})();
|
|
@@ -56732,14 +57009,17 @@ ${err?.stack || ""}`);
|
|
|
56732
57009
|
isRunning: () => this.running,
|
|
56733
57010
|
isScreenshotActive: () => this.p2p?.screenshotActive ?? false,
|
|
56734
57011
|
getScreenshotTargetSessionId: () => this.p2p?.screenshotTargetSessionId,
|
|
57012
|
+
getScreenshotTargetSessionIds: () => this.p2p?.screenshotTargetSessionIds ?? [],
|
|
56735
57013
|
isUsingRelay: () => this.p2p?.isUsingRelay ?? false,
|
|
56736
57014
|
hasAnyNeedingFirstFrame: () => this.p2p?.hasAnyNeedingFirstFrame() ?? false,
|
|
57015
|
+
hasAnyNeedingFirstFrameForTarget: (targetSessionId) => this.p2p?.hasAnyNeedingFirstFrameForTarget(targetSessionId) ?? false,
|
|
56737
57016
|
getCdp: (targetSessionId) => {
|
|
56738
57017
|
if (targetSessionId) return this.getCdpFor(targetSessionId);
|
|
56739
57018
|
LOG.warn("P2P", "Screenshot requested without targetSessionId \u2014 cannot determine target session. Skipping frame.");
|
|
56740
57019
|
return null;
|
|
56741
57020
|
},
|
|
56742
|
-
sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf)
|
|
57021
|
+
sendScreenshotBuffer: (buf) => this.p2p.sendScreenshotBuffer(buf),
|
|
57022
|
+
sendScreenshotBufferForTarget: (targetSessionId, buf) => this.p2p.sendScreenshotBufferForTarget(targetSessionId, buf)
|
|
56743
57023
|
}, planLimits ?? void 0);
|
|
56744
57024
|
this.screenshotController.start();
|
|
56745
57025
|
this.p2p.onScreenshotStart(() => this.screenshotController?.triggerImmediate());
|
|
@@ -56768,11 +57048,12 @@ ${err?.stack || ""}`);
|
|
|
56768
57048
|
});
|
|
56769
57049
|
this.serverConn.on("force_update_required", (msg) => {
|
|
56770
57050
|
const payload = msg.payload;
|
|
56771
|
-
|
|
56772
|
-
|
|
56773
|
-
|
|
56774
|
-
|
|
56775
|
-
}
|
|
57051
|
+
const parsedUpdate = buildMandatoryUpdateInfoFromServerPayload(payload, pkgVersion);
|
|
57052
|
+
if (!parsedUpdate.info) {
|
|
57053
|
+
LOG.error("Upgrade", `Ignoring invalid mandatory daemon update target from server: ${parsedUpdate.error || "unknown"}`);
|
|
57054
|
+
return;
|
|
57055
|
+
}
|
|
57056
|
+
this.pendingMandatoryUpdate = parsedUpdate.info;
|
|
56776
57057
|
LOG.warn("Upgrade", `Mandatory daemon update required (${this.pendingMandatoryUpdate.reason})`);
|
|
56777
57058
|
void this.maybeApplyMandatoryUpdate("server-force-update");
|
|
56778
57059
|
});
|
|
@@ -56883,15 +57164,9 @@ ${err?.stack || ""}`);
|
|
|
56883
57164
|
const cmdStart = Date.now();
|
|
56884
57165
|
const source = msg.ipcWs ? "ext" : typeof msg.source === "string" && msg.source.trim() ? msg.source : "ws";
|
|
56885
57166
|
try {
|
|
56886
|
-
|
|
56887
|
-
|
|
56888
|
-
|
|
56889
|
-
code: "DAEMON_UPDATE_REQUIRED",
|
|
56890
|
-
required: true,
|
|
56891
|
-
latest: this.pendingMandatoryUpdate.targetVersion,
|
|
56892
|
-
reason: this.pendingMandatoryUpdate.reason,
|
|
56893
|
-
interactionId
|
|
56894
|
-
});
|
|
57167
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(cmd, interactionId);
|
|
57168
|
+
if (mandatoryUpdateBlock) {
|
|
57169
|
+
this.sendResult(msg, false, mandatoryUpdateBlock);
|
|
56895
57170
|
return;
|
|
56896
57171
|
}
|
|
56897
57172
|
if (source === "api" && !loadConfig().allowServerApiProxy) {
|
|
@@ -56936,6 +57211,10 @@ ${err?.stack || ""}`);
|
|
|
56936
57211
|
const interactionId = String(normalizedData._interactionId);
|
|
56937
57212
|
const cmdStart = Date.now();
|
|
56938
57213
|
try {
|
|
57214
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(cmdType, interactionId);
|
|
57215
|
+
if (mandatoryUpdateBlock) {
|
|
57216
|
+
return { success: false, ...mandatoryUpdateBlock };
|
|
57217
|
+
}
|
|
56939
57218
|
switch (cmdType) {
|
|
56940
57219
|
case "get_runtime_snapshot": {
|
|
56941
57220
|
const sessionId = typeof normalizedData.sessionId === "string" ? normalizedData.sessionId : "";
|
|
@@ -57114,8 +57393,22 @@ ${err?.stack || ""}`);
|
|
|
57114
57393
|
}));
|
|
57115
57394
|
return;
|
|
57116
57395
|
}
|
|
57396
|
+
const normalizedArgs = this.ensureInteractionContext(args);
|
|
57397
|
+
const interactionId = String(normalizedArgs._interactionId);
|
|
57398
|
+
const mandatoryUpdateBlock = this.getMandatoryUpdateBlockPayload(command, interactionId);
|
|
57399
|
+
if (mandatoryUpdateBlock) {
|
|
57400
|
+
ws.send(JSON.stringify({
|
|
57401
|
+
type: "ext:command_result",
|
|
57402
|
+
payload: {
|
|
57403
|
+
requestId,
|
|
57404
|
+
success: false,
|
|
57405
|
+
...mandatoryUpdateBlock
|
|
57406
|
+
}
|
|
57407
|
+
}));
|
|
57408
|
+
return;
|
|
57409
|
+
}
|
|
57117
57410
|
try {
|
|
57118
|
-
const result = await this.components.router.execute(command,
|
|
57411
|
+
const result = await this.components.router.execute(command, normalizedArgs, "ipc");
|
|
57119
57412
|
ws.send(JSON.stringify({
|
|
57120
57413
|
type: "ext:command_result",
|
|
57121
57414
|
payload: {
|
|
@@ -85940,12 +86233,12 @@ function splitStringBySpace(str) {
|
|
|
85940
86233
|
}
|
|
85941
86234
|
return pieces;
|
|
85942
86235
|
}
|
|
85943
|
-
var import_chardet,
|
|
86236
|
+
var import_chardet, import_child_process14, import_fs7, import_node_path2, import_node_os4, import_node_crypto, import_iconv_lite, ExternalEditor;
|
|
85944
86237
|
var init_esm2 = __esm({
|
|
85945
86238
|
"../../node_modules/@inquirer/external-editor/dist/esm/index.js"() {
|
|
85946
86239
|
"use strict";
|
|
85947
86240
|
import_chardet = __toESM(require_lib2(), 1);
|
|
85948
|
-
|
|
86241
|
+
import_child_process14 = require("child_process");
|
|
85949
86242
|
import_fs7 = require("fs");
|
|
85950
86243
|
import_node_path2 = __toESM(require("path"), 1);
|
|
85951
86244
|
import_node_os4 = __toESM(require("os"), 1);
|
|
@@ -86052,7 +86345,7 @@ var init_esm2 = __esm({
|
|
|
86052
86345
|
}
|
|
86053
86346
|
launchEditor() {
|
|
86054
86347
|
try {
|
|
86055
|
-
const editorProcess = (0,
|
|
86348
|
+
const editorProcess = (0, import_child_process14.spawnSync)(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: "inherit" });
|
|
86056
86349
|
this.lastExitStatus = editorProcess.status ?? 0;
|
|
86057
86350
|
} catch (launchError) {
|
|
86058
86351
|
throw new LaunchEditorError(launchError);
|
|
@@ -86060,7 +86353,7 @@ var init_esm2 = __esm({
|
|
|
86060
86353
|
}
|
|
86061
86354
|
launchEditorAsync(callback) {
|
|
86062
86355
|
try {
|
|
86063
|
-
const editorProcess = (0,
|
|
86356
|
+
const editorProcess = (0, import_child_process14.spawn)(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: "inherit" });
|
|
86064
86357
|
editorProcess.on("exit", (code) => {
|
|
86065
86358
|
this.lastExitStatus = code;
|
|
86066
86359
|
setImmediate(callback);
|
|
@@ -88338,9 +88631,9 @@ async function runWizard(options = {}) {
|
|
|
88338
88631
|
}
|
|
88339
88632
|
async function checkForUpdate() {
|
|
88340
88633
|
try {
|
|
88341
|
-
const { execFileSync:
|
|
88634
|
+
const { execFileSync: execFileSync6 } = await import("child_process");
|
|
88342
88635
|
const currentVersion = resolvePackageVersion();
|
|
88343
|
-
const latestVersion = readLatestPublishedCliVersion(
|
|
88636
|
+
const latestVersion = readLatestPublishedCliVersion(execFileSync6);
|
|
88344
88637
|
if (!latestVersion) return;
|
|
88345
88638
|
if (!currentVersion || !latestVersion || currentVersion === latestVersion) return;
|
|
88346
88639
|
console.log(source_default2.yellow(` Update available: ${currentVersion} \u2192 ${latestVersion}`));
|
|
@@ -88357,7 +88650,7 @@ async function checkForUpdate() {
|
|
|
88357
88650
|
const spinner = (await Promise.resolve().then(() => (init_ora(), ora_exports))).default("Updating adhdev CLI...").start();
|
|
88358
88651
|
try {
|
|
88359
88652
|
const installCommand = buildPinnedGlobalInstallCommand({ packageName: "adhdev", targetVersion: "latest" });
|
|
88360
|
-
|
|
88653
|
+
execFileSync6(installCommand.command, installCommand.args, {
|
|
88361
88654
|
encoding: "utf-8",
|
|
88362
88655
|
timeout: 6e4,
|
|
88363
88656
|
stdio: ["pipe", "pipe", "pipe"]
|