@zenalexa/unicli 0.225.1 → 0.225.3

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.
Files changed (271) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +3 -3
  3. package/README.zh-CN.md +3 -3
  4. package/dist/adapters/acl-anthology/papers.d.ts +16 -9
  5. package/dist/adapters/acl-anthology/papers.d.ts.map +1 -1
  6. package/dist/adapters/acl-anthology/papers.js +322 -58
  7. package/dist/adapters/acl-anthology/papers.js.map +1 -1
  8. package/dist/adapters/arxiv/papers.d.ts +22 -4
  9. package/dist/adapters/arxiv/papers.d.ts.map +1 -1
  10. package/dist/adapters/arxiv/papers.js +202 -4
  11. package/dist/adapters/arxiv/papers.js.map +1 -1
  12. package/dist/adapters/baidu-scholar/search.d.ts +15 -1
  13. package/dist/adapters/baidu-scholar/search.d.ts.map +1 -1
  14. package/dist/adapters/baidu-scholar/search.js +72 -8
  15. package/dist/adapters/baidu-scholar/search.js.map +1 -1
  16. package/dist/adapters/biorxiv/preprints.d.ts +9 -0
  17. package/dist/adapters/biorxiv/preprints.d.ts.map +1 -0
  18. package/dist/adapters/biorxiv/preprints.js +78 -0
  19. package/dist/adapters/biorxiv/preprints.js.map +1 -0
  20. package/dist/adapters/cnki/search.d.ts +82 -0
  21. package/dist/adapters/cnki/search.d.ts.map +1 -0
  22. package/dist/adapters/cnki/search.js +236 -0
  23. package/dist/adapters/cnki/search.js.map +1 -0
  24. package/dist/adapters/cvf/papers.d.ts +12 -7
  25. package/dist/adapters/cvf/papers.d.ts.map +1 -1
  26. package/dist/adapters/cvf/papers.js +210 -27
  27. package/dist/adapters/cvf/papers.js.map +1 -1
  28. package/dist/adapters/dblp/publications.d.ts +12 -5
  29. package/dist/adapters/dblp/publications.d.ts.map +1 -1
  30. package/dist/adapters/dblp/publications.js +31 -8
  31. package/dist/adapters/dblp/publications.js.map +1 -1
  32. package/dist/adapters/google-scholar/search.d.ts +22 -1
  33. package/dist/adapters/google-scholar/search.d.ts.map +1 -1
  34. package/dist/adapters/google-scholar/search.js +129 -14
  35. package/dist/adapters/google-scholar/search.js.map +1 -1
  36. package/dist/adapters/hf/paper.d.ts +12 -3
  37. package/dist/adapters/hf/paper.d.ts.map +1 -1
  38. package/dist/adapters/hf/paper.js +65 -5
  39. package/dist/adapters/hf/paper.js.map +1 -1
  40. package/dist/adapters/medrxiv/preprints.d.ts +9 -0
  41. package/dist/adapters/medrxiv/preprints.d.ts.map +1 -0
  42. package/dist/adapters/medrxiv/preprints.js +78 -0
  43. package/dist/adapters/medrxiv/preprints.js.map +1 -0
  44. package/dist/adapters/neurips/proceedings.d.ts +8 -7
  45. package/dist/adapters/neurips/proceedings.d.ts.map +1 -1
  46. package/dist/adapters/neurips/proceedings.js +209 -21
  47. package/dist/adapters/neurips/proceedings.js.map +1 -1
  48. package/dist/adapters/openalex/works.d.ts +21 -5
  49. package/dist/adapters/openalex/works.d.ts.map +1 -1
  50. package/dist/adapters/openalex/works.js +108 -8
  51. package/dist/adapters/openalex/works.js.map +1 -1
  52. package/dist/adapters/openreview/papers.d.ts +10 -4
  53. package/dist/adapters/openreview/papers.d.ts.map +1 -1
  54. package/dist/adapters/openreview/papers.js +351 -24
  55. package/dist/adapters/openreview/papers.js.map +1 -1
  56. package/dist/adapters/pmlr/proceedings.d.ts +6 -6
  57. package/dist/adapters/pmlr/proceedings.d.ts.map +1 -1
  58. package/dist/adapters/pmlr/proceedings.js +92 -12
  59. package/dist/adapters/pmlr/proceedings.js.map +1 -1
  60. package/dist/adapters/pubmed/articles.d.ts +8 -4
  61. package/dist/adapters/pubmed/articles.d.ts.map +1 -1
  62. package/dist/adapters/pubmed/articles.js +272 -39
  63. package/dist/adapters/pubmed/articles.js.map +1 -1
  64. package/dist/adapters/rxiv/preprints.d.ts +75 -0
  65. package/dist/adapters/rxiv/preprints.d.ts.map +1 -0
  66. package/dist/adapters/rxiv/preprints.js +651 -0
  67. package/dist/adapters/rxiv/preprints.js.map +1 -0
  68. package/dist/adapters/scholar-artifacts/pdf-read.d.ts +49 -0
  69. package/dist/adapters/scholar-artifacts/pdf-read.d.ts.map +1 -0
  70. package/dist/adapters/scholar-artifacts/pdf-read.js +204 -0
  71. package/dist/adapters/scholar-artifacts/pdf-read.js.map +1 -0
  72. package/dist/adapters/scholar-artifacts/pdf.d.ts +16 -0
  73. package/dist/adapters/scholar-artifacts/pdf.d.ts.map +1 -0
  74. package/dist/adapters/scholar-artifacts/pdf.js +122 -0
  75. package/dist/adapters/scholar-artifacts/pdf.js.map +1 -0
  76. package/dist/adapters/semantic-scholar/papers.d.ts +6 -6
  77. package/dist/adapters/semantic-scholar/papers.d.ts.map +1 -1
  78. package/dist/adapters/semantic-scholar/papers.js +80 -6
  79. package/dist/adapters/semantic-scholar/papers.js.map +1 -1
  80. package/dist/adapters/unpaywall/works.d.ts +7 -7
  81. package/dist/adapters/unpaywall/works.d.ts.map +1 -1
  82. package/dist/adapters/unpaywall/works.js +104 -12
  83. package/dist/adapters/unpaywall/works.js.map +1 -1
  84. package/dist/adapters/wanfang/search.d.ts +14 -0
  85. package/dist/adapters/wanfang/search.d.ts.map +1 -1
  86. package/dist/adapters/wanfang/search.js +56 -7
  87. package/dist/adapters/wanfang/search.js.map +1 -1
  88. package/dist/browser/page.d.ts +2 -0
  89. package/dist/browser/page.d.ts.map +1 -1
  90. package/dist/browser/page.js +12 -0
  91. package/dist/browser/page.js.map +1 -1
  92. package/dist/browser/protocol.d.ts +6 -1
  93. package/dist/browser/protocol.d.ts.map +1 -1
  94. package/dist/browser/protocol.js.map +1 -1
  95. package/dist/commands/browser/actions.d.ts.map +1 -1
  96. package/dist/commands/browser/actions.js +487 -8
  97. package/dist/commands/browser/actions.js.map +1 -1
  98. package/dist/commands/compute.js +12 -1
  99. package/dist/commands/compute.js.map +1 -1
  100. package/dist/commands/schema.d.ts.map +1 -1
  101. package/dist/commands/schema.js +22 -0
  102. package/dist/commands/schema.js.map +1 -1
  103. package/dist/commands/scholar.d.ts +77 -5
  104. package/dist/commands/scholar.d.ts.map +1 -1
  105. package/dist/commands/scholar.js +2945 -83
  106. package/dist/commands/scholar.js.map +1 -1
  107. package/dist/commands/search.d.ts.map +1 -1
  108. package/dist/commands/search.js +14 -3
  109. package/dist/commands/search.js.map +1 -1
  110. package/dist/compute/contracts.d.ts +55 -0
  111. package/dist/compute/contracts.d.ts.map +1 -0
  112. package/dist/compute/contracts.js +487 -0
  113. package/dist/compute/contracts.js.map +1 -0
  114. package/dist/core/command-contract.d.ts.map +1 -1
  115. package/dist/core/command-contract.js +5 -0
  116. package/dist/core/command-contract.js.map +1 -1
  117. package/dist/core/schema-v2.d.ts +1 -0
  118. package/dist/core/schema-v2.d.ts.map +1 -1
  119. package/dist/core/schema-v2.js +1 -0
  120. package/dist/core/schema-v2.js.map +1 -1
  121. package/dist/discovery/aliases.d.ts +8 -1
  122. package/dist/discovery/aliases.d.ts.map +1 -1
  123. package/dist/discovery/aliases.js +333 -20
  124. package/dist/discovery/aliases.js.map +1 -1
  125. package/dist/discovery/core-catalog.d.ts +2 -0
  126. package/dist/discovery/core-catalog.d.ts.map +1 -1
  127. package/dist/discovery/core-catalog.js +525 -66
  128. package/dist/discovery/core-catalog.js.map +1 -1
  129. package/dist/discovery/intents.d.ts +1 -0
  130. package/dist/discovery/intents.d.ts.map +1 -1
  131. package/dist/discovery/intents.js +299 -2
  132. package/dist/discovery/intents.js.map +1 -1
  133. package/dist/discovery/loader.d.ts.map +1 -1
  134. package/dist/discovery/loader.js +3 -0
  135. package/dist/discovery/loader.js.map +1 -1
  136. package/dist/discovery/macos-dynamic.d.ts +1 -0
  137. package/dist/discovery/macos-dynamic.d.ts.map +1 -1
  138. package/dist/discovery/macos-dynamic.js +20 -1
  139. package/dist/discovery/macos-dynamic.js.map +1 -1
  140. package/dist/discovery/search.d.ts.map +1 -1
  141. package/dist/discovery/search.js +12 -5
  142. package/dist/discovery/search.js.map +1 -1
  143. package/dist/engine/browser/evidence.d.ts +34 -1
  144. package/dist/engine/browser/evidence.d.ts.map +1 -1
  145. package/dist/engine/browser/evidence.js +141 -6
  146. package/dist/engine/browser/evidence.js.map +1 -1
  147. package/dist/engine/capability-policy.d.ts.map +1 -1
  148. package/dist/engine/capability-policy.js +30 -4
  149. package/dist/engine/capability-policy.js.map +1 -1
  150. package/dist/engine/kernel/stages.d.ts.map +1 -1
  151. package/dist/engine/kernel/stages.js +3 -0
  152. package/dist/engine/kernel/stages.js.map +1 -1
  153. package/dist/engine/operation-policy.d.ts +4 -1
  154. package/dist/engine/operation-policy.d.ts.map +1 -1
  155. package/dist/engine/operation-policy.js +23 -0
  156. package/dist/engine/operation-policy.js.map +1 -1
  157. package/dist/engine/steps/fetch-text.d.ts.map +1 -1
  158. package/dist/engine/steps/fetch-text.js +2 -2
  159. package/dist/engine/steps/fetch-text.js.map +1 -1
  160. package/dist/engine/steps/fetch.d.ts +1 -0
  161. package/dist/engine/steps/fetch.d.ts.map +1 -1
  162. package/dist/engine/steps/fetch.js +24 -4
  163. package/dist/engine/steps/fetch.js.map +1 -1
  164. package/dist/fast-path/handlers/discovery.d.ts +5 -5
  165. package/dist/fast-path/handlers/discovery.d.ts.map +1 -1
  166. package/dist/fast-path/handlers/discovery.js +61 -8
  167. package/dist/fast-path/handlers/discovery.js.map +1 -1
  168. package/dist/fast-path/manifest.d.ts +3 -0
  169. package/dist/fast-path/manifest.d.ts.map +1 -1
  170. package/dist/fast-path/manifest.js.map +1 -1
  171. package/dist/fast-path/policy.d.ts.map +1 -1
  172. package/dist/fast-path/policy.js +3 -0
  173. package/dist/fast-path/policy.js.map +1 -1
  174. package/dist/fast-path/render.d.ts +2 -0
  175. package/dist/fast-path/render.d.ts.map +1 -1
  176. package/dist/fast-path/render.js +9 -0
  177. package/dist/fast-path/render.js.map +1 -1
  178. package/dist/manifest-compact.txt +2 -2
  179. package/dist/manifest.json +6977 -1002
  180. package/dist/mcp/handler.d.ts +2 -16
  181. package/dist/mcp/handler.d.ts.map +1 -1
  182. package/dist/mcp/handler.js.map +1 -1
  183. package/dist/mcp/http-transport.d.ts +7 -1
  184. package/dist/mcp/http-transport.d.ts.map +1 -1
  185. package/dist/mcp/http-transport.js +20 -1
  186. package/dist/mcp/http-transport.js.map +1 -1
  187. package/dist/mcp/jsonrpc.d.ts +27 -0
  188. package/dist/mcp/jsonrpc.d.ts.map +1 -0
  189. package/dist/mcp/jsonrpc.js +12 -0
  190. package/dist/mcp/jsonrpc.js.map +1 -0
  191. package/dist/mcp/origin-guard.d.ts +26 -0
  192. package/dist/mcp/origin-guard.d.ts.map +1 -0
  193. package/dist/mcp/origin-guard.js +42 -0
  194. package/dist/mcp/origin-guard.js.map +1 -0
  195. package/dist/mcp/profiles/computer-use.d.ts.map +1 -1
  196. package/dist/mcp/profiles/computer-use.js +30 -270
  197. package/dist/mcp/profiles/computer-use.js.map +1 -1
  198. package/dist/mcp/streamable-http/session.d.ts +4 -22
  199. package/dist/mcp/streamable-http/session.d.ts.map +1 -1
  200. package/dist/mcp/streamable-http/session.js +4 -24
  201. package/dist/mcp/streamable-http/session.js.map +1 -1
  202. package/dist/mcp/tools.d.ts.map +1 -1
  203. package/dist/mcp/tools.js +74 -54
  204. package/dist/mcp/tools.js.map +1 -1
  205. package/dist/output/envelope.d.ts +2 -0
  206. package/dist/output/envelope.d.ts.map +1 -1
  207. package/dist/output/envelope.js.map +1 -1
  208. package/dist/output/error-map.d.ts +14 -0
  209. package/dist/output/error-map.d.ts.map +1 -1
  210. package/dist/output/error-map.js +20 -0
  211. package/dist/output/error-map.js.map +1 -1
  212. package/dist/registry.d.ts +2 -0
  213. package/dist/registry.d.ts.map +1 -1
  214. package/dist/registry.js +1 -0
  215. package/dist/registry.js.map +1 -1
  216. package/dist/transport/cascade.d.ts.map +1 -1
  217. package/dist/transport/cascade.js +77 -5
  218. package/dist/transport/cascade.js.map +1 -1
  219. package/dist/transport/refs.d.ts +33 -1
  220. package/dist/transport/refs.d.ts.map +1 -1
  221. package/dist/transport/refs.js +40 -1
  222. package/dist/transport/refs.js.map +1 -1
  223. package/dist/types/scholarly.d.ts +19 -4
  224. package/dist/types/scholarly.d.ts.map +1 -1
  225. package/dist/types/scholarly.js +4 -4
  226. package/dist/types.d.ts +8 -0
  227. package/dist/types.d.ts.map +1 -1
  228. package/dist/types.js.map +1 -1
  229. package/package.json +1 -1
  230. package/server.json +2 -2
  231. package/skills/unicli/SKILL.md +1 -1
  232. package/skills/unicli-claude-code/SKILL.md +1 -1
  233. package/skills/unicli-hermes/SKILL.md +1 -1
  234. package/src/adapters/acl-anthology/papers.test.ts +111 -0
  235. package/src/adapters/acl-anthology/papers.ts +379 -71
  236. package/src/adapters/arxiv/papers.test.ts +46 -0
  237. package/src/adapters/arxiv/papers.ts +251 -4
  238. package/src/adapters/baidu-scholar/search.ts +74 -11
  239. package/src/adapters/biorxiv/preprints.ts +112 -0
  240. package/src/adapters/cnki/search.ts +357 -0
  241. package/src/adapters/cvf/papers.ts +260 -27
  242. package/src/adapters/dblp/publications.test.ts +9 -0
  243. package/src/adapters/dblp/publications.ts +31 -8
  244. package/src/adapters/defuddle/read.yaml +30 -0
  245. package/src/adapters/google-scholar/search.ts +165 -17
  246. package/src/adapters/hf/paper.test.ts +23 -0
  247. package/src/adapters/hf/paper.ts +89 -5
  248. package/src/adapters/hf/top.yaml +34 -2
  249. package/src/adapters/huggingface-papers/daily.yaml +37 -3
  250. package/src/adapters/huggingface-papers/search.yaml +43 -9
  251. package/src/adapters/jina/read.yaml +30 -0
  252. package/src/adapters/markdown-new/read.yaml +50 -0
  253. package/src/adapters/medrxiv/preprints.ts +112 -0
  254. package/src/adapters/neurips/proceedings.ts +266 -22
  255. package/src/adapters/ollama-cloud/fetch.yaml +39 -0
  256. package/src/adapters/ollama-cloud/search.yaml +43 -0
  257. package/src/adapters/openalex/works.test.ts +15 -4
  258. package/src/adapters/openalex/works.ts +136 -8
  259. package/src/adapters/openreview/papers.test.ts +31 -0
  260. package/src/adapters/openreview/papers.ts +407 -29
  261. package/src/adapters/pmlr/proceedings.ts +102 -12
  262. package/src/adapters/pubmed/articles.test.ts +88 -1
  263. package/src/adapters/pubmed/articles.ts +343 -44
  264. package/src/adapters/rxiv/preprints.test.ts +233 -0
  265. package/src/adapters/rxiv/preprints.ts +849 -0
  266. package/src/adapters/scholar-artifacts/pdf-read.ts +277 -0
  267. package/src/adapters/scholar-artifacts/pdf.ts +133 -0
  268. package/src/adapters/semantic-scholar/papers.ts +98 -6
  269. package/src/adapters/unpaywall/works.ts +141 -12
  270. package/src/adapters/wanfang/search.ts +57 -7
  271. package/src/adapters/cnki/search.yaml +0 -49
@@ -6,20 +6,21 @@
6
6
  * @breaks Action, lease, daemon, and evidence failures propagate as command errors or evidence envelopes. No fallback.
7
7
  */
8
8
  import { appendFileSync, mkdirSync } from "node:fs";
9
- import { dirname as pathDirname, join } from "node:path";
9
+ import { basename as pathBasename, dirname as pathDirname, join, } from "node:path";
10
10
  import chalk from "chalk";
11
11
  import { userHome } from "../../engine/user-home.js";
12
12
  import { FINGERPRINT_PERSIST_JS, verifyRef, } from "../../browser/snapshot-identity.js";
13
13
  import { rankCandidates } from "../../browser/observe.js";
14
14
  import { buildExtractJs, buildFindJs, ensureNetworkCapture, getOperatorPage, operatorAction, readFrames, resolveAllowedUploadPath, resolveWorkspace, validateRef, withBrowserOperatorEnv, } from "./runtime.js";
15
- import { sendCommand } from "../../browser/daemon-client.js";
15
+ import { listSessions, sendCommand } from "../../browser/daemon-client.js";
16
16
  import { registerBrowserAuthoringSubcommands } from "./authoring.js";
17
- import { captureBrowserEvidencePacket, captureRenderAwareBrowserEvidence, installBrowserEvidenceHooks, } from "../../engine/browser/evidence.js";
17
+ import { captureBrowserEvidencePacket, captureRenderAwareBrowserEvidence, installBrowserEvidenceHooks, readBrowserConsole, } from "../../engine/browser/evidence.js";
18
18
  import { assertBrowserSessionLeaseUrlGuard, createBrowserSessionLease, } from "../../engine/browser/session-lease.js";
19
19
  import { assertBrowserSessionLeaseTargetCurrent, enrichBrowserSessionLease, } from "../../engine/browser/session-runtime.js";
20
20
  import { isBrowserActionEvidenceEnabled, withBrowserActionEvidence, } from "../../engine/browser/action-evidence.js";
21
21
  import { withBrowserSessionLeaseLock } from "../../engine/browser/session-lock.js";
22
22
  export { withBrowserOperatorEnv };
23
+ const BROWSER_DOM_QUERY_RESULT_MAX_CHARS = 20_000;
23
24
  export function applyBrowserOperatorRootOptions(command) {
24
25
  command
25
26
  .option("--workspace <name>", "Reuse a named automation workspace instead of the default shared session")
@@ -91,6 +92,371 @@ function browserActionWatchdogMode(value) {
91
92
  return "off";
92
93
  }
93
94
  }
95
+ async function readBrowserConnectionTargetEvidence(page, finalUrl) {
96
+ const requests = await page.networkRequests();
97
+ return selectBrowserConnectionTargetEvidence(finalUrl, requests);
98
+ }
99
+ function selectBrowserConnectionTargetEvidence(finalUrl, requests) {
100
+ for (let index = requests.length - 1; index >= 0; index -= 1) {
101
+ const request = requests[index];
102
+ if (!request?.remoteIPAddress)
103
+ continue;
104
+ if (!isSameBrowserDocumentUrl(finalUrl, request.url))
105
+ continue;
106
+ return {
107
+ source: "cdp_network_response",
108
+ url: request.url,
109
+ remote_ip_address: request.remoteIPAddress,
110
+ ...(request.remotePort !== undefined
111
+ ? { remote_port: request.remotePort }
112
+ : {}),
113
+ status: request.status,
114
+ resource_type: request.type,
115
+ };
116
+ }
117
+ return undefined;
118
+ }
119
+ function isSameBrowserDocumentUrl(left, right) {
120
+ if (left === right)
121
+ return true;
122
+ const normalizedLeft = normalizeBrowserUrlForDocumentMatch(left);
123
+ const normalizedRight = normalizeBrowserUrlForDocumentMatch(right);
124
+ return normalizedLeft !== undefined && normalizedLeft === normalizedRight;
125
+ }
126
+ function normalizeBrowserUrlForDocumentMatch(rawUrl) {
127
+ try {
128
+ const url = new URL(rawUrl);
129
+ url.hash = "";
130
+ return url.href;
131
+ }
132
+ catch {
133
+ return undefined;
134
+ }
135
+ }
136
+ const BROWSER_CDP_READ_ONLY_METHODS = new Set([
137
+ "Page.getFrameTree",
138
+ "Target.getTargetInfo",
139
+ ]);
140
+ const BROWSER_CDP_RESULT_MAX_CHARS = 20_000;
141
+ async function closeAllBrowserSessions() {
142
+ const sessions = await listSessions();
143
+ const reports = [];
144
+ for (const session of sessions) {
145
+ await sendCommand("close-window", { workspace: session.workspace });
146
+ reports.push({
147
+ workspace: session.workspace,
148
+ action: closeActionForSession(session),
149
+ status: "completed",
150
+ });
151
+ }
152
+ return {
153
+ ok: true,
154
+ scope: "all_managed_sessions",
155
+ session_count: sessions.length,
156
+ closed_count: reports.filter((report) => report.action === "closed_window")
157
+ .length,
158
+ released_count: reports.filter((report) => report.action === "released_binding").length,
159
+ failed_count: 0,
160
+ sessions: reports,
161
+ };
162
+ }
163
+ function closeActionForSession(session) {
164
+ return session.owned === false ? "released_binding" : "closed_window";
165
+ }
166
+ function normalizeBrowserDialogProviderResult(result, workspace) {
167
+ if (!isRecord(result) ||
168
+ result.evidence_type !== "browser-dialog-supervision" ||
169
+ result.supervision !== "active") {
170
+ throw new Error("Browser dialog supervisor returned an invalid payload.");
171
+ }
172
+ const respondedDialog = readDialogEntries([result.responded_dialog])[0];
173
+ return {
174
+ ok: true,
175
+ evidence_type: "browser-dialog-supervision",
176
+ workspace,
177
+ captured_at: readString(result.captured_at) ?? new Date().toISOString(),
178
+ supervision: "active",
179
+ pending_count: readNonNegativeInteger(result.pending_count),
180
+ recent_count: readNonNegativeInteger(result.recent_count),
181
+ pending_dialogs: readDialogEntries(result.pending_dialogs),
182
+ recent_dialogs: readDialogRecords(result.recent_dialogs),
183
+ ...(respondedDialog === undefined
184
+ ? {}
185
+ : { responded_dialog: respondedDialog }),
186
+ ...(readString(result.url) === undefined
187
+ ? {}
188
+ : { url: readString(result.url) }),
189
+ ...(readString(result.title) === undefined
190
+ ? {}
191
+ : { title: readString(result.title) }),
192
+ };
193
+ }
194
+ function normalizeBrowserDownloadsProviderResult(result, workspace, limit) {
195
+ if (!isRecord(result) || result.evidence_type !== "browser-downloads") {
196
+ throw new Error("Browser downloads provider returned an invalid payload.");
197
+ }
198
+ const downloads = readDownloadEntries(result.downloads);
199
+ return {
200
+ ok: true,
201
+ evidence_type: "browser-downloads",
202
+ workspace,
203
+ captured_at: readString(result.captured_at) ?? new Date().toISOString(),
204
+ limit,
205
+ count: downloads.length,
206
+ downloads,
207
+ };
208
+ }
209
+ function parseBrowserDialogAction(action) {
210
+ if (action === "accept" || action === "dismiss")
211
+ return action;
212
+ throw new Error("Browser dialog action must be accept or dismiss.");
213
+ }
214
+ function parseBrowserDomQueryKind(rawKind) {
215
+ if (rawKind === undefined || rawKind === "text")
216
+ return "text";
217
+ if (rawKind === "value" || rawKind === "attributes")
218
+ return rawKind;
219
+ throw new Error("Browser query kind must be text, value, or attributes.");
220
+ }
221
+ function buildBrowserDomQueryJs(ref, kind) {
222
+ const refJson = JSON.stringify(ref);
223
+ const kindJson = JSON.stringify(kind);
224
+ return `(() => {
225
+ const __unicli_dom_query = true;
226
+ const ref = ${refJson};
227
+ const kind = ${kindJson};
228
+ const el = document.querySelector('[data-unicli-ref="' + ref + '"]');
229
+ if (!el) throw new Error('Ref not found: ' + ref);
230
+ const readText = () => {
231
+ if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
232
+ return String(el.value || '');
233
+ }
234
+ const text = 'innerText' in el ? el.innerText : el.textContent;
235
+ return String(text || '').trim();
236
+ };
237
+ if (kind === 'text') {
238
+ const value = readText();
239
+ return { value, original_length: value.length, truncated: false };
240
+ }
241
+ if (kind === 'value') {
242
+ const value = 'value' in el ? String(el.value || '') : String(el.getAttribute('value') || '');
243
+ return { value, original_length: value.length, truncated: false };
244
+ }
245
+ const allowed = new Set(['href', 'src', 'alt', 'title', 'aria-label', 'role', 'name', 'placeholder', 'type']);
246
+ const attrs = {};
247
+ for (const attr of Array.from(el.attributes || [])) {
248
+ const name = attr.name.toLowerCase();
249
+ if (name === 'data-unicli-ref') continue;
250
+ if (!allowed.has(name) && !name.startsWith('aria-')) continue;
251
+ attrs[name] = String(attr.value || '').slice(0, 500);
252
+ }
253
+ const value = JSON.stringify(attrs);
254
+ return { value, original_length: value.length, truncated: false };
255
+ })()`;
256
+ }
257
+ function normalizeBrowserDomQueryResult({ kind, rawResult, ref, url, }) {
258
+ if (!isRecord(rawResult)) {
259
+ throw new Error("Browser query provider returned an invalid payload.");
260
+ }
261
+ const value = readStringAllowEmpty(rawResult.value);
262
+ if (value === undefined) {
263
+ throw new Error("Browser query provider returned no result value.");
264
+ }
265
+ const originalLength = readNonNegativeInteger(rawResult.original_length) || value.length;
266
+ const truncatedValue = value.length <= BROWSER_DOM_QUERY_RESULT_MAX_CHARS
267
+ ? value
268
+ : value.slice(0, BROWSER_DOM_QUERY_RESULT_MAX_CHARS);
269
+ return {
270
+ ok: true,
271
+ evidence_type: "browser-dom-query",
272
+ authority: "ref_read_only",
273
+ kind,
274
+ ref,
275
+ result: truncatedValue,
276
+ result_chars: Math.max(originalLength, value.length),
277
+ result_truncated: rawResult.truncated === true ||
278
+ value.length > BROWSER_DOM_QUERY_RESULT_MAX_CHARS,
279
+ url,
280
+ };
281
+ }
282
+ function readDialogEntries(value) {
283
+ if (!Array.isArray(value))
284
+ return [];
285
+ return value.flatMap((entry) => {
286
+ if (!isRecord(entry))
287
+ return [];
288
+ const id = readString(entry.id);
289
+ const type = readString(entry.type);
290
+ const message = readString(entry.message);
291
+ const openedAt = readString(entry.opened_at);
292
+ if (id === undefined ||
293
+ type === undefined ||
294
+ message === undefined ||
295
+ openedAt === undefined) {
296
+ return [];
297
+ }
298
+ const url = readString(entry.url);
299
+ const defaultPrompt = readString(entry.default_prompt);
300
+ return [
301
+ {
302
+ id: id.slice(0, 120),
303
+ type: type.slice(0, 40),
304
+ message: message.slice(0, 1_000),
305
+ opened_at: openedAt,
306
+ ...(url === undefined ? {} : { url: url.slice(0, 2_000) }),
307
+ ...(defaultPrompt === undefined
308
+ ? {}
309
+ : { default_prompt: defaultPrompt.slice(0, 1_000) }),
310
+ },
311
+ ];
312
+ });
313
+ }
314
+ function readDialogRecords(value) {
315
+ if (!Array.isArray(value))
316
+ return [];
317
+ return value.flatMap((record) => {
318
+ if (!isRecord(record))
319
+ return [];
320
+ const entry = readDialogEntries([record])[0];
321
+ const closedAt = readString(record.closed_at);
322
+ const closedBy = readString(record.closed_by);
323
+ if (entry === undefined ||
324
+ closedAt === undefined ||
325
+ (closedBy !== "agent" &&
326
+ closedBy !== "remote" &&
327
+ closedBy !== "tab_closed")) {
328
+ return [];
329
+ }
330
+ return [
331
+ {
332
+ ...entry,
333
+ closed_at: closedAt,
334
+ closed_by: closedBy,
335
+ ...(record.action === "accept" || record.action === "dismiss"
336
+ ? { action: record.action }
337
+ : {}),
338
+ },
339
+ ];
340
+ });
341
+ }
342
+ function readDownloadEntries(value) {
343
+ if (!Array.isArray(value))
344
+ return [];
345
+ return value.slice(0, 50).flatMap((entry) => {
346
+ if (!isRecord(entry))
347
+ return [];
348
+ const id = readNonNegativeInteger(entry.id);
349
+ const state = readString(entry.state);
350
+ const danger = readString(entry.danger);
351
+ const filenameBasename = readString(entry.filename_basename);
352
+ if (state === undefined ||
353
+ danger === undefined ||
354
+ filenameBasename === undefined) {
355
+ return [];
356
+ }
357
+ return [
358
+ {
359
+ id,
360
+ state: state.slice(0, 40),
361
+ danger: danger.slice(0, 80),
362
+ exists: entry.exists === true,
363
+ paused: entry.paused === true,
364
+ incognito: entry.incognito === true,
365
+ bytes_received: readNonNegativeInteger(entry.bytes_received),
366
+ total_bytes: readNonNegativeInteger(entry.total_bytes),
367
+ file_size: readNonNegativeInteger(entry.file_size),
368
+ filename_basename: pathBasename(filenameBasename).slice(0, 240),
369
+ ...(readString(entry.mime) === undefined
370
+ ? {}
371
+ : { mime: readString(entry.mime).slice(0, 160) }),
372
+ ...(readString(entry.url) === undefined
373
+ ? {}
374
+ : { url: readString(entry.url).slice(0, 2_000) }),
375
+ ...(readString(entry.final_url) === undefined
376
+ ? {}
377
+ : { final_url: readString(entry.final_url).slice(0, 2_000) }),
378
+ ...(readString(entry.started_at) === undefined
379
+ ? {}
380
+ : { started_at: readString(entry.started_at) }),
381
+ ...(readString(entry.ended_at) === undefined
382
+ ? {}
383
+ : { ended_at: readString(entry.ended_at) }),
384
+ ...(readString(entry.error) === undefined
385
+ ? {}
386
+ : { error: readString(entry.error).slice(0, 160) }),
387
+ },
388
+ ];
389
+ });
390
+ }
391
+ function parseDownloadLimit(rawLimit) {
392
+ const parsed = Number.parseInt(rawLimit ?? "20", 10);
393
+ if (!Number.isFinite(parsed))
394
+ return 20;
395
+ return Math.max(1, Math.min(50, Math.trunc(parsed)));
396
+ }
397
+ function readNonNegativeInteger(value) {
398
+ return typeof value === "number" && Number.isFinite(value) && value >= 0
399
+ ? Math.trunc(value)
400
+ : 0;
401
+ }
402
+ function readString(value) {
403
+ return typeof value === "string" && value.length > 0 ? value : undefined;
404
+ }
405
+ function readStringAllowEmpty(value) {
406
+ return typeof value === "string" ? value : undefined;
407
+ }
408
+ function isRecord(value) {
409
+ return typeof value === "object" && value !== null && !Array.isArray(value);
410
+ }
411
+ function parseBrowserCdpParams(rawParams) {
412
+ if (rawParams === undefined)
413
+ return {};
414
+ let parsed;
415
+ try {
416
+ parsed = JSON.parse(rawParams);
417
+ }
418
+ catch {
419
+ throw new Error("CDP params must be a JSON object.");
420
+ }
421
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
422
+ throw new Error("CDP params must be a JSON object.");
423
+ }
424
+ return parsed;
425
+ }
426
+ function assertBrowserCdpReadOnlyMethod(method) {
427
+ if (BROWSER_CDP_READ_ONLY_METHODS.has(method))
428
+ return;
429
+ throw new Error(`CDP method ${method} is not in the read-only allowlist. Supported methods: ${[
430
+ ...BROWSER_CDP_READ_ONLY_METHODS,
431
+ ].join(", ")}`);
432
+ }
433
+ function createBrowserCdpReadOnlyResult(input) {
434
+ const resultJson = JSON.stringify(input.result ?? null);
435
+ if (resultJson.length <= BROWSER_CDP_RESULT_MAX_CHARS) {
436
+ return {
437
+ ok: true,
438
+ evidence_type: "browser-cdp-readonly",
439
+ workspace: input.workspace,
440
+ method: input.method,
441
+ authority: "read_only_allowlist",
442
+ params_keys: Object.keys(input.params).sort(),
443
+ result_json_chars: resultJson.length,
444
+ result_truncated: false,
445
+ result: input.result,
446
+ };
447
+ }
448
+ return {
449
+ ok: true,
450
+ evidence_type: "browser-cdp-readonly",
451
+ workspace: input.workspace,
452
+ method: input.method,
453
+ authority: "read_only_allowlist",
454
+ params_keys: Object.keys(input.params).sort(),
455
+ result_json_chars: resultJson.length,
456
+ result_truncated: true,
457
+ result_preview: resultJson.slice(0, BROWSER_CDP_RESULT_MAX_CHARS),
458
+ };
459
+ }
94
460
  export function registerBrowserOperatorSubcommands(root, program, namespace) {
95
461
  root
96
462
  .command("open <url>")
@@ -99,12 +465,20 @@ export function registerBrowserOperatorSubcommands(root, program, namespace) {
99
465
  const page = await getOperatorPage(root, namespace);
100
466
  await ensureNetworkCapture(page);
101
467
  await page.goto(url, { settleMs: 2000 });
102
- const title = await page.title();
468
+ const finalUrl = await page.url();
469
+ const [title, connectionTargetEvidence] = await Promise.all([
470
+ page.title(),
471
+ readBrowserConnectionTargetEvidence(page, finalUrl),
472
+ ]);
103
473
  return {
104
474
  ok: true,
105
- url,
475
+ requested_url: url,
476
+ url: finalUrl,
106
477
  title,
107
478
  workspace: resolveWorkspace(root, namespace),
479
+ ...(connectionTargetEvidence
480
+ ? { connection_target_evidence: connectionTargetEvidence }
481
+ : {}),
108
482
  };
109
483
  }));
110
484
  root
@@ -136,6 +510,27 @@ export function registerBrowserOperatorSubcommands(root, program, namespace) {
136
510
  return { url, snapshot };
137
511
  });
138
512
  }));
513
+ root
514
+ .command("query <ref>")
515
+ .description("Read bounded DOM data from a verified snapshot ref")
516
+ .option("--kind <kind>", "Query kind: text, value, or attributes", "text")
517
+ .action((ref, opts) => operatorAction(program, root, namespace, "query", async () => {
518
+ validateRef(ref);
519
+ const kind = parseBrowserDomQueryKind(opts.kind);
520
+ const page = await getOperatorPage(root, namespace);
521
+ const selector = `[data-unicli-ref="${ref}"]`;
522
+ return await withRecordedBrowserAction(program, root, namespace, "query", page, { ref, kind }, async () => {
523
+ await verifyRef(page, selector);
524
+ const url = await page.url();
525
+ const rawResult = await page.evaluate(buildBrowserDomQueryJs(ref, kind));
526
+ return normalizeBrowserDomQueryResult({
527
+ kind,
528
+ rawResult,
529
+ ref,
530
+ url,
531
+ });
532
+ });
533
+ }));
139
534
  root
140
535
  .command("screenshot [path]")
141
536
  .description("Capture page screenshot")
@@ -192,6 +587,62 @@ export function registerBrowserOperatorSubcommands(root, program, namespace) {
192
587
  screenshotDir,
193
588
  });
194
589
  }));
590
+ root
591
+ .command("console")
592
+ .description("Read bounded browser console messages and page errors")
593
+ .option("--clear", "Clear captured console entries after reading")
594
+ .option("--max <n>", "Maximum console entries to return", "50")
595
+ .option("--text-max <n>", "Maximum text characters per entry", "1000")
596
+ .action((opts) => operatorAction(program, root, namespace, "console", async () => {
597
+ const page = await getOperatorPage(root, namespace);
598
+ return await readBrowserConsole(page, {
599
+ clear: opts.clear === true,
600
+ maxEntries: parseInt(opts.max, 10),
601
+ maxTextChars: parseInt(opts.textMax, 10),
602
+ });
603
+ }));
604
+ root
605
+ .command("cdp <method> [params]")
606
+ .description("Run a read-only allowlisted Chrome DevTools Protocol command")
607
+ .action((method, paramsJson) => operatorAction(program, root, namespace, "cdp", async () => {
608
+ assertBrowserCdpReadOnlyMethod(method);
609
+ const params = parseBrowserCdpParams(paramsJson);
610
+ const page = await getOperatorPage(root, namespace);
611
+ const result = await page.sendCDP(method, params);
612
+ return createBrowserCdpReadOnlyResult({
613
+ workspace: resolveWorkspace(root, namespace),
614
+ method,
615
+ params,
616
+ result,
617
+ });
618
+ }));
619
+ root
620
+ .command("dialogs")
621
+ .description("Start and read provider-owned browser dialog supervision")
622
+ .option("--clear-recent", "Clear recent dialog records after reading")
623
+ .action((opts) => operatorAction(program, root, namespace, "dialogs", async () => {
624
+ const workspace = resolveWorkspace(root, namespace);
625
+ const result = await sendCommand("dialog-read", {
626
+ workspace,
627
+ clearRecent: opts.clearRecent === true,
628
+ });
629
+ return normalizeBrowserDialogProviderResult(result, workspace);
630
+ }));
631
+ root
632
+ .command("dialog <action> [dialogId]")
633
+ .description("Respond to a pending browser JavaScript dialog")
634
+ .option("--prompt <text>", "Prompt text for prompt() dialogs")
635
+ .action((actionRaw, dialogId, opts) => operatorAction(program, root, namespace, "dialog", async () => {
636
+ const action = parseBrowserDialogAction(actionRaw);
637
+ const workspace = resolveWorkspace(root, namespace);
638
+ const result = await sendCommand("dialog-respond", {
639
+ workspace,
640
+ dialogAction: action,
641
+ ...(dialogId === undefined ? {} : { dialogId }),
642
+ ...(opts.prompt === undefined ? {} : { promptText: opts.prompt }),
643
+ });
644
+ return normalizeBrowserDialogProviderResult(result, workspace);
645
+ }));
195
646
  root
196
647
  .command("click <ref>")
197
648
  .description("Click element by ref number from state")
@@ -268,7 +719,14 @@ export function registerBrowserOperatorSubcommands(root, program, namespace) {
268
719
  .description("Get current URL")
269
720
  .action(() => operatorAction(program, root, namespace, "get url", async () => {
270
721
  const page = await getOperatorPage(root, namespace);
271
- return await page.url();
722
+ const url = await page.url();
723
+ const connectionTargetEvidence = await readBrowserConnectionTargetEvidence(page, url);
724
+ return {
725
+ value: url,
726
+ ...(connectionTargetEvidence
727
+ ? { connection_target_evidence: connectionTargetEvidence }
728
+ : {}),
729
+ };
272
730
  }));
273
731
  get
274
732
  .command("text <ref>")
@@ -456,6 +914,19 @@ export function registerBrowserOperatorSubcommands(root, program, namespace) {
456
914
  const page = await getOperatorPage(root, namespace);
457
915
  return await readFrames(page);
458
916
  }));
917
+ root
918
+ .command("downloads")
919
+ .description("List recent browser downloads without exposing local file paths")
920
+ .option("--limit <n>", "Maximum download records to return", "20")
921
+ .action((opts) => operatorAction(program, root, namespace, "downloads", async () => {
922
+ const workspace = resolveWorkspace(root, namespace);
923
+ const limit = parseDownloadLimit(opts.limit);
924
+ const result = await sendCommand("downloads-read", {
925
+ workspace,
926
+ downloadLimit: limit,
927
+ });
928
+ return normalizeBrowserDownloadsProviderResult(result, workspace, limit);
929
+ }));
459
930
  root
460
931
  .command("extract")
461
932
  .description("Extract long-form page text with chunked pagination")
@@ -516,10 +987,18 @@ export function registerBrowserOperatorSubcommands(root, program, namespace) {
516
987
  root
517
988
  .command("close")
518
989
  .description("Close the automation browser window")
519
- .action(() => operatorAction(program, root, namespace, "close", async () => {
990
+ .option("--all", "Close or release all managed browser sessions")
991
+ .action((opts) => operatorAction(program, root, namespace, "close", async () => {
992
+ if (opts.all === true) {
993
+ return await closeAllBrowserSessions();
994
+ }
520
995
  const page = await getOperatorPage(root, namespace);
521
996
  await page.closeWindow();
522
- return { ok: true, workspace: resolveWorkspace(root, namespace) };
997
+ return {
998
+ ok: true,
999
+ scope: "current_managed_session",
1000
+ workspace: resolveWorkspace(root, namespace),
1001
+ };
523
1002
  }));
524
1003
  }
525
1004
  //# sourceMappingURL=actions.js.map