opendevbrowser 0.0.24 → 0.0.26
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/README.md +1 -1
- package/dist/browser/fingerprint/canary.d.ts.map +1 -1
- package/dist/{chunk-K2TEHJCV.js → chunk-AVQL6WAS.js} +2856 -694
- package/dist/chunk-AVQL6WAS.js.map +1 -0
- package/dist/{chunk-5I6TZRVS.js → chunk-GTTYIAI7.js} +1053 -474
- package/dist/chunk-GTTYIAI7.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +25 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/inspiredesign.d.ts.map +1 -1
- package/dist/cli/commands/serve.d.ts +10 -13
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/daemon-client.d.ts +13 -0
- package/dist/cli/daemon-client.d.ts.map +1 -1
- package/dist/cli/daemon-commands.d.ts.map +1 -1
- package/dist/cli/daemon-status-policy.d.ts +6 -0
- package/dist/cli/daemon-status-policy.d.ts.map +1 -0
- package/dist/cli/daemon-status.d.ts +1 -0
- package/dist/cli/daemon-status.d.ts.map +1 -1
- package/dist/cli/daemon.d.ts +12 -2
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/index.js +188 -108
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/remote-manager.d.ts +8 -6
- package/dist/cli/remote-manager.d.ts.map +1 -1
- package/dist/cli/utils/http.d.ts.map +1 -1
- package/dist/daemon-fingerprint.json +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +147 -46
- package/dist/index.js.map +1 -1
- package/dist/inspiredesign/brief-expansion.d.ts +41 -0
- package/dist/inspiredesign/brief-expansion.d.ts.map +1 -0
- package/dist/inspiredesign/handoff.d.ts +3 -1
- package/dist/inspiredesign/handoff.d.ts.map +1 -1
- package/dist/opendevbrowser.d.ts.map +1 -1
- package/dist/opendevbrowser.js +147 -46
- package/dist/opendevbrowser.js.map +1 -1
- package/dist/providers/inspiredesign-capture-mode.d.ts +3 -0
- package/dist/providers/inspiredesign-capture-mode.d.ts.map +1 -0
- package/dist/providers/inspiredesign-capture.d.ts +8 -1
- package/dist/providers/inspiredesign-capture.d.ts.map +1 -1
- package/dist/providers/inspiredesign-contract.d.ts +30 -0
- package/dist/providers/inspiredesign-contract.d.ts.map +1 -1
- package/dist/providers/renderer.d.ts +2 -1
- package/dist/providers/renderer.d.ts.map +1 -1
- package/dist/providers/workflows.d.ts +2 -0
- package/dist/providers/workflows.d.ts.map +1 -1
- package/dist/{providers-6YVHKTOJ.js → providers-T2FQJCF6.js} +2 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/inspiredesign_run.d.ts.map +1 -1
- package/dist/tools/status.d.ts.map +1 -1
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
- package/skills/opendevbrowser-best-practices/SKILL.md +3 -2
- package/skills/opendevbrowser-design-agent/SKILL.md +1 -0
- package/skills/opendevbrowser-design-agent/assets/templates/inspiredesign-advanced-brief.v1.json +1370 -0
- package/skills/opendevbrowser-design-agent/scripts/validate-skill-assets.sh +2 -0
- package/dist/chunk-5I6TZRVS.js.map +0 -1
- package/dist/chunk-K2TEHJCV.js.map +0 -1
- /package/dist/{providers-6YVHKTOJ.js.map → providers-T2FQJCF6.js.map} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CLI_COMMANDS,
|
|
4
4
|
CLI_COMMAND_HELP_DETAILS,
|
|
5
|
+
DEFAULT_CLICK_TRANSPORT_TIMEOUT_MS,
|
|
6
|
+
DEFAULT_DAEMON_STATUS_FETCH_OPTIONS,
|
|
7
|
+
DEFAULT_DIALOG_TRANSPORT_TIMEOUT_MS,
|
|
8
|
+
DEFAULT_REVIEW_TRANSPORT_TIMEOUT_MS,
|
|
9
|
+
DEFAULT_SCREENSHOT_TRANSPORT_TIMEOUT_MS,
|
|
10
|
+
DEFAULT_SNAPSHOT_TRANSPORT_TIMEOUT_MS,
|
|
11
|
+
DEFAULT_TARGET_CREATION_TRANSPORT_TIMEOUT_MS,
|
|
12
|
+
DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS,
|
|
5
13
|
DaemonClient,
|
|
6
14
|
EXIT_DISCONNECTED,
|
|
7
15
|
EXIT_EXECUTION,
|
|
@@ -12,6 +20,8 @@ import {
|
|
|
12
20
|
VALID_FLAGS,
|
|
13
21
|
buildAnnotateResult,
|
|
14
22
|
callDaemon,
|
|
23
|
+
createDaemonStopHeaders,
|
|
24
|
+
createDisconnectedError,
|
|
15
25
|
createOpenDevBrowserCore,
|
|
16
26
|
createUsageError,
|
|
17
27
|
extractExtension,
|
|
@@ -21,9 +31,9 @@ import {
|
|
|
21
31
|
formatErrorPayload,
|
|
22
32
|
generateSecureToken,
|
|
23
33
|
getChromeUserDataRoots,
|
|
24
|
-
getCurrentDaemonFingerprint,
|
|
25
34
|
getExtensionPath,
|
|
26
35
|
getProfileDirs,
|
|
36
|
+
isCurrentDaemonFingerprint,
|
|
27
37
|
loadGlobalConfig,
|
|
28
38
|
onboarding_metadata_default,
|
|
29
39
|
readDaemonMetadata,
|
|
@@ -31,7 +41,7 @@ import {
|
|
|
31
41
|
resolveExitCode,
|
|
32
42
|
startDaemon,
|
|
33
43
|
toCliError
|
|
34
|
-
} from "../chunk-
|
|
44
|
+
} from "../chunk-GTTYIAI7.js";
|
|
35
45
|
import "../chunk-STGGGVYT.js";
|
|
36
46
|
import {
|
|
37
47
|
createNoOpSkillRemovalResult,
|
|
@@ -60,10 +70,11 @@ import {
|
|
|
60
70
|
INSPIREDESIGN_HANDOFF_GUIDANCE,
|
|
61
71
|
cleanupExpiredArtifacts,
|
|
62
72
|
isChallengeAutomationMode,
|
|
73
|
+
resolveInspiredesignCaptureMode,
|
|
63
74
|
setDefaultLogSink,
|
|
64
75
|
stderrSink,
|
|
65
76
|
summarizePrimaryProviderIssue
|
|
66
|
-
} from "../chunk-
|
|
77
|
+
} from "../chunk-AVQL6WAS.js";
|
|
67
78
|
import "../chunk-FUSXMW3G.js";
|
|
68
79
|
|
|
69
80
|
// src/cli/args.ts
|
|
@@ -421,7 +432,7 @@ var HELP_FLAG_GROUPS = [
|
|
|
421
432
|
{ flag: "--region", description: "Region or country hint for provider selection. Treat it as advisory unless output metadata reports `region_authoritative=true`." },
|
|
422
433
|
{ flag: "--sort", description: "Sort mode for shopping results." },
|
|
423
434
|
{ flag: "--brief", description: "Inspiredesign brief describing the target design direction." },
|
|
424
|
-
{ flag: "--capture-mode", description: "Inspiredesign capture mode: off
|
|
435
|
+
{ flag: "--capture-mode", description: "Inspiredesign capture mode: off or deep. Any --url forces deep." },
|
|
425
436
|
{ flag: "--include-prototype-guidance", description: "Include inspiredesign prototype guidance in workflow output." },
|
|
426
437
|
{ flag: "--product-url", description: "Target product URL for product-video workflows." },
|
|
427
438
|
{ flag: "--product-name", description: "Product name override for product-video workflows." },
|
|
@@ -505,10 +516,11 @@ var HELP_ONBOARDING_ENTRIES = [
|
|
|
505
516
|
},
|
|
506
517
|
{
|
|
507
518
|
label: "inspiredesign_followthrough",
|
|
508
|
-
description: "After inspiredesign finishes, continue in Canvas with the emitted request template and load the canvas-contract design-agent lane before patching.",
|
|
519
|
+
description: "After inspiredesign finishes, read advanced-brief.md first, then continue in Canvas with the emitted request template and load the canvas-contract design-agent lane before patching.",
|
|
509
520
|
details: [
|
|
510
521
|
{ label: "quick:", value: INSPIREDESIGN_HANDOFF_COMMANDS.loadBestPractices },
|
|
511
522
|
{ label: "design:", value: INSPIREDESIGN_HANDOFF_COMMANDS.loadDesignAgent },
|
|
523
|
+
{ label: "brief:", value: INSPIREDESIGN_HANDOFF_GUIDANCE.reviewAdvancedBrief },
|
|
512
524
|
{ label: "prep:", value: INSPIREDESIGN_HANDOFF_GUIDANCE.prepareCanvasPlanRequest },
|
|
513
525
|
{ label: "run:", value: INSPIREDESIGN_HANDOFF_COMMANDS.continueInCanvas }
|
|
514
526
|
]
|
|
@@ -1517,7 +1529,15 @@ async function runNativeCommand(args) {
|
|
|
1517
1529
|
// src/cli/commands/serve.ts
|
|
1518
1530
|
var daemonHandle = null;
|
|
1519
1531
|
var PS_MAX_BUFFER = 8 * 1024 * 1024;
|
|
1532
|
+
var DAEMON_SHUTDOWN_POLL_ATTEMPTS = 10;
|
|
1533
|
+
var DAEMON_SHUTDOWN_POLL_DELAY_MS = 100;
|
|
1534
|
+
var DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS = 250;
|
|
1535
|
+
var DAEMON_STOP_TIMEOUT_MS = 1e3;
|
|
1536
|
+
var MIN_PORT = 1;
|
|
1537
|
+
var MAX_PORT = 65535;
|
|
1520
1538
|
var SERVE_COMMAND_PATTERN = /(?:^|\s)(?:\S*[\\/])?(?:opendevbrowser|dist[\\/]+cli[\\/]+index\.js)(?=\s|$).*?\bserve\b/;
|
|
1539
|
+
var SERVE_PORT_SPLIT_PATTERN = /(?:^|\s)--port\s+(\d+)(?=\s|$)/;
|
|
1540
|
+
var SERVE_PORT_EQUALS_PATTERN = /(?:^|\s)--port=(\d+)(?=\s|$)/;
|
|
1521
1541
|
var SERVE_STOP_PATTERN = /(?:^|\s)--stop(?:\s|$)/;
|
|
1522
1542
|
var CURRENT_UID = typeof process.getuid === "function" ? process.getuid() : null;
|
|
1523
1543
|
var CURRENT_EXECUTABLE = process.execPath;
|
|
@@ -1536,29 +1556,6 @@ async function resolveExistingDaemon(port, tokens) {
|
|
|
1536
1556
|
function isPositivePid(value) {
|
|
1537
1557
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
1538
1558
|
}
|
|
1539
|
-
function rememberStalePid(staleDaemonPids, pid) {
|
|
1540
|
-
if (isPositivePid(pid)) {
|
|
1541
|
-
staleDaemonPids.add(pid);
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
async function stopDaemonOnPort(port, token) {
|
|
1545
|
-
try {
|
|
1546
|
-
const response = await fetchWithTimeout(`http://127.0.0.1:${port}/stop`, {
|
|
1547
|
-
method: "POST",
|
|
1548
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
1549
|
-
});
|
|
1550
|
-
return response.ok;
|
|
1551
|
-
} catch {
|
|
1552
|
-
return false;
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
async function stopStaleDaemon(port, daemon, staleDaemonPids) {
|
|
1556
|
-
rememberStalePid(staleDaemonPids, daemon.status.pid);
|
|
1557
|
-
const stopped = await stopDaemonOnPort(port, daemon.token);
|
|
1558
|
-
if (!stopped && isPositivePid(daemon.status.pid)) {
|
|
1559
|
-
terminateProcess(daemon.status.pid);
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
1559
|
function parseServeArgs(rawArgs) {
|
|
1563
1560
|
const parsed = { stop: false };
|
|
1564
1561
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
@@ -1572,7 +1569,7 @@ function parseServeArgs(rawArgs) {
|
|
|
1572
1569
|
if (!value) {
|
|
1573
1570
|
throw createUsageError("Missing value for --port");
|
|
1574
1571
|
}
|
|
1575
|
-
parsed.port = parseNumberFlag(value, "--port", { min:
|
|
1572
|
+
parsed.port = parseNumberFlag(value, "--port", { min: MIN_PORT, max: MAX_PORT });
|
|
1576
1573
|
i += 1;
|
|
1577
1574
|
continue;
|
|
1578
1575
|
}
|
|
@@ -1581,7 +1578,7 @@ function parseServeArgs(rawArgs) {
|
|
|
1581
1578
|
if (!value) {
|
|
1582
1579
|
throw createUsageError("Missing value for --port");
|
|
1583
1580
|
}
|
|
1584
|
-
parsed.port = parseNumberFlag(value, "--port", { min:
|
|
1581
|
+
parsed.port = parseNumberFlag(value, "--port", { min: MIN_PORT, max: MAX_PORT });
|
|
1585
1582
|
continue;
|
|
1586
1583
|
}
|
|
1587
1584
|
if (arg === "--token") {
|
|
@@ -1629,6 +1626,14 @@ function parseServeProcessSnapshot(line) {
|
|
|
1629
1626
|
command
|
|
1630
1627
|
};
|
|
1631
1628
|
}
|
|
1629
|
+
function parseServeCommandPort(command) {
|
|
1630
|
+
const rawPort = command.match(SERVE_PORT_EQUALS_PATTERN)?.[1] ?? command.match(SERVE_PORT_SPLIT_PATTERN)?.[1];
|
|
1631
|
+
if (!rawPort) {
|
|
1632
|
+
return null;
|
|
1633
|
+
}
|
|
1634
|
+
const port = Number.parseInt(rawPort, 10);
|
|
1635
|
+
return Number.isInteger(port) && port >= MIN_PORT && port <= MAX_PORT ? port : null;
|
|
1636
|
+
}
|
|
1632
1637
|
function listServeProcessSnapshots() {
|
|
1633
1638
|
const result = spawnSync("ps", ["-axww", "-o", "pid=,uid=,command="], {
|
|
1634
1639
|
encoding: "utf-8",
|
|
@@ -1651,6 +1656,9 @@ function isCurrentExecutableServeProcess(snapshot) {
|
|
|
1651
1656
|
}
|
|
1652
1657
|
return !SERVE_STOP_PATTERN.test(snapshot.command);
|
|
1653
1658
|
}
|
|
1659
|
+
function isRequestedPortServeProcess(snapshot, requestedPort) {
|
|
1660
|
+
return isCurrentExecutableServeProcess(snapshot) && parseServeCommandPort(snapshot.command) === requestedPort;
|
|
1661
|
+
}
|
|
1654
1662
|
function terminateProcess(pid) {
|
|
1655
1663
|
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid || pid === process.ppid) {
|
|
1656
1664
|
return false;
|
|
@@ -1666,9 +1674,9 @@ function terminateProcess(pid) {
|
|
|
1666
1674
|
}
|
|
1667
1675
|
return true;
|
|
1668
1676
|
}
|
|
1669
|
-
function cleanupCompetingServeProcesses(keepPid) {
|
|
1677
|
+
function cleanupCompetingServeProcesses(requestedPort, keepPid) {
|
|
1670
1678
|
const candidates = listServeProcessSnapshots().filter((snapshot) => {
|
|
1671
|
-
if (!
|
|
1679
|
+
if (!isRequestedPortServeProcess(snapshot, requestedPort)) {
|
|
1672
1680
|
return false;
|
|
1673
1681
|
}
|
|
1674
1682
|
if (snapshot.pid === process.pid || snapshot.pid === process.ppid) {
|
|
@@ -1690,6 +1698,85 @@ function cleanupCompetingServeProcesses(keepPid) {
|
|
|
1690
1698
|
}
|
|
1691
1699
|
return clearedPids;
|
|
1692
1700
|
}
|
|
1701
|
+
function terminateServeProcessByPid(pid) {
|
|
1702
|
+
if (!isPositivePid(pid)) {
|
|
1703
|
+
return false;
|
|
1704
|
+
}
|
|
1705
|
+
const snapshot = listServeProcessSnapshots().find((item) => item.pid === pid);
|
|
1706
|
+
return snapshot ? isCurrentExecutableServeProcess(snapshot) && terminateProcess(pid) : false;
|
|
1707
|
+
}
|
|
1708
|
+
function buildStaleStopMessage(metadata) {
|
|
1709
|
+
const pid = isPositivePid(metadata.pid) ? ` pid=${metadata.pid}` : "";
|
|
1710
|
+
return `Daemon rejected stale stop request for 127.0.0.1:${metadata.port}${pid}. Run \`opendevbrowser status --daemon\` to inspect the active daemon, then restart from the current install if needed.`;
|
|
1711
|
+
}
|
|
1712
|
+
function buildProtectedMismatchMessage(port, status) {
|
|
1713
|
+
return `Daemon on 127.0.0.1:${port} pid=${status.pid} is protected by a different opendevbrowser build. Run \`opendevbrowser status --daemon\` to inspect it, then restart from the current install.`;
|
|
1714
|
+
}
|
|
1715
|
+
async function waitForDaemonShutdown(port, token) {
|
|
1716
|
+
for (let attempt = 0; attempt < DAEMON_SHUTDOWN_POLL_ATTEMPTS; attempt += 1) {
|
|
1717
|
+
const status = await fetchDaemonStatus(port, token, { timeoutMs: DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS });
|
|
1718
|
+
if (!status?.ok) {
|
|
1719
|
+
return true;
|
|
1720
|
+
}
|
|
1721
|
+
await new Promise((resolve5) => setTimeout(resolve5, DAEMON_SHUTDOWN_POLL_DELAY_MS));
|
|
1722
|
+
}
|
|
1723
|
+
return false;
|
|
1724
|
+
}
|
|
1725
|
+
async function stopMismatchedDaemon(port, daemon) {
|
|
1726
|
+
let response;
|
|
1727
|
+
try {
|
|
1728
|
+
response = await fetchWithTimeout(`http://127.0.0.1:${port}/stop`, {
|
|
1729
|
+
method: "POST",
|
|
1730
|
+
headers: createDaemonStopHeaders(daemon.token, "serve.upgrade")
|
|
1731
|
+
}, DAEMON_STOP_TIMEOUT_MS);
|
|
1732
|
+
} catch (error) {
|
|
1733
|
+
const status = await fetchDaemonStatus(port, daemon.token, {
|
|
1734
|
+
timeoutMs: DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS
|
|
1735
|
+
});
|
|
1736
|
+
if (!status?.ok) {
|
|
1737
|
+
return null;
|
|
1738
|
+
}
|
|
1739
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1740
|
+
return `Failed to stop mismatched daemon on 127.0.0.1:${port}: ${message}.`;
|
|
1741
|
+
}
|
|
1742
|
+
if (response.status === 409) {
|
|
1743
|
+
return buildProtectedMismatchMessage(port, daemon.status);
|
|
1744
|
+
}
|
|
1745
|
+
if (!response.ok) {
|
|
1746
|
+
return `Failed to stop mismatched daemon on 127.0.0.1:${port}: stop returned ${response.status}.`;
|
|
1747
|
+
}
|
|
1748
|
+
if (await waitForDaemonShutdown(port, daemon.token)) {
|
|
1749
|
+
return null;
|
|
1750
|
+
}
|
|
1751
|
+
if (terminateServeProcessByPid(daemon.status.pid)) {
|
|
1752
|
+
return null;
|
|
1753
|
+
}
|
|
1754
|
+
return `Timed out waiting for mismatched daemon on 127.0.0.1:${port} to stop.`;
|
|
1755
|
+
}
|
|
1756
|
+
async function prepareExistingDaemon(port, daemon) {
|
|
1757
|
+
if (isCurrentDaemonFingerprint(daemon.status.fingerprint)) {
|
|
1758
|
+
return null;
|
|
1759
|
+
}
|
|
1760
|
+
return await stopMismatchedDaemon(port, daemon);
|
|
1761
|
+
}
|
|
1762
|
+
function buildAlreadyRunningResult(port, status, fallbackRelayPort, clearedCount) {
|
|
1763
|
+
const relayPort = status.relay.port ?? fallbackRelayPort;
|
|
1764
|
+
const staleNote = clearedCount > 0 ? `
|
|
1765
|
+
Cleared ${clearedCount} stale daemon process${clearedCount === 1 ? "" : "es"}.` : "";
|
|
1766
|
+
return {
|
|
1767
|
+
success: true,
|
|
1768
|
+
message: `Daemon already running on 127.0.0.1:${port} (pid=${status.pid}, relay ${relayPort}).${staleNote}`,
|
|
1769
|
+
data: {
|
|
1770
|
+
port,
|
|
1771
|
+
pid: status.pid,
|
|
1772
|
+
relayPort,
|
|
1773
|
+
alreadyRunning: true,
|
|
1774
|
+
staleDaemonsCleared: clearedCount,
|
|
1775
|
+
relay: status.relay
|
|
1776
|
+
},
|
|
1777
|
+
exitCode: null
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1693
1780
|
async function runServe(args) {
|
|
1694
1781
|
const serveArgs = parseServeArgs(args.rawArgs);
|
|
1695
1782
|
if (serveArgs.stop) {
|
|
@@ -1705,8 +1792,11 @@ async function runServe(args) {
|
|
|
1705
1792
|
try {
|
|
1706
1793
|
const response = await fetchWithTimeout(`http://127.0.0.1:${metadata2.port}/stop`, {
|
|
1707
1794
|
method: "POST",
|
|
1708
|
-
headers:
|
|
1795
|
+
headers: createDaemonStopHeaders(metadata2.token, "serve.stop")
|
|
1709
1796
|
});
|
|
1797
|
+
if (response.status === 409) {
|
|
1798
|
+
return { success: false, message: buildStaleStopMessage(metadata2), exitCode: EXIT_EXECUTION };
|
|
1799
|
+
}
|
|
1710
1800
|
if (!response.ok) {
|
|
1711
1801
|
throw new Error(`Stop failed (${response.status})`);
|
|
1712
1802
|
}
|
|
@@ -1721,34 +1811,23 @@ async function runServe(args) {
|
|
|
1721
1811
|
const metadata = readDaemonMetadata();
|
|
1722
1812
|
const metadataToken = metadata?.port === requestedPort ? metadata.token : void 0;
|
|
1723
1813
|
const tokenCandidates = resolveTokenCandidates(serveArgs.token, metadataToken, config.daemonToken);
|
|
1724
|
-
const currentFingerprint = getCurrentDaemonFingerprint();
|
|
1725
1814
|
const existingDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
|
|
1726
|
-
const staleDaemonPids = new Set(
|
|
1815
|
+
const staleDaemonPids = /* @__PURE__ */ new Set();
|
|
1727
1816
|
const staleCleared = () => staleDaemonPids.size;
|
|
1728
|
-
let replacedStaleFingerprint = false;
|
|
1729
1817
|
if (existingDaemon) {
|
|
1730
|
-
const
|
|
1731
|
-
if (
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
data: {
|
|
1740
|
-
port: requestedPort,
|
|
1741
|
-
pid: existingDaemon.status.pid,
|
|
1742
|
-
relayPort,
|
|
1743
|
-
alreadyRunning: true,
|
|
1744
|
-
staleDaemonsCleared: clearedCount2,
|
|
1745
|
-
relay: existingDaemon.status.relay
|
|
1746
|
-
},
|
|
1747
|
-
exitCode: null
|
|
1748
|
-
};
|
|
1818
|
+
const mismatchMessage = await prepareExistingDaemon(requestedPort, existingDaemon);
|
|
1819
|
+
if (mismatchMessage) {
|
|
1820
|
+
return { success: false, message: mismatchMessage, exitCode: EXIT_EXECUTION };
|
|
1821
|
+
}
|
|
1822
|
+
if (isCurrentDaemonFingerprint(existingDaemon.status.fingerprint)) {
|
|
1823
|
+
for (const pid of cleanupCompetingServeProcesses(requestedPort, existingDaemon.status.pid)) {
|
|
1824
|
+
staleDaemonPids.add(pid);
|
|
1825
|
+
}
|
|
1826
|
+
return buildAlreadyRunningResult(requestedPort, existingDaemon.status, config.relayPort, staleCleared());
|
|
1749
1827
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1828
|
+
}
|
|
1829
|
+
for (const pid of cleanupCompetingServeProcesses(requestedPort)) {
|
|
1830
|
+
staleDaemonPids.add(pid);
|
|
1752
1831
|
}
|
|
1753
1832
|
let nativeStatus = getNativeStatusSnapshot();
|
|
1754
1833
|
let nativeMessage = null;
|
|
@@ -1791,35 +1870,17 @@ Cleared ${clearedCount2} stale daemon process${clearedCount2 === 1 ? "" : "es"}.
|
|
|
1791
1870
|
}
|
|
1792
1871
|
const runningDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
|
|
1793
1872
|
if (runningDaemon) {
|
|
1794
|
-
const
|
|
1795
|
-
if (
|
|
1796
|
-
|
|
1797
|
-
const clearedCount2 = staleCleared();
|
|
1798
|
-
const staleNote2 = clearedCount2 > 0 ? `
|
|
1799
|
-
Cleared ${clearedCount2} stale daemon process${clearedCount2 === 1 ? "" : "es"}.` : "";
|
|
1800
|
-
return {
|
|
1801
|
-
success: true,
|
|
1802
|
-
message: `Daemon already running on 127.0.0.1:${requestedPort} (pid=${runningDaemon.status.pid}, relay ${relayPort}).${staleNote2}`,
|
|
1803
|
-
data: {
|
|
1804
|
-
port: requestedPort,
|
|
1805
|
-
pid: runningDaemon.status.pid,
|
|
1806
|
-
relayPort,
|
|
1807
|
-
alreadyRunning: true,
|
|
1808
|
-
staleDaemonsCleared: clearedCount2,
|
|
1809
|
-
relay: runningDaemon.status.relay
|
|
1810
|
-
},
|
|
1811
|
-
exitCode: null
|
|
1812
|
-
};
|
|
1873
|
+
const mismatchMessage = await prepareExistingDaemon(requestedPort, runningDaemon);
|
|
1874
|
+
if (mismatchMessage) {
|
|
1875
|
+
return { success: false, message: mismatchMessage, exitCode: EXIT_EXECUTION };
|
|
1813
1876
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
if (attempt === 0) {
|
|
1817
|
-
continue;
|
|
1877
|
+
if (isCurrentDaemonFingerprint(runningDaemon.status.fingerprint)) {
|
|
1878
|
+
return buildAlreadyRunningResult(requestedPort, runningDaemon.status, config.relayPort, staleCleared());
|
|
1818
1879
|
}
|
|
1819
1880
|
}
|
|
1820
1881
|
if (attempt === 0) {
|
|
1821
1882
|
let clearedNewPid = false;
|
|
1822
|
-
for (const pid of cleanupCompetingServeProcesses()) {
|
|
1883
|
+
for (const pid of cleanupCompetingServeProcesses(requestedPort)) {
|
|
1823
1884
|
const previousSize = staleDaemonPids.size;
|
|
1824
1885
|
staleDaemonPids.add(pid);
|
|
1825
1886
|
if (staleDaemonPids.size > previousSize) {
|
|
@@ -1854,9 +1915,8 @@ Cleared ${clearedCount2} stale daemon process${clearedCount2 === 1 ? "" : "es"}.
|
|
|
1854
1915
|
const clearedCount = staleCleared();
|
|
1855
1916
|
const staleNote = clearedCount > 0 ? `
|
|
1856
1917
|
Cleared ${clearedCount} stale daemon process${clearedCount === 1 ? "" : "es"}.` : "";
|
|
1857
|
-
const fingerprintNote = replacedStaleFingerprint ? "\nReplaced stale daemon fingerprint." : "";
|
|
1858
1918
|
const message = nativeMessage ? `${baseMessage}
|
|
1859
|
-
${nativeMessage}${
|
|
1919
|
+
${nativeMessage}${staleNote}` : `${baseMessage}${staleNote}`;
|
|
1860
1920
|
return {
|
|
1861
1921
|
success: true,
|
|
1862
1922
|
message,
|
|
@@ -2424,17 +2484,40 @@ var parseDaemonArgs = (rawArgs) => {
|
|
|
2424
2484
|
var stopDaemonIfRunning = async () => {
|
|
2425
2485
|
const metadata = readDaemonMetadata();
|
|
2426
2486
|
if (!metadata) {
|
|
2427
|
-
return
|
|
2487
|
+
return { outcome: "not_running" };
|
|
2428
2488
|
}
|
|
2429
2489
|
try {
|
|
2430
2490
|
const response = await fetchWithTimeout(`http://127.0.0.1:${metadata.port}/stop`, {
|
|
2431
2491
|
method: "POST",
|
|
2432
|
-
headers:
|
|
2492
|
+
headers: createDaemonStopHeaders(metadata.token, "daemon.uninstall")
|
|
2433
2493
|
});
|
|
2434
|
-
|
|
2435
|
-
|
|
2494
|
+
if (response.status === 409) {
|
|
2495
|
+
return { outcome: "fingerprint_rejected", pid: metadata.pid, port: metadata.port };
|
|
2496
|
+
}
|
|
2497
|
+
return response.ok ? { outcome: "stopped", pid: metadata.pid, port: metadata.port } : { outcome: "failed", pid: metadata.pid, port: metadata.port, status: response.status };
|
|
2498
|
+
} catch (error) {
|
|
2499
|
+
return {
|
|
2500
|
+
outcome: "failed",
|
|
2501
|
+
pid: metadata.pid,
|
|
2502
|
+
port: metadata.port,
|
|
2503
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
};
|
|
2507
|
+
var buildStopFailureMessage = (stop) => {
|
|
2508
|
+
const target = stop.port ? `127.0.0.1:${stop.port}` : "recorded daemon";
|
|
2509
|
+
const pid = stop.pid ? ` pid=${stop.pid}` : "";
|
|
2510
|
+
if (stop.outcome === "fingerprint_rejected") {
|
|
2511
|
+
return `Daemon autostart removed, but the running daemon at ${target}${pid} rejected the stop request as stale. Run \`opendevbrowser status --daemon\` to inspect it and restart from the current install if needed.`;
|
|
2512
|
+
}
|
|
2513
|
+
const reason = stop.error ?? (stop.status ? `HTTP ${stop.status}` : "unknown error");
|
|
2514
|
+
return `Daemon autostart removed, but stopping ${target}${pid} failed (${reason}).`;
|
|
2515
|
+
};
|
|
2516
|
+
var shouldFailUninstallStop = (stop) => {
|
|
2517
|
+
if (stop.outcome === "stopped" || stop.outcome === "not_running") {
|
|
2436
2518
|
return false;
|
|
2437
2519
|
}
|
|
2520
|
+
return true;
|
|
2438
2521
|
};
|
|
2439
2522
|
var formatReason = (reason) => {
|
|
2440
2523
|
return reason ? reason.replace(/_/g, " ") : "unknown reason";
|
|
@@ -2509,7 +2592,15 @@ async function runDaemonCommand(args) {
|
|
|
2509
2592
|
exitCode: EXIT_EXECUTION
|
|
2510
2593
|
};
|
|
2511
2594
|
}
|
|
2512
|
-
await stopDaemonIfRunning();
|
|
2595
|
+
const stop = await stopDaemonIfRunning();
|
|
2596
|
+
if (shouldFailUninstallStop(stop)) {
|
|
2597
|
+
return {
|
|
2598
|
+
success: false,
|
|
2599
|
+
message: buildStopFailureMessage(stop),
|
|
2600
|
+
data: { ...result, stop },
|
|
2601
|
+
exitCode: EXIT_EXECUTION
|
|
2602
|
+
};
|
|
2603
|
+
}
|
|
2513
2604
|
return {
|
|
2514
2605
|
success: true,
|
|
2515
2606
|
message: `Daemon autostart removed (${result.platform}).`,
|
|
@@ -2517,7 +2608,7 @@ async function runDaemonCommand(args) {
|
|
|
2517
2608
|
};
|
|
2518
2609
|
}
|
|
2519
2610
|
const autostart = getAutostartStatus();
|
|
2520
|
-
const daemonStatus = await fetchDaemonStatusFromMetadata();
|
|
2611
|
+
const daemonStatus = await fetchDaemonStatusFromMetadata(void 0, DEFAULT_DAEMON_STATUS_FETCH_OPTIONS);
|
|
2521
2612
|
const running = Boolean(daemonStatus);
|
|
2522
2613
|
const message = buildStatusMessage(autostart, running);
|
|
2523
2614
|
const data = {
|
|
@@ -3440,15 +3531,6 @@ async function runSessionInspector(args) {
|
|
|
3440
3531
|
};
|
|
3441
3532
|
}
|
|
3442
3533
|
|
|
3443
|
-
// src/cli/transport-timeouts.ts
|
|
3444
|
-
var DEFAULT_CLICK_TRANSPORT_TIMEOUT_MS = 6e4;
|
|
3445
|
-
var DEFAULT_DIALOG_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3446
|
-
var DEFAULT_TARGET_CREATION_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3447
|
-
var DEFAULT_SNAPSHOT_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3448
|
-
var DEFAULT_REVIEW_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3449
|
-
var DEFAULT_SCREENSHOT_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3450
|
-
var DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS = 12e4;
|
|
3451
|
-
|
|
3452
3534
|
// src/cli/commands/challenge-automation-mode.ts
|
|
3453
3535
|
function parseOptionalChallengeAutomationMode(rawArgs) {
|
|
3454
3536
|
const value = parseOptionalStringFlag(rawArgs, "--challenge-automation-mode");
|
|
@@ -3574,11 +3656,6 @@ async function runSessionStatus(args) {
|
|
|
3574
3656
|
}
|
|
3575
3657
|
|
|
3576
3658
|
// src/cli/commands/status.ts
|
|
3577
|
-
var DAEMON_STATUS_READ_OPTIONS = {
|
|
3578
|
-
timeoutMs: 5e3,
|
|
3579
|
-
retryAttempts: 5,
|
|
3580
|
-
retryDelayMs: 250
|
|
3581
|
-
};
|
|
3582
3659
|
var parseStatusArgs2 = (rawArgs) => {
|
|
3583
3660
|
const parsed = { daemon: false };
|
|
3584
3661
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
@@ -3619,21 +3696,23 @@ async function runStatus(args) {
|
|
|
3619
3696
|
exitCode: assessment.exitCode ?? void 0
|
|
3620
3697
|
};
|
|
3621
3698
|
}
|
|
3622
|
-
const daemonStatus = await fetchDaemonStatusFromMetadata(void 0,
|
|
3699
|
+
const daemonStatus = await fetchDaemonStatusFromMetadata(void 0, DEFAULT_DAEMON_STATUS_FETCH_OPTIONS);
|
|
3623
3700
|
if (!daemonStatus) {
|
|
3624
|
-
throw
|
|
3701
|
+
throw createDisconnectedError("Daemon not running. Start with `opendevbrowser serve`.");
|
|
3625
3702
|
}
|
|
3626
3703
|
const nativeStatus = getNativeStatusSnapshot();
|
|
3627
3704
|
const nativeAssessment = assessNativeStatus(nativeStatus);
|
|
3705
|
+
const fingerprintLine = daemonStatus.fingerprintCurrent === false ? "Daemon fingerprint: mismatch with current build" : "Daemon fingerprint: current";
|
|
3628
3706
|
const baseLines = [
|
|
3629
3707
|
`Daemon OK (pid=${daemonStatus.pid})`,
|
|
3708
|
+
fingerprintLine,
|
|
3630
3709
|
`Relay: port=${daemonStatus.relay.port ?? "n/a"} ext=${daemonStatus.relay.extensionConnected ? "on" : "off"} handshake=${daemonStatus.relay.extensionHandshakeComplete ? "on" : "off"} cdp=${daemonStatus.relay.cdpConnected ? "on" : "off"} annotate=${daemonStatus.relay.annotationConnected ? "on" : "off"} ops=${daemonStatus.relay.opsConnected ? "on" : "off"} canvas=${daemonStatus.relay.canvasConnected ? "on" : "off"} pairing=${daemonStatus.relay.pairingRequired ? "on" : "off"} health=${daemonStatus.relay.health?.reason ?? "n/a"}`,
|
|
3631
3710
|
`Native: ${nativeAssessment.summary}`,
|
|
3632
3711
|
daemonStatus.relay.lastHandshakeError ? `Relay last handshake error: ${daemonStatus.relay.lastHandshakeError.code} (${daemonStatus.relay.lastHandshakeError.message})` : "Relay last handshake error: none",
|
|
3633
3712
|
"Legend: ext=extension websocket, handshake=extension handshake, cdp=active /cdp client, annotate=annotation channel, ops=ops clients, canvas=canvas clients, pairing=token required, health=relay status"
|
|
3634
3713
|
];
|
|
3635
3714
|
if (!nativeAssessment.success) {
|
|
3636
|
-
baseLines.splice(
|
|
3715
|
+
baseLines.splice(4, 0, `Native detail: ${nativeAssessment.message}`);
|
|
3637
3716
|
}
|
|
3638
3717
|
const baseMessage = baseLines.join("\n");
|
|
3639
3718
|
const message = daemon || args.outputFormat !== "text" ? baseMessage : [
|
|
@@ -7391,10 +7470,11 @@ async function runInspiredesignCommand(args) {
|
|
|
7391
7470
|
if (!parsed.brief?.trim()) {
|
|
7392
7471
|
throw createUsageError("Missing --brief");
|
|
7393
7472
|
}
|
|
7473
|
+
const captureMode = resolveInspiredesignCaptureMode(parsed.captureMode, parsed.urls);
|
|
7394
7474
|
const data = await callDaemon("inspiredesign.run", {
|
|
7395
7475
|
brief: parsed.brief,
|
|
7396
7476
|
urls: parsed.urls,
|
|
7397
|
-
captureMode
|
|
7477
|
+
captureMode,
|
|
7398
7478
|
includePrototypeGuidance: parsed.includePrototypeGuidance,
|
|
7399
7479
|
mode: parsed.mode ?? "compact",
|
|
7400
7480
|
timeoutMs: parsed.timeoutMs ?? DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS,
|
|
@@ -7414,7 +7494,7 @@ async function runInspiredesignCommand(args) {
|
|
|
7414
7494
|
// package.json
|
|
7415
7495
|
var package_default = {
|
|
7416
7496
|
name: "opendevbrowser",
|
|
7417
|
-
version: "0.0.
|
|
7497
|
+
version: "0.0.26",
|
|
7418
7498
|
description: "Browser automation runtime with snapshot-refs-actions, browser replay screencasts, public read-only desktop observation, and browser-scoped computer-use orchestration",
|
|
7419
7499
|
type: "module",
|
|
7420
7500
|
main: "dist/index.js",
|