@zenalexa/unicli 0.222.3 → 0.223.1
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/AGENTS.md +24 -1
- package/README.md +16 -5
- package/README.zh-CN.md +2 -2
- package/dist/browser/auth-sync.d.ts +32 -0
- package/dist/browser/auth-sync.d.ts.map +1 -0
- package/dist/browser/auth-sync.js +119 -0
- package/dist/browser/auth-sync.js.map +1 -0
- package/dist/browser/bridge.d.ts +2 -0
- package/dist/browser/bridge.d.ts.map +1 -1
- package/dist/browser/bridge.js +4 -3
- package/dist/browser/bridge.js.map +1 -1
- package/dist/browser/cdp-client.d.ts +5 -0
- package/dist/browser/cdp-client.d.ts.map +1 -1
- package/dist/browser/cdp-client.js +18 -3
- package/dist/browser/cdp-client.js.map +1 -1
- package/dist/browser/chrome-policy.d.ts +38 -0
- package/dist/browser/chrome-policy.d.ts.map +1 -0
- package/dist/browser/chrome-policy.js +261 -0
- package/dist/browser/chrome-policy.js.map +1 -0
- package/dist/browser/daemon-client.d.ts +3 -0
- package/dist/browser/daemon-client.d.ts.map +1 -1
- package/dist/browser/daemon-client.js +13 -15
- package/dist/browser/daemon-client.js.map +1 -1
- package/dist/browser/doctor.d.ts +147 -0
- package/dist/browser/doctor.d.ts.map +1 -0
- package/dist/browser/doctor.js +784 -0
- package/dist/browser/doctor.js.map +1 -0
- package/dist/browser/launcher.d.ts +17 -8
- package/dist/browser/launcher.d.ts.map +1 -1
- package/dist/browser/launcher.js +51 -11
- package/dist/browser/launcher.js.map +1 -1
- package/dist/browser/local-profiles.d.ts +55 -0
- package/dist/browser/local-profiles.d.ts.map +1 -0
- package/dist/browser/local-profiles.js +333 -0
- package/dist/browser/local-profiles.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/browser/index.d.ts +2 -2
- package/dist/commands/browser/index.d.ts.map +1 -1
- package/dist/commands/browser/index.js +195 -14
- package/dist/commands/browser/index.js.map +1 -1
- package/dist/commands/compute.d.ts.map +1 -1
- package/dist/commands/compute.js +116 -11
- package/dist/commands/compute.js.map +1 -1
- package/dist/commands/doctor-compute.d.ts +3 -1
- package/dist/commands/doctor-compute.d.ts.map +1 -1
- package/dist/commands/doctor-compute.js +78 -2
- package/dist/commands/doctor-compute.js.map +1 -1
- package/dist/compute/capture-reference.d.ts +40 -0
- package/dist/compute/capture-reference.d.ts.map +1 -0
- package/dist/compute/capture-reference.js +285 -0
- package/dist/compute/capture-reference.js.map +1 -0
- package/dist/compute/capture.d.ts +67 -0
- package/dist/compute/capture.d.ts.map +1 -0
- package/dist/compute/capture.js +247 -0
- package/dist/compute/capture.js.map +1 -0
- package/dist/discovery/aliases.d.ts.map +1 -1
- package/dist/discovery/aliases.js +13 -0
- package/dist/discovery/aliases.js.map +1 -1
- package/dist/discovery/core-catalog.d.ts +37 -0
- package/dist/discovery/core-catalog.d.ts.map +1 -0
- package/dist/discovery/core-catalog.js +352 -0
- package/dist/discovery/core-catalog.js.map +1 -0
- package/dist/discovery/intents.d.ts.map +1 -1
- package/dist/discovery/intents.js +51 -0
- package/dist/discovery/intents.js.map +1 -1
- package/dist/discovery/search.d.ts +10 -6
- package/dist/discovery/search.d.ts.map +1 -1
- package/dist/discovery/search.js +21 -102
- package/dist/discovery/search.js.map +1 -1
- package/dist/engine/executor.d.ts +6 -1
- package/dist/engine/executor.d.ts.map +1 -1
- package/dist/engine/executor.js +2 -0
- package/dist/engine/executor.js.map +1 -1
- package/dist/engine/kernel/stages.d.ts.map +1 -1
- package/dist/engine/kernel/stages.js +4 -0
- package/dist/engine/kernel/stages.js.map +1 -1
- package/dist/engine/steps/browser-helpers.d.ts.map +1 -1
- package/dist/engine/steps/browser-helpers.js +29 -1
- package/dist/engine/steps/browser-helpers.js.map +1 -1
- package/dist/fast-path/handlers/discovery.d.ts.map +1 -1
- package/dist/fast-path/handlers/discovery.js +80 -1
- package/dist/fast-path/handlers/discovery.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/mcp/handler.d.ts.map +1 -1
- package/dist/mcp/handler.js +19 -4
- package/dist/mcp/handler.js.map +1 -1
- package/dist/mcp/profiles/computer-use.d.ts.map +1 -1
- package/dist/mcp/profiles/computer-use.js +106 -4
- package/dist/mcp/profiles/computer-use.js.map +1 -1
- package/docs/mcp/clients/claude-code.md +8 -7
- package/docs/mcp/clients/claude-desktop.md +1 -1
- package/docs/mcp/clients/codex.md +1 -1
- package/docs/mcp/clients/cursor.md +1 -1
- package/docs/mcp/clients/gemini-cli.md +1 -1
- package/docs/operate/compute.md +58 -0
- package/docs/operate/focus-behavior.md +25 -0
- package/package.json +1 -1
- package/server.json +2 -2
- package/skills/unicli/SKILL.md +54 -38
- package/skills/unicli-browser/SKILL.md +56 -10
- package/skills/unicli-claude-code/SKILL.md +1 -1
- package/skills/unicli-hermes/SKILL.md +1 -1
- package/skills/unicli-operate/SKILL.md +1 -1
- package/skills/unicli-smart-search/SKILL.md +7 -5
- package/skills/unicli-usage/SKILL.md +39 -1
- package/src/hub/external-clis.yaml +6 -0
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @owner src/browser/doctor.ts
|
|
3
|
+
* @does Build a machine-readable browser reliability report from live daemon, profile, CDP, layering, repair, and retry state.
|
|
4
|
+
* @needs src/browser local-profiles/launcher/cdp-client/daemon-client/bridge/protocol
|
|
5
|
+
* @feeds src/commands/browser/index.ts, tests/unit/commands/browser.test.ts
|
|
6
|
+
* @breaks Probe failures are returned as diagnostics in the report; raw cookies, auth headers, and endpoint secrets are never emitted.
|
|
7
|
+
*/
|
|
8
|
+
import { detectDefaultProfileDebugBlocks, detectLocalBrowserProfiles, } from "./local-profiles.js";
|
|
9
|
+
import { getCDPPort, isCDPAvailable, launchChrome } from "./launcher.js";
|
|
10
|
+
import { getRemoteEndpoint } from "./cdp-client.js";
|
|
11
|
+
import { BROWSER_DAEMON_COMMAND_MAX_ATTEMPTS, BROWSER_DAEMON_EXTENSION_RETRY_DELAY_MS, BROWSER_DAEMON_NETWORK_RETRY_DELAY_MS, fetchDaemonPortConflict, fetchDaemonStatus, listSessions, } from "./daemon-client.js";
|
|
12
|
+
import { BROWSER_REMOTE_CONNECT_MAX_ATTEMPTS, BROWSER_REMOTE_RETRY_DELAY_MS, } from "./bridge.js";
|
|
13
|
+
import { MAX_EAGER_RECONNECT_ATTEMPTS, WS_RECONNECT_BASE_DELAY, WS_RECONNECT_MAX_DELAY, } from "./protocol.js";
|
|
14
|
+
import { buildChrome136RemoteDebuggingGuidance, detectChromeRemoteDebuggingPolicy, } from "./chrome-policy.js";
|
|
15
|
+
const REQUIRED_BROWSER_CAPABILITIES = [
|
|
16
|
+
"cookie_reuse",
|
|
17
|
+
"background_operation",
|
|
18
|
+
"browser_use",
|
|
19
|
+
"page_layering",
|
|
20
|
+
"direct_connect",
|
|
21
|
+
"stability",
|
|
22
|
+
"reliability",
|
|
23
|
+
"repair",
|
|
24
|
+
"retry",
|
|
25
|
+
];
|
|
26
|
+
export async function runBrowserDoctor(repairAttempt) {
|
|
27
|
+
const profiles = detectLocalBrowserProfiles();
|
|
28
|
+
const defaultProfileDebugBlocks = detectDefaultProfileDebugBlocks();
|
|
29
|
+
const remoteDebuggingPolicy = detectChromeRemoteDebuggingPolicy();
|
|
30
|
+
const chrome136Guidance = buildChrome136RemoteDebuggingGuidance();
|
|
31
|
+
const daemonProbe = await probeDaemon();
|
|
32
|
+
const daemonStatus = daemonProbe.value;
|
|
33
|
+
const conflict = daemonStatus === null
|
|
34
|
+
? await probeDaemonPortConflict()
|
|
35
|
+
: { value: null };
|
|
36
|
+
const sessionsProbe = daemonStatus?.extensionConnected === true
|
|
37
|
+
? await probeSessions()
|
|
38
|
+
: { value: [] };
|
|
39
|
+
const localCdp = await probeLocalCdp();
|
|
40
|
+
const remote = getRemoteEndpoint();
|
|
41
|
+
const backgroundStatus = buildBackgroundStatus(daemonStatus, conflict.value);
|
|
42
|
+
const isAutomationReady = backgroundStatus === "ready" || localCdp.value || remote !== null;
|
|
43
|
+
const cookieReuse = buildCookieReuse(profiles);
|
|
44
|
+
const backgroundOperation = {
|
|
45
|
+
status: backgroundStatus,
|
|
46
|
+
daemon: buildDaemonReport(daemonStatus, conflict.value, daemonProbe.error ?? conflict.error),
|
|
47
|
+
sessions_count: sessionsProbe.value.length,
|
|
48
|
+
...(sessionsProbe.error ? { session_error: sessionsProbe.error } : {}),
|
|
49
|
+
controls: [
|
|
50
|
+
"default windowFocused=false",
|
|
51
|
+
"browser start uses --no-startup-window by default",
|
|
52
|
+
"--background",
|
|
53
|
+
"--focus",
|
|
54
|
+
"--workspace",
|
|
55
|
+
"--isolated",
|
|
56
|
+
"--shared-session",
|
|
57
|
+
"--daemon-port",
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
const browserUse = {
|
|
61
|
+
modes: ["logged-in Chrome", "headless Chrome", "remote CDP cloud browser"],
|
|
62
|
+
layers: [
|
|
63
|
+
{
|
|
64
|
+
name: "runtime-control",
|
|
65
|
+
owner: "src/commands/browser/actions.ts",
|
|
66
|
+
proves: "CLI options route focus, workspace, and background intent before browser work starts.",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "browser-session",
|
|
70
|
+
owner: "src/browser/bridge.ts",
|
|
71
|
+
proves: "Daemon, extension, local CDP, and remote CDP connection paths are explicit.",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "page-state",
|
|
75
|
+
owner: "src/browser/page.ts",
|
|
76
|
+
proves: "DOM, frame, network, screenshot, and CDP operations are page-scoped.",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "evidence-repair",
|
|
80
|
+
owner: "src/engine/browser/evidence.ts",
|
|
81
|
+
proves: "Before/after evidence, movement checks, and repair commands are serialized for agents.",
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
const directConnect = {
|
|
86
|
+
local_cdp: {
|
|
87
|
+
port: getCDPPort(),
|
|
88
|
+
reachable: localCdp.value,
|
|
89
|
+
command: "unicli browser start",
|
|
90
|
+
...(localCdp.error ? { error: localCdp.error } : {}),
|
|
91
|
+
},
|
|
92
|
+
remote_cdp: {
|
|
93
|
+
configured: remote !== null,
|
|
94
|
+
...(remote ? { endpoint: redactEndpoint(remote.endpoint) } : {}),
|
|
95
|
+
header_count: remote ? Object.keys(remote.headers).length : 0,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const chromeRemoteDebugging = {
|
|
99
|
+
chrome_136: chrome136Guidance,
|
|
100
|
+
policy: remoteDebuggingPolicy,
|
|
101
|
+
};
|
|
102
|
+
const stabilityReliability = {
|
|
103
|
+
guards: [
|
|
104
|
+
"non-focusing daemon command default",
|
|
105
|
+
"no-startup-window local Chrome launch",
|
|
106
|
+
"doctor sessions probe does not create placeholder tabs",
|
|
107
|
+
"workspace lease",
|
|
108
|
+
"target lease",
|
|
109
|
+
"domain/path guard",
|
|
110
|
+
"render stability probe",
|
|
111
|
+
"action movement watchdog",
|
|
112
|
+
"Chrome 136+ non-default user-data-dir requirement",
|
|
113
|
+
],
|
|
114
|
+
evidence: [
|
|
115
|
+
"DOM snapshot",
|
|
116
|
+
"screenshot",
|
|
117
|
+
"network",
|
|
118
|
+
"console",
|
|
119
|
+
"frame tree",
|
|
120
|
+
],
|
|
121
|
+
background_safe: true,
|
|
122
|
+
};
|
|
123
|
+
const repairRetry = {
|
|
124
|
+
retry_policy: [
|
|
125
|
+
{
|
|
126
|
+
surface: "daemon-command",
|
|
127
|
+
max_attempts: BROWSER_DAEMON_COMMAND_MAX_ATTEMPTS,
|
|
128
|
+
network_retry_delay_ms: BROWSER_DAEMON_NETWORK_RETRY_DELAY_MS,
|
|
129
|
+
extension_retry_delay_ms: BROWSER_DAEMON_EXTENSION_RETRY_DELAY_MS,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
surface: "remote-cdp",
|
|
133
|
+
max_attempts: BROWSER_REMOTE_CONNECT_MAX_ATTEMPTS,
|
|
134
|
+
retry_delay_ms: BROWSER_REMOTE_RETRY_DELAY_MS,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
surface: "extension-websocket",
|
|
138
|
+
max_attempts: MAX_EAGER_RECONNECT_ATTEMPTS,
|
|
139
|
+
min_delay_ms: WS_RECONNECT_BASE_DELAY,
|
|
140
|
+
max_delay_ms: WS_RECONNECT_MAX_DELAY,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
recovery_commands: [
|
|
144
|
+
"unicli browser profiles --json",
|
|
145
|
+
"unicli auth import <site> --domain <domain>",
|
|
146
|
+
"unicli browser cookies <domain> --profile-id <id>",
|
|
147
|
+
"unicli browser start",
|
|
148
|
+
"unicli browser bind",
|
|
149
|
+
"unicli browser evidence --render-aware",
|
|
150
|
+
"unicli repair <site> <command>",
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
const nextActions = buildNextActions(profiles, backgroundStatus, localCdp.value, remote !== null, remoteDebuggingPolicy);
|
|
154
|
+
const defaultPath = buildDefaultPath({
|
|
155
|
+
profiles,
|
|
156
|
+
backgroundOperation,
|
|
157
|
+
directConnect,
|
|
158
|
+
cookieReuse,
|
|
159
|
+
});
|
|
160
|
+
const checks = buildChecks({
|
|
161
|
+
profiles,
|
|
162
|
+
cookieReuse,
|
|
163
|
+
backgroundOperation,
|
|
164
|
+
directConnect,
|
|
165
|
+
defaultProfileDebugBlocks,
|
|
166
|
+
remoteDebuggingPolicy,
|
|
167
|
+
chrome136Guidance,
|
|
168
|
+
});
|
|
169
|
+
const selfRepair = buildSelfRepair({
|
|
170
|
+
profiles,
|
|
171
|
+
backgroundOperation,
|
|
172
|
+
directConnect,
|
|
173
|
+
defaultProfileDebugBlocks,
|
|
174
|
+
remoteDebuggingPolicy,
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
status: isAutomationReady ? "ready" : "needs-action",
|
|
178
|
+
cookie_reuse: cookieReuse,
|
|
179
|
+
background_operation: backgroundOperation,
|
|
180
|
+
browser_use: browserUse,
|
|
181
|
+
direct_connect: directConnect,
|
|
182
|
+
chrome_remote_debugging: chromeRemoteDebugging,
|
|
183
|
+
stability_reliability: stabilityReliability,
|
|
184
|
+
repair_retry: repairRetry,
|
|
185
|
+
default_path: defaultPath,
|
|
186
|
+
checks,
|
|
187
|
+
self_repair: selfRepair,
|
|
188
|
+
...(repairAttempt ? { repair_attempt: repairAttempt } : {}),
|
|
189
|
+
next_actions: nextActions,
|
|
190
|
+
completeness: buildCompleteness({
|
|
191
|
+
cookieReuse,
|
|
192
|
+
backgroundOperation,
|
|
193
|
+
browserUse,
|
|
194
|
+
directConnect,
|
|
195
|
+
stabilityReliability,
|
|
196
|
+
repairRetry,
|
|
197
|
+
}),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
export async function repairBrowserDoctor() {
|
|
201
|
+
const policy = detectChromeRemoteDebuggingPolicy();
|
|
202
|
+
if (policy.state === "disabled") {
|
|
203
|
+
return {
|
|
204
|
+
status: "failed",
|
|
205
|
+
actions: [
|
|
206
|
+
{
|
|
207
|
+
id: "enable-remote-debugging-policy",
|
|
208
|
+
status: "failed",
|
|
209
|
+
command: policy.next_step,
|
|
210
|
+
detail: "Chrome policy RemoteDebuggingAllowed=false blocks local CDP. Uni-CLI will not try unsupported feature-flag bypasses.",
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const port = getCDPPort();
|
|
216
|
+
if (await isCDPAvailable(port)) {
|
|
217
|
+
return {
|
|
218
|
+
status: "already-ready",
|
|
219
|
+
actions: [
|
|
220
|
+
{
|
|
221
|
+
id: "start-local-automation-cdp",
|
|
222
|
+
status: "skipped",
|
|
223
|
+
command: "unicli browser start",
|
|
224
|
+
detail: `Local CDP is already reachable on port ${String(port)}.`,
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
const actualPort = await launchChrome(port);
|
|
231
|
+
return {
|
|
232
|
+
status: "repaired",
|
|
233
|
+
actions: [
|
|
234
|
+
{
|
|
235
|
+
id: "start-local-automation-cdp",
|
|
236
|
+
status: "repaired",
|
|
237
|
+
command: "unicli browser start",
|
|
238
|
+
detail: `Started Uni-CLI automation Chrome CDP on port ${String(actualPort)}.`,
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
return {
|
|
245
|
+
status: "failed",
|
|
246
|
+
actions: [
|
|
247
|
+
{
|
|
248
|
+
id: "start-local-automation-cdp",
|
|
249
|
+
status: "failed",
|
|
250
|
+
command: "unicli browser start",
|
|
251
|
+
detail: errorMessage(err),
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function probeDaemon() {
|
|
258
|
+
try {
|
|
259
|
+
return { value: await fetchDaemonStatus({ timeout: 1000 }) };
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
return { value: null, error: errorMessage(err) };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async function probeDaemonPortConflict() {
|
|
266
|
+
try {
|
|
267
|
+
return { value: await fetchDaemonPortConflict({ timeout: 1000 }) };
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
return { value: null, error: errorMessage(err) };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function probeSessions() {
|
|
274
|
+
try {
|
|
275
|
+
return { value: await listSessions() };
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
return { value: [], error: errorMessage(err) };
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async function probeLocalCdp() {
|
|
282
|
+
try {
|
|
283
|
+
return { value: await isCDPAvailable(getCDPPort()) };
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
return { value: false, error: errorMessage(err) };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function buildCookieReuse(profiles) {
|
|
290
|
+
return {
|
|
291
|
+
status: profiles.length > 0 ? "ready" : "needs-profile",
|
|
292
|
+
profiles_count: profiles.length,
|
|
293
|
+
raw_cookie_values_returned: false,
|
|
294
|
+
raw_cookie_export_supported: true,
|
|
295
|
+
direct_browser_cookie_import_supported: true,
|
|
296
|
+
command: "unicli browser profiles --json",
|
|
297
|
+
direct_browser_cookie_import_command: "unicli auth import <site> --domain <domain> --browser <id> --profile <name>",
|
|
298
|
+
explicit_cookie_export_command: "unicli browser cookies <domain> --profile-id <id>",
|
|
299
|
+
strategy: [
|
|
300
|
+
"import domain cookies from the selected local browser DB when platform decryption is available",
|
|
301
|
+
"prefer a live DevToolsActivePort recorded by the selected profile",
|
|
302
|
+
"launch Chrome CDP with a Uni-CLI automation profile instead of the default user-data-dir",
|
|
303
|
+
"inject selected local profile cookies into the automation profile for browserSession=user commands",
|
|
304
|
+
"extract raw domain cookies through explicit user-requested CDP export",
|
|
305
|
+
],
|
|
306
|
+
reuse_paths: [
|
|
307
|
+
"direct browser DB cookie import",
|
|
308
|
+
"profile DevToolsActivePort",
|
|
309
|
+
"automation profile launch under ~/.unicli",
|
|
310
|
+
"selected profile cookie injection into CDP automation profile",
|
|
311
|
+
"explicit raw cookie export through browser cookies",
|
|
312
|
+
"profile discovery without returning raw cookie values",
|
|
313
|
+
],
|
|
314
|
+
profiles: profiles.slice(0, 20).map((profile) => ({
|
|
315
|
+
id: profile.id,
|
|
316
|
+
browser_name: profile.browser_name,
|
|
317
|
+
profile_dir: profile.profile_dir,
|
|
318
|
+
profile_name: profile.profile_name,
|
|
319
|
+
debug_port_state: profile.debug_port.state,
|
|
320
|
+
})),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function buildBackgroundStatus(daemon, conflict) {
|
|
324
|
+
if (daemon?.extensionConnected)
|
|
325
|
+
return "ready";
|
|
326
|
+
if (daemon)
|
|
327
|
+
return "needs-extension";
|
|
328
|
+
if (conflict)
|
|
329
|
+
return "blocked";
|
|
330
|
+
return "stopped";
|
|
331
|
+
}
|
|
332
|
+
function buildDaemonReport(daemon, conflict, error) {
|
|
333
|
+
if (!daemon) {
|
|
334
|
+
return {
|
|
335
|
+
status: conflict ? "blocked" : "stopped",
|
|
336
|
+
extension_connected: false,
|
|
337
|
+
...(conflict ? { conflict } : {}),
|
|
338
|
+
...(error ? { error } : {}),
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
status: "running",
|
|
343
|
+
port: daemon.port,
|
|
344
|
+
extension_connected: daemon.extensionConnected,
|
|
345
|
+
pending: daemon.pending,
|
|
346
|
+
memory_mb: daemon.memoryMB,
|
|
347
|
+
...(error ? { error } : {}),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function buildNextActions(profiles, backgroundStatus, localCdpReachable, remoteConfigured, remoteDebuggingPolicy) {
|
|
351
|
+
const commands = [];
|
|
352
|
+
if (remoteDebuggingPolicy.state === "disabled") {
|
|
353
|
+
commands.push(remoteDebuggingPolicy.next_step);
|
|
354
|
+
}
|
|
355
|
+
if (profiles.length === 0)
|
|
356
|
+
commands.push("unicli browser profiles --json");
|
|
357
|
+
else {
|
|
358
|
+
commands.push("unicli auth import <site> --domain <domain>");
|
|
359
|
+
commands.push("unicli browser cookies <domain> --profile-id <id>");
|
|
360
|
+
}
|
|
361
|
+
if (backgroundStatus !== "ready")
|
|
362
|
+
commands.push("unicli browser start");
|
|
363
|
+
if (backgroundStatus === "needs-extension") {
|
|
364
|
+
commands.push("unicli browser bind");
|
|
365
|
+
}
|
|
366
|
+
if (!localCdpReachable && !remoteConfigured) {
|
|
367
|
+
commands.push("unicli browser remote --status");
|
|
368
|
+
}
|
|
369
|
+
commands.push("unicli browser evidence --render-aware");
|
|
370
|
+
commands.push("unicli repair <site> <command>");
|
|
371
|
+
return [...new Set(commands)];
|
|
372
|
+
}
|
|
373
|
+
function buildDefaultPath(input) {
|
|
374
|
+
if (input.directConnect.local_cdp.reachable) {
|
|
375
|
+
return {
|
|
376
|
+
status: "ready",
|
|
377
|
+
mode: "local-cdp-automation-profile",
|
|
378
|
+
ready: true,
|
|
379
|
+
next_step: "Run the requested Uni-CLI command.",
|
|
380
|
+
commands: [
|
|
381
|
+
"unicli browser doctor --json",
|
|
382
|
+
"unicli <site> <command> -f json",
|
|
383
|
+
"unicli repair <site> <command>",
|
|
384
|
+
],
|
|
385
|
+
detail: "Default browser commands can use the Uni-CLI automation profile on local CDP. Authenticated sites reuse selected local profile cookies.",
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
if (input.directConnect.remote_cdp.configured) {
|
|
389
|
+
return {
|
|
390
|
+
status: "ready",
|
|
391
|
+
mode: "remote-cdp",
|
|
392
|
+
ready: true,
|
|
393
|
+
next_step: "Run the requested Uni-CLI command.",
|
|
394
|
+
commands: [
|
|
395
|
+
"unicli browser remote --status",
|
|
396
|
+
"unicli <site> <command> -f json",
|
|
397
|
+
],
|
|
398
|
+
detail: "Remote CDP is configured and can carry browser commands.",
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
if (input.backgroundOperation.status === "ready") {
|
|
402
|
+
return {
|
|
403
|
+
status: "ready",
|
|
404
|
+
mode: "daemon-extension",
|
|
405
|
+
ready: true,
|
|
406
|
+
next_step: "Run the requested browser command.",
|
|
407
|
+
commands: [
|
|
408
|
+
"unicli browser sessions",
|
|
409
|
+
"unicli browser open <url>",
|
|
410
|
+
"unicli <site> <command> -f json",
|
|
411
|
+
],
|
|
412
|
+
detail: "Daemon and extension are connected for background tab control.",
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
const commands = ["unicli browser doctor --repair"];
|
|
416
|
+
if (input.profiles.length === 0)
|
|
417
|
+
commands.push("unicli browser profiles --json");
|
|
418
|
+
if (input.cookieReuse.status !== "ready") {
|
|
419
|
+
commands.push("unicli auth import <site> --domain <domain>");
|
|
420
|
+
}
|
|
421
|
+
commands.push("unicli browser doctor --json");
|
|
422
|
+
return {
|
|
423
|
+
status: "needs-action",
|
|
424
|
+
mode: "none",
|
|
425
|
+
ready: false,
|
|
426
|
+
next_step: commands[0],
|
|
427
|
+
commands,
|
|
428
|
+
detail: "No default browser delivery path is currently reachable. Run the safe repair command first.",
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
function buildChecks(input) {
|
|
432
|
+
const localCdpReady = input.directConnect.local_cdp.reachable;
|
|
433
|
+
const hasDefaultBrowserPath = localCdpReady || input.backgroundOperation.status === "ready";
|
|
434
|
+
const remoteConfigured = input.directConnect.remote_cdp.configured;
|
|
435
|
+
return [
|
|
436
|
+
{
|
|
437
|
+
name: "Chrome 136+ remote debugging hardening",
|
|
438
|
+
ok: true,
|
|
439
|
+
status: "ready",
|
|
440
|
+
detail: "Official Chrome behavior: default user-data-dir cannot expose CDP; supported repair is a non-default automation profile, Chrome for Testing/Chromium, extension bridge, or remote CDP.",
|
|
441
|
+
next_step: "unicli browser doctor --repair",
|
|
442
|
+
commands: [
|
|
443
|
+
input.chrome136Guidance.safe_command,
|
|
444
|
+
"unicli auth import <site> --domain <domain>",
|
|
445
|
+
"unicli browser profiles --json",
|
|
446
|
+
],
|
|
447
|
+
evidence: [
|
|
448
|
+
`default_user_data_dir_cdp_supported=${String(input.chrome136Guidance.default_user_data_dir_cdp_supported)}`,
|
|
449
|
+
`policy_can_bypass_default_user_data_dir=${String(input.chrome136Guidance.policy_can_bypass_default_user_data_dir)}`,
|
|
450
|
+
...input.chrome136Guidance.official_docs,
|
|
451
|
+
],
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: "remote debugging policy",
|
|
455
|
+
ok: input.remoteDebuggingPolicy.state !== "disabled",
|
|
456
|
+
status: input.remoteDebuggingPolicy.state === "disabled"
|
|
457
|
+
? "needs-action"
|
|
458
|
+
: "ready",
|
|
459
|
+
detail: input.remoteDebuggingPolicy.detail,
|
|
460
|
+
next_step: input.remoteDebuggingPolicy.next_step,
|
|
461
|
+
commands: input.remoteDebuggingPolicy.commands,
|
|
462
|
+
evidence: [
|
|
463
|
+
`RemoteDebuggingAllowed=${input.remoteDebuggingPolicy.state}`,
|
|
464
|
+
`source=${input.remoteDebuggingPolicy.source}`,
|
|
465
|
+
...input.remoteDebuggingPolicy.official_docs,
|
|
466
|
+
],
|
|
467
|
+
auto_repairable: false,
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
name: "runtime state",
|
|
471
|
+
ok: true,
|
|
472
|
+
status: "ready",
|
|
473
|
+
detail: "Uni-CLI browser runtime is available.",
|
|
474
|
+
next_step: "No action.",
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: "local browser profiles",
|
|
478
|
+
ok: input.profiles.length > 0,
|
|
479
|
+
status: input.profiles.length > 0 ? "ready" : "needs-action",
|
|
480
|
+
detail: input.profiles.length > 0
|
|
481
|
+
? `${String(input.profiles.length)} local Chromium-family profile(s) discovered without returning raw cookie values.`
|
|
482
|
+
: "No local Chromium-family profiles were discovered.",
|
|
483
|
+
next_step: input.profiles.length > 0
|
|
484
|
+
? "unicli browser profiles --json"
|
|
485
|
+
: "Open a Chromium-family browser once, then run `unicli browser profiles --json`.",
|
|
486
|
+
commands: ["unicli browser profiles --json"],
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
name: "cookie reuse",
|
|
490
|
+
ok: input.cookieReuse.status === "ready",
|
|
491
|
+
status: input.cookieReuse.status === "ready" ? "ready" : "needs-action",
|
|
492
|
+
detail: input.cookieReuse.status === "ready"
|
|
493
|
+
? "Cookie reuse can import from local browser DBs and explicit cookie export."
|
|
494
|
+
: "Cookie reuse has no discovered local profile source.",
|
|
495
|
+
next_step: input.cookieReuse.status === "ready"
|
|
496
|
+
? "unicli auth import <site> --domain <domain>"
|
|
497
|
+
: "unicli browser profiles --json",
|
|
498
|
+
commands: [
|
|
499
|
+
"unicli auth import <site> --domain <domain>",
|
|
500
|
+
"unicli browser cookies <domain> --profile-id <id>",
|
|
501
|
+
],
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
name: "default profile CDP trap",
|
|
505
|
+
ok: input.defaultProfileDebugBlocks.length === 0,
|
|
506
|
+
status: input.defaultProfileDebugBlocks.length === 0 ? "ready" : "needs-action",
|
|
507
|
+
detail: input.defaultProfileDebugBlocks.length === 0
|
|
508
|
+
? "No Chrome process was detected trying to expose CDP from a default user-data-dir."
|
|
509
|
+
: `${String(input.defaultProfileDebugBlocks.length)} Chrome process(es) use --remote-debugging-port with a default user-data-dir. Chrome 136+ blocks that port; no supported policy or feature flag makes that default profile CDP path reliable.`,
|
|
510
|
+
next_step: input.defaultProfileDebugBlocks.length === 0
|
|
511
|
+
? "No action."
|
|
512
|
+
: "unicli browser doctor --repair",
|
|
513
|
+
commands: input.defaultProfileDebugBlocks.length === 0
|
|
514
|
+
? []
|
|
515
|
+
: ["unicli browser doctor --repair"],
|
|
516
|
+
evidence: input.defaultProfileDebugBlocks.map((block) => `pid=${String(block.pid)} ${block.browser_name} default user-data-dir`),
|
|
517
|
+
auto_repairable: input.defaultProfileDebugBlocks.length > 0,
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
name: "local automation CDP",
|
|
521
|
+
ok: localCdpReady,
|
|
522
|
+
status: localCdpReady ? "ready" : "needs-action",
|
|
523
|
+
detail: localCdpReady
|
|
524
|
+
? `Local CDP is reachable on port ${String(input.directConnect.local_cdp.port)}.`
|
|
525
|
+
: `Local CDP is not reachable on port ${String(input.directConnect.local_cdp.port)}.`,
|
|
526
|
+
next_step: localCdpReady
|
|
527
|
+
? "No action."
|
|
528
|
+
: "unicli browser doctor --repair",
|
|
529
|
+
commands: localCdpReady
|
|
530
|
+
? ["unicli browser status"]
|
|
531
|
+
: ["unicli browser doctor --repair", "unicli browser start"],
|
|
532
|
+
auto_repairable: !localCdpReady,
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
name: "daemon extension bridge",
|
|
536
|
+
ok: input.backgroundOperation.status === "ready",
|
|
537
|
+
status: input.backgroundOperation.status === "ready" ? "ready" : "needs-action",
|
|
538
|
+
detail: input.backgroundOperation.status === "ready"
|
|
539
|
+
? "Daemon and extension are connected for background tab control."
|
|
540
|
+
: `Daemon bridge is ${input.backgroundOperation.status}; local CDP can still serve command delivery if reachable.`,
|
|
541
|
+
next_step: input.backgroundOperation.status === "ready"
|
|
542
|
+
? "No action."
|
|
543
|
+
: "unicli daemon restart",
|
|
544
|
+
commands: ["unicli daemon restart", "unicli browser bind"],
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
name: "remote CDP",
|
|
548
|
+
ok: remoteConfigured || hasDefaultBrowserPath,
|
|
549
|
+
status: remoteConfigured || hasDefaultBrowserPath ? "ready" : "needs-action",
|
|
550
|
+
detail: remoteConfigured
|
|
551
|
+
? "Remote CDP endpoint is configured."
|
|
552
|
+
: hasDefaultBrowserPath
|
|
553
|
+
? "Remote CDP endpoint is optional; local browser delivery is already available."
|
|
554
|
+
: "Remote CDP endpoint is optional but useful when no local browser path is reachable.",
|
|
555
|
+
next_step: remoteConfigured
|
|
556
|
+
? "unicli browser remote --status"
|
|
557
|
+
: hasDefaultBrowserPath
|
|
558
|
+
? "No action unless cloud browser is required."
|
|
559
|
+
: "Set UNICLI_CDP_ENDPOINT or run `unicli browser doctor --repair` for local CDP.",
|
|
560
|
+
commands: ["unicli browser remote --status"],
|
|
561
|
+
},
|
|
562
|
+
];
|
|
563
|
+
}
|
|
564
|
+
function buildSelfRepair(input) {
|
|
565
|
+
const cdpReady = input.directConnect.local_cdp.reachable;
|
|
566
|
+
const actions = [];
|
|
567
|
+
if (input.remoteDebuggingPolicy.state === "disabled") {
|
|
568
|
+
actions.push({
|
|
569
|
+
id: "enable-remote-debugging-policy",
|
|
570
|
+
status: "manual",
|
|
571
|
+
command: input.remoteDebuggingPolicy.next_step,
|
|
572
|
+
safe: false,
|
|
573
|
+
detail: "RemoteDebuggingAllowed=false is an admin policy boundary. Uni-CLI reports it and refuses unsupported bypasses.",
|
|
574
|
+
expected_result: "chrome://policy no longer reports RemoteDebuggingAllowed=false; local CDP can then be repaired with `unicli browser doctor --repair`.",
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
actions.push({
|
|
578
|
+
id: "start-local-automation-cdp",
|
|
579
|
+
status: input.remoteDebuggingPolicy.state === "disabled"
|
|
580
|
+
? "blocked"
|
|
581
|
+
: cdpReady
|
|
582
|
+
? "not-needed"
|
|
583
|
+
: "available",
|
|
584
|
+
command: "unicli browser doctor --repair",
|
|
585
|
+
safe: true,
|
|
586
|
+
detail: input.remoteDebuggingPolicy.state === "disabled"
|
|
587
|
+
? "Blocked by Chrome policy RemoteDebuggingAllowed=false."
|
|
588
|
+
: cdpReady
|
|
589
|
+
? "Local automation CDP is already reachable."
|
|
590
|
+
: "Starts Chrome with Uni-CLI's automation profile and --no-startup-window.",
|
|
591
|
+
expected_result: `127.0.0.1:${String(input.directConnect.local_cdp.port)} listens from a ~/.unicli automation profile.`,
|
|
592
|
+
});
|
|
593
|
+
if (input.defaultProfileDebugBlocks.length > 0) {
|
|
594
|
+
actions.push({
|
|
595
|
+
id: "ignore-default-profile-debug-port",
|
|
596
|
+
status: "manual",
|
|
597
|
+
command: "Stop retrying the default-profile Chrome launch; run `unicli browser doctor --repair`.",
|
|
598
|
+
safe: true,
|
|
599
|
+
detail: "Chrome 136+ blocks remote debugging on default user-data-dir launches. Uni-CLI can repair the delivery path by starting an automation profile; it cannot make default-profile CDP supported.",
|
|
600
|
+
expected_result: "Agent stops treating default-profile --remote-debugging-port with no listener as a transient race.",
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
if (input.backgroundOperation.status !== "ready") {
|
|
604
|
+
actions.push({
|
|
605
|
+
id: "repair-daemon-extension-bridge",
|
|
606
|
+
status: "manual",
|
|
607
|
+
command: "unicli daemon restart && unicli browser bind",
|
|
608
|
+
safe: false,
|
|
609
|
+
detail: "Daemon/extension repair may need user-visible browser extension state, so doctor reports it but does not silently force it.",
|
|
610
|
+
expected_result: "browser doctor reports background_operation=ready when extension connects.",
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
if (input.profiles.length === 0) {
|
|
614
|
+
actions.push({
|
|
615
|
+
id: "create-local-profile-source",
|
|
616
|
+
status: "manual",
|
|
617
|
+
command: "Open Chrome/Arc/Brave/Edge once, sign in, then run `unicli browser profiles --json`.",
|
|
618
|
+
safe: false,
|
|
619
|
+
detail: "Profile creation and sign-in require user account intent.",
|
|
620
|
+
expected_result: "browser doctor reports cookie_reuse=ready.",
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
safe_command: "unicli browser doctor --repair",
|
|
625
|
+
actions,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
function buildCompleteness(input) {
|
|
629
|
+
const matrix = {
|
|
630
|
+
cookie_reuse: capabilityCheck({
|
|
631
|
+
status: input.cookieReuse.status === "ready" ? "ready" : "needs-action",
|
|
632
|
+
evidence: [
|
|
633
|
+
`profiles_count=${String(input.cookieReuse.profiles_count)}`,
|
|
634
|
+
"raw_cookie_values_returned=false",
|
|
635
|
+
"raw_cookie_export_supported=true",
|
|
636
|
+
"direct_browser_cookie_import_supported=true",
|
|
637
|
+
input.cookieReuse.direct_browser_cookie_import_command,
|
|
638
|
+
input.cookieReuse.explicit_cookie_export_command,
|
|
639
|
+
],
|
|
640
|
+
diagnostics: input.cookieReuse.status === "ready"
|
|
641
|
+
? []
|
|
642
|
+
: ["no local Chromium-family profiles discovered"],
|
|
643
|
+
repair_commands: [
|
|
644
|
+
input.cookieReuse.command,
|
|
645
|
+
input.cookieReuse.direct_browser_cookie_import_command,
|
|
646
|
+
input.cookieReuse.explicit_cookie_export_command,
|
|
647
|
+
],
|
|
648
|
+
}),
|
|
649
|
+
background_operation: capabilityCheck({
|
|
650
|
+
status: input.backgroundOperation.status === "ready" ? "ready" : "needs-action",
|
|
651
|
+
evidence: [
|
|
652
|
+
`daemon=${input.backgroundOperation.daemon.status}`,
|
|
653
|
+
`extension_connected=${String(input.backgroundOperation.daemon.extension_connected)}`,
|
|
654
|
+
`sessions_count=${String(input.backgroundOperation.sessions_count)}`,
|
|
655
|
+
"windowFocused=false by default",
|
|
656
|
+
"doctor sessions probe is read-only",
|
|
657
|
+
],
|
|
658
|
+
diagnostics: [
|
|
659
|
+
input.backgroundOperation.daemon.conflict,
|
|
660
|
+
input.backgroundOperation.daemon.error,
|
|
661
|
+
input.backgroundOperation.session_error,
|
|
662
|
+
input.backgroundOperation.status === "needs-extension"
|
|
663
|
+
? "browser daemon is running but extension is not connected"
|
|
664
|
+
: undefined,
|
|
665
|
+
input.backgroundOperation.status === "stopped"
|
|
666
|
+
? "browser daemon is not running"
|
|
667
|
+
: undefined,
|
|
668
|
+
],
|
|
669
|
+
repair_commands: input.backgroundOperation.status === "ready"
|
|
670
|
+
? ["unicli browser bind"]
|
|
671
|
+
: ["unicli browser start", "unicli browser bind"],
|
|
672
|
+
}),
|
|
673
|
+
browser_use: capabilityCheck({
|
|
674
|
+
status: "ready",
|
|
675
|
+
evidence: input.browserUse.modes,
|
|
676
|
+
repair_commands: ["unicli browser doctor --json"],
|
|
677
|
+
}),
|
|
678
|
+
page_layering: capabilityCheck({
|
|
679
|
+
status: "ready",
|
|
680
|
+
evidence: input.browserUse.layers.map((layer) => layer.name),
|
|
681
|
+
repair_commands: ["unicli browser evidence --render-aware"],
|
|
682
|
+
}),
|
|
683
|
+
direct_connect: capabilityCheck({
|
|
684
|
+
status: input.directConnect.local_cdp.reachable ||
|
|
685
|
+
input.directConnect.remote_cdp.configured
|
|
686
|
+
? "ready"
|
|
687
|
+
: "needs-action",
|
|
688
|
+
evidence: [
|
|
689
|
+
input.directConnect.local_cdp.reachable
|
|
690
|
+
? `local CDP reachable on port ${String(input.directConnect.local_cdp.port)}`
|
|
691
|
+
: `local CDP unreachable on port ${String(input.directConnect.local_cdp.port)}`,
|
|
692
|
+
input.directConnect.remote_cdp.configured
|
|
693
|
+
? "remote CDP configured"
|
|
694
|
+
: "remote CDP not configured",
|
|
695
|
+
],
|
|
696
|
+
diagnostics: [input.directConnect.local_cdp.error],
|
|
697
|
+
repair_commands: [
|
|
698
|
+
"unicli browser start",
|
|
699
|
+
"unicli browser remote --status",
|
|
700
|
+
],
|
|
701
|
+
}),
|
|
702
|
+
stability: capabilityCheck({
|
|
703
|
+
status: "ready",
|
|
704
|
+
evidence: input.stabilityReliability.guards,
|
|
705
|
+
repair_commands: ["unicli browser evidence --render-aware"],
|
|
706
|
+
}),
|
|
707
|
+
reliability: capabilityCheck({
|
|
708
|
+
status: input.backgroundOperation.status === "ready" ||
|
|
709
|
+
input.directConnect.local_cdp.reachable ||
|
|
710
|
+
input.directConnect.remote_cdp.configured
|
|
711
|
+
? "ready"
|
|
712
|
+
: "needs-action",
|
|
713
|
+
evidence: [
|
|
714
|
+
`background=${input.backgroundOperation.status}`,
|
|
715
|
+
`local_cdp_reachable=${String(input.directConnect.local_cdp.reachable)}`,
|
|
716
|
+
`remote_cdp_configured=${String(input.directConnect.remote_cdp.configured)}`,
|
|
717
|
+
],
|
|
718
|
+
diagnostics: [
|
|
719
|
+
input.backgroundOperation.daemon.conflict,
|
|
720
|
+
input.backgroundOperation.daemon.error,
|
|
721
|
+
input.backgroundOperation.status === "stopped"
|
|
722
|
+
? "no browser control path is currently reachable"
|
|
723
|
+
: undefined,
|
|
724
|
+
],
|
|
725
|
+
repair_commands: [
|
|
726
|
+
"unicli browser start",
|
|
727
|
+
"unicli browser bind",
|
|
728
|
+
"unicli browser remote --status",
|
|
729
|
+
],
|
|
730
|
+
}),
|
|
731
|
+
repair: capabilityCheck({
|
|
732
|
+
status: "ready",
|
|
733
|
+
evidence: input.repairRetry.recovery_commands,
|
|
734
|
+
repair_commands: input.repairRetry.recovery_commands,
|
|
735
|
+
}),
|
|
736
|
+
retry: capabilityCheck({
|
|
737
|
+
status: "ready",
|
|
738
|
+
evidence: input.repairRetry.retry_policy.map((policy) => `${policy.surface} max_attempts=${String(policy.max_attempts)}`),
|
|
739
|
+
repair_commands: ["unicli browser doctor --json"],
|
|
740
|
+
}),
|
|
741
|
+
};
|
|
742
|
+
const missing = REQUIRED_BROWSER_CAPABILITIES.filter((capability) => matrix[capability].status !== "ready");
|
|
743
|
+
return {
|
|
744
|
+
complete: missing.length === 0,
|
|
745
|
+
required_capabilities: [...REQUIRED_BROWSER_CAPABILITIES],
|
|
746
|
+
missing,
|
|
747
|
+
matrix,
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
function capabilityCheck(input) {
|
|
751
|
+
const diagnostics = (input.diagnostics ?? []).filter((item) => typeof item === "string" && item.length > 0);
|
|
752
|
+
return {
|
|
753
|
+
status: input.status,
|
|
754
|
+
evidence: input.evidence,
|
|
755
|
+
repair_commands: input.repair_commands,
|
|
756
|
+
...(diagnostics.length > 0 ? { diagnostics } : {}),
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
function redactEndpoint(endpoint) {
|
|
760
|
+
try {
|
|
761
|
+
const parsed = new URL(endpoint);
|
|
762
|
+
return `${parsed.protocol}//${parsed.host}${redactEndpointPath(parsed.pathname)}${parsed.search ? "?..." : ""}`;
|
|
763
|
+
}
|
|
764
|
+
catch {
|
|
765
|
+
return endpoint
|
|
766
|
+
.replace(/\/\/[^/@]+@/, "//")
|
|
767
|
+
.replace(/(\/devtools\/(?:browser|page))\/[^?#]+/i, "$1/...")
|
|
768
|
+
.replace(/\?.*$/, "?...")
|
|
769
|
+
.replace(/#.*/, "");
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
function redactEndpointPath(pathname) {
|
|
773
|
+
if (pathname === "" || pathname === "/")
|
|
774
|
+
return "";
|
|
775
|
+
const match = pathname.match(/^\/devtools\/(browser|page)(?:\/.*)?$/i);
|
|
776
|
+
if (!match)
|
|
777
|
+
return "/...";
|
|
778
|
+
const base = `/devtools/${match[1].toLowerCase()}`;
|
|
779
|
+
return pathname === base ? base : `${base}/...`;
|
|
780
|
+
}
|
|
781
|
+
function errorMessage(err) {
|
|
782
|
+
return err instanceof Error ? err.message : String(err);
|
|
783
|
+
}
|
|
784
|
+
//# sourceMappingURL=doctor.js.map
|